Refactor parts of actions to NCPCompat.

This is not finished, log action is missing still.
This commit is contained in:
asofold 2013-01-30 14:05:39 +01:00
parent 4e85e9d211
commit fd9bb76202
19 changed files with 457 additions and 333 deletions

View File

@ -0,0 +1,136 @@
package fr.neatmonster.nocheatplus.actions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import fr.neatmonster.nocheatplus.actions.AbstractActionList.ActionListFactory;
import fr.neatmonster.nocheatplus.actions.types.CommandAction;
import fr.neatmonster.nocheatplus.actions.types.DummyAction;
import fr.neatmonster.nocheatplus.logging.LogUtil;
public abstract class AbstractActionFactory <D extends ActionData, L extends AbstractActionList<D, L>>{
// TODO: static ?
protected static final Map<String, Object> lib = new HashMap<String, Object>();
protected final ActionListFactory<D, L> listFactory;
/**
* Instantiates a new action factory.
*
* @param library
* the library
*/
public AbstractActionFactory(final Map<String, Object> library, final ActionListFactory<D, L> listFactory) {
this.listFactory = listFactory;
lib.putAll(library);
}
public abstract Action<D, L> createAction(String actionDefinition);
/**
* Creates a new Action object.
*
* @param definition
* the definition
* @param permission
* the permission
* @return the action list
*/
public L createActionList(final String definition, final String permission) {
final L list = listFactory.getNewActionList(permission);
// Do check for null, to allow removing default actions, for better robustness.
if (definition == null) return list;
boolean first = true;
for (String s : definition.split("vl>")) {
s = s.trim();
if (s.length() == 0) {
first = false;
continue;
}
try {
Integer vl;
String def;
if (first) {
first = false;
vl = 0;
def = s;
} else {
final String[] listEntry = s.split("\\s+", 2);
vl = Integer.parseInt(listEntry[0]);
def = listEntry[1];
}
list.setActions(vl, createActions(def.split("\\s+")));
} catch (final Exception e) {
LogUtil.logWarning("[NoCheatPlus] Couldn't parse action definition 'vl:" + s + "'.");
}
}
return list;
}
/**
* Creates a new Action object.
*
* @param definitions
* the definitions
* @return the action[]
*/
@SuppressWarnings("unchecked")
public Action<D, L>[] createActions(final String... definitions) {
final List<Action<D, L>> actions = new ArrayList<Action<D, L>>();
for (final String def : definitions) {
if (def.length() == 0)
continue;
try {
actions.add(createAction(def));
} catch (final IllegalArgumentException e) {
LogUtil.logWarning("[NoCheatPlus] Failed to create action: " + e.getMessage());
actions.add(new DummyAction<D, L>(def));
}
}
return (Action<D, L>[]) actions.toArray(new Action<?, ?>[actions.size()]);
}
/**
* Parses the cmd action.
*
* @param definition
* the definition
* @return the action
*/
protected <PH extends ParameterHolder, LPH extends AbstractActionList<PH, LPH>> Action<PH, LPH> parseCmdAction(final String definition) {
final String[] parts = definition.split(":");
final String name = parts[0];
final Object command = lib.get(parts[0]);
int delay = 0;
int repeat = 0;
if (command == null)
throw new IllegalArgumentException("NoCheatPlus doesn't know command '" + name
+ "'. Have you forgotten to define it?");
if (parts.length > 1)
try {
delay = Integer.parseInt(parts[1]);
repeat = Integer.parseInt(parts[2]);
} catch (final Exception e) {
LogUtil.logWarning("[NoCheatPlus] Couldn't parse details of command '" + definition
+ "', will use default values instead.");
delay = 0;
repeat = 0;
}
return new CommandAction<PH, LPH>(name, delay, repeat, command.toString());
}
}

View File

@ -0,0 +1,133 @@
package fr.neatmonster.nocheatplus.actions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import fr.neatmonster.nocheatplus.config.ConfigFileWithActions;
public abstract class AbstractActionList<D extends ActionData, L extends AbstractActionList<D, L>>{
public static interface ActionListFactory<D extends ActionData, L extends AbstractActionList<D, L>>{
public L getNewActionList(String permissionSilent);
}
/** Something to return if nothing is set. */
protected static final Action<?, ?>[] emptyArray = new Action[0];
/** This is a very bad design decision, but it's also really convenient to define this here. */
public final String permissionSilent;
/** The actions of this AbstractActionList, "bundled" by threshold (violation level). */
private final Map<Integer, Action<D, L>[]> actions = new HashMap<Integer, Action<D, L>[]>();
/** The thresholds of this list. **/
protected final List<Integer> thresholds = new ArrayList<Integer>();
protected final ActionListFactory<D, L> listFactory;
/**
* Instantiates a new action list.
*
* @param permissionSilent
* the permission
*/
public AbstractActionList(final String permissionSilent, final ActionListFactory<D, L> listFactory) {
this.listFactory = listFactory;
this.permissionSilent = permissionSilent + ".silent";
}
/**
* Get a list of actions that match the violation level. The only method that has to be called by a check.
*
* @param violationLevel
* the violation level that should be matched
* @return the array of actions whose threshold was closest to the violation level but not bigger
*/
@SuppressWarnings("unchecked")
public Action<D, L>[] getActions(final double violationLevel) {
Integer result = null;
for (final Integer threshold : thresholds)
if (threshold <= violationLevel)
result = threshold;
if (result != null)
return actions.get(result);
else
return (Action<D, L>[]) emptyArray;
}
/**
* Get a sorted list of the thresholds/violation levels that were used in this list.
*
* @return the sorted list of thresholds.
*/
public List<Integer> getThresholds() {
return thresholds;
}
/**
* Add an entry to this AbstractActionList. The list will be sorted by thresholds automatically after the insertion.
*
* @param threshold
* the minimum violation level a player needs to have to be suspected to the given actions
* @param actions
* the actions that will be used if the player reached the accompanying threshold/violation level
*/
public void setActions(final Integer threshold, final Action<D, L>[] actions) {
if (!thresholds.contains(threshold)) {
thresholds.add(threshold);
Collections.sort(thresholds);
}
this.actions.put(threshold, actions);
}
/**
* Return a copy of this list, but optimize it, i.e. remove entries that are
* never called, possibly do other optimizations which are possible given
* the specific configuration.
*
* @param config Configuration to adapt to.
* @return Optimized AbstractActionList, individual Actions can be identical instances, altered Action instances must always be new instances, arrays are always new arrays.
*/
public L getOptimizedCopy(final ConfigFileWithActions<D, L> config) {
final L newList = listFactory.getNewActionList(permissionSilent);
for (final Entry<Integer, Action<D, L>[]> entry : actions.entrySet()){
final Integer t = entry.getKey();
final Action<D, L>[] a = getOptimizedCopy(config, t, entry.getValue());
if (a != null && a.length > 0){
newList.setActions(t, a);
}
}
return newList;
}
/**
* Get an optimized copy of the Actions array, given the config in use.
* @param config
* @param threshold
* @param actions
* @return Copy with optimized entries, null or empty arrays are possible. Contained Actions might be identical to the given ones, just changed actions must be new instances to preserve consistency, Action instances are not to be altered.
*/
public Action<D, L>[] getOptimizedCopy(final ConfigFileWithActions<D, L> config, final Integer threshold, final Action<D, L>[] actions)
{
if (actions == null || actions.length == 0) return null;
final ArrayList<Action<D, L>> optimized = new ArrayList<Action<D, L>>();
for (final Action<D, L> action : actions){
final Action<D, L> optAction = action.getOptimizedCopy(config, threshold);
if (optAction != null) optimized.add(optAction);
}
if (optimized.isEmpty()) return null;
@SuppressWarnings("unchecked")
final Action<D, L>[] optActions = (Action<D, L>[]) new Action<?, ?>[optimized.size()];
optimized.toArray(optActions);
return optActions;
}
}

View File

@ -1,7 +1,6 @@
package fr.neatmonster.nocheatplus.actions;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.config.ConfigFile;
import fr.neatmonster.nocheatplus.config.ConfigFileWithActions;
/*
* MMP"""""""MM dP oo
@ -16,7 +15,7 @@ import fr.neatmonster.nocheatplus.config.ConfigFile;
* An action gets executed as the result of a failed check. If it 'really' gets executed depends on how many executions
* have occurred within the last 60 seconds and how much time was between this and the previous execution.
*/
public abstract class Action {
public abstract class Action <D extends ActionData, L extends AbstractActionList<D, L>>{
/**
* The name of the action, to identify it, e.g. in the configuration file.
*/
@ -57,7 +56,7 @@ public abstract class Action {
* the violation data
* @return true, if successful
*/
public abstract boolean execute(final ViolationData violationData);
public abstract boolean execute(final D violationData);
/**
* Check if parameters are needed at all for faster processing.
@ -84,7 +83,7 @@ public abstract class Action {
* @param threshold
* @return Can return this (unchanged), null (not to be executed ever) or a new instance (changed, optimized).
*/
public Action getOptimizedCopy(final ConfigFile config, final Integer threshold) {
public Action<D, L> getOptimizedCopy(final ConfigFileWithActions<D, L> config, final Integer threshold) {
return this;
}
}

View File

@ -0,0 +1,10 @@
package fr.neatmonster.nocheatplus.actions;
/**
* This is data relevant for an action.
* @author mc_dev
*
*/
public interface ActionData {
}

View File

@ -0,0 +1,29 @@
package fr.neatmonster.nocheatplus.actions;
/**
* Namse subject to change.
* @author mc_dev
*
*/
public interface ParameterHolder extends ActionData{
/**
*
* @param parameterName
* @return Will always return some string, if not set: "<?PARAMETERNAME>".
*/
public String getParameter(final ParameterName parameterName);
/**
* This might not set any parameters, if needsParameters() returns false.
* @param parameterName
* @param value
*/
public void setParameter(final ParameterName parameterName, String value);
/**
* Check if any of the actions needs parameters.
* @return If true, actions are likely to contian command or logging actions.
*/
boolean needsParameters();
}

View File

@ -2,9 +2,10 @@ package fr.neatmonster.nocheatplus.actions.types;
import java.util.ArrayList;
import fr.neatmonster.nocheatplus.actions.AbstractActionList;
import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.actions.ParameterHolder;
import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.ViolationData;
/*
* MMP"""""""MM dP oo M""MMM""MMM""M oo dP dP
@ -26,7 +27,7 @@ import fr.neatmonster.nocheatplus.checks.ViolationData;
/**
* Action with parameters is used for the messages (chat, console, log) or the commands.
*/
public abstract class ActionWithParameters extends Action {
public abstract class ActionWithParameters<D extends ParameterHolder, L extends AbstractActionList<D, L>> extends Action<D, L> {
/** The parts of the message. */
protected final ArrayList<Object> messageParts;
@ -64,7 +65,7 @@ public abstract class ActionWithParameters extends Action {
* the violation data
* @return the message
*/
protected String getMessage(final ViolationData violationData) {
protected String getMessage(final D violationData) { // interface
// Should be big enough most of the time.
final StringBuilder log = new StringBuilder(150);

View File

@ -1,7 +1,8 @@
package fr.neatmonster.nocheatplus.actions.types;
import fr.neatmonster.nocheatplus.actions.AbstractActionList;
import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.actions.ActionData;
/*
* MM'""""'YMM dP MMP"""""""MM dP oo
@ -16,7 +17,7 @@ import fr.neatmonster.nocheatplus.checks.ViolationData;
* Do something check-specific. Usually that is to cancel the event, undo something the player did, or do something the
* server should've done.
*/
public class CancelAction extends Action {
public class CancelAction<D extends ActionData, L extends AbstractActionList<D, L>> extends Action<D, L> {
/**
* Instantiates a new cancel action.
@ -29,7 +30,7 @@ public class CancelAction extends Action {
* @see fr.neatmonster.nocheatplus.actions.Action#execute(fr.neatmonster.nocheatplus.checks.ViolationData)
*/
@Override
public boolean execute(final ViolationData data) {
public boolean execute(final D data) {
return true;
}

View File

@ -3,7 +3,8 @@ package fr.neatmonster.nocheatplus.actions.types;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandException;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.actions.AbstractActionList;
import fr.neatmonster.nocheatplus.actions.ParameterHolder;
import fr.neatmonster.nocheatplus.logging.LogUtil;
/*
@ -26,7 +27,7 @@ import fr.neatmonster.nocheatplus.logging.LogUtil;
/**
* Execute a command by imitating an administrator typing the command directly into the console.
*/
public class CommandAction extends ActionWithParameters {
public class CommandAction<D extends ParameterHolder, L extends AbstractActionList<D, L>> extends ActionWithParameters<D, L> {
/**
* Instantiates a new command action.
@ -49,7 +50,7 @@ public class CommandAction extends ActionWithParameters {
* @see fr.neatmonster.nocheatplus.actions.Action#execute(fr.neatmonster.nocheatplus.checks.ViolationData)
*/
@Override
public boolean execute(final ViolationData violationData) {
public boolean execute(final D violationData) {
final String command = super.getMessage(violationData);
try {
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command);

View File

@ -1,8 +1,9 @@
package fr.neatmonster.nocheatplus.actions.types;
import fr.neatmonster.nocheatplus.actions.AbstractActionList;
import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.config.ConfigFile;
import fr.neatmonster.nocheatplus.actions.ActionData;
import fr.neatmonster.nocheatplus.config.ConfigFileWithActions;
/*
* M""""""'YMM MMP"""""""MM dP oo
@ -18,7 +19,7 @@ import fr.neatmonster.nocheatplus.config.ConfigFile;
* If an action can't be parsed correctly, at least keep it stored in this form to not lose it when loading/storing the
* configuration file.
*/
public class DummyAction extends Action {
public class DummyAction<D extends ActionData, L extends AbstractActionList<D, L>> extends Action<D, L> {
/** The original string used for this action definition. */
protected final String definition;
@ -37,7 +38,7 @@ public class DummyAction extends Action {
* @see fr.neatmonster.nocheatplus.actions.Action#execute(fr.neatmonster.nocheatplus.checks.ViolationData)
*/
@Override
public boolean execute(final ViolationData violationData) {
public boolean execute(final D violationData) {
return false;
}
@ -50,7 +51,7 @@ public class DummyAction extends Action {
}
@Override
public Action getOptimizedCopy(final ConfigFile config, final Integer threshold)
public Action<D, L> getOptimizedCopy(final ConfigFileWithActions<D, L> config, final Integer threshold)
{
// Never execute this.
return null;

View File

@ -0,0 +1,73 @@
package fr.neatmonster.nocheatplus.config;
import fr.neatmonster.nocheatplus.actions.AbstractActionFactory;
import fr.neatmonster.nocheatplus.actions.AbstractActionList;
import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.actions.ActionData;
public abstract class ConfigFileWithActions<D extends ActionData, L extends AbstractActionList<D, L>> extends RawConfigFile {
/**
* Do this after reading new data.<br>
* TODO: Specify what this actually does.
*/
public abstract void regenerateActionLists();
/** The factory. */
protected AbstractActionFactory<D, L> factory = null;
/**
* A convenience method to get an optimized action list from the configuration.
*
* @param path
* the path
* @param permission
* the permission
* @return the action list
*/
public L getOptimizedActionList(final String path, final String permission)
{
final String value = this.getString(path);
return factory.createActionList(value, permission).getOptimizedCopy(this);
}
/**
* A convenience method to get default action lists from the configuration, without
* applying any optimization.
*
* @param path
* the path
* @param permission
* the permission
* @return the action list
*/
public L getDefaultActionList(final String path, final String permission)
{
final String value = this.getString(path);
return factory.createActionList(value, permission);
}
/**
* Safely store ActionLists back into the yml file.
*
* @param path
* the path
* @param list
* the list
*/
public void set(final String path, final L list) {
final StringBuffer string = new StringBuffer();
for (final Integer threshold : list.getThresholds()) {
if (threshold > 0)
string.append(" vl>").append(threshold);
for (final Action<D, L> action : list.getActions(threshold))
string.append(" ").append(action);
}
set(path, string.toString().trim());
}
}

View File

@ -6,7 +6,7 @@ import java.util.Collection;
* This is to bridge the gap between ConfigFile which needs Action and RawConfigFile which has to be available in NCPCompat. <br>
* Aim is not speed of execution but providing a way of accessing all configs to set properties from within compatibility modules.
* <br>
* This might be seen as a refactoring/structuring stage, leading to putting actions to NCPCompat as well.
* This might be seen as a refactoring/structuring stage, leading to putting actions to NCPCompat as well. RawConfigFile might get changed.
* @author mc_dev
*
*/

View File

@ -1,14 +1,10 @@
package fr.neatmonster.nocheatplus.actions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import fr.neatmonster.nocheatplus.actions.types.CancelAction;
import fr.neatmonster.nocheatplus.actions.types.CommandAction;
import fr.neatmonster.nocheatplus.actions.types.DummyAction;
import fr.neatmonster.nocheatplus.actions.types.LogAction;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.logging.LogUtil;
/*
@ -24,8 +20,7 @@ import fr.neatmonster.nocheatplus.logging.LogUtil;
/**
* Helps with creating Actions out of text string definitions.
*/
public class ActionFactory {
protected static final Map<String, Object> lib = new HashMap<String, Object>();
public class ActionFactory extends AbstractActionFactory<ViolationData, ActionList> {
/**
* Instantiates a new action factory.
@ -34,7 +29,7 @@ public class ActionFactory {
* the library
*/
public ActionFactory(final Map<String, Object> library) {
lib.putAll(library);
super(library, ActionList.listFactory);
}
/**
@ -44,122 +39,24 @@ public class ActionFactory {
* the action definition
* @return the action
*/
public Action createAction(String actionDefinition) {
public Action<ViolationData, ActionList> createAction(String actionDefinition) {
actionDefinition = actionDefinition.toLowerCase();
if (actionDefinition.equals("cancel"))
return new CancelAction();
return new CancelAction<ViolationData, ActionList>();
if (actionDefinition.startsWith("cmd:"))
return parseCmdAction(actionDefinition.split(":", 2)[1]);
if (actionDefinition.startsWith("log:"))
return parseLogAction(actionDefinition.split(":", 2)[1]);
if (actionDefinition.startsWith("cmd:"))
return parseCmdAction(actionDefinition.split(":", 2)[1]);
throw new IllegalArgumentException("NoCheatPlus doesn't understand action '" + actionDefinition + "' at all");
}
/**
* Creates a new Action object.
*
* @param definition
* the definition
* @param permission
* the permission
* @return the action list
*/
public ActionList createActionList(final String definition, final String permission) {
final ActionList list = new ActionList(permission);
// Do check for null, to allow removing default actions, for better robustness.
if (definition == null) return list;
boolean first = true;
for (String s : definition.split("vl>")) {
s = s.trim();
if (s.length() == 0) {
first = false;
continue;
}
try {
Integer vl;
String def;
if (first) {
first = false;
vl = 0;
def = s;
} else {
final String[] listEntry = s.split("\\s+", 2);
vl = Integer.parseInt(listEntry[0]);
def = listEntry[1];
}
list.setActions(vl, createActions(def.split("\\s+")));
} catch (final Exception e) {
LogUtil.logWarning("[NoCheatPlus] Couldn't parse action definition 'vl:" + s + "'.");
}
}
return list;
}
/**
* Creates a new Action object.
*
* @param definitions
* the definitions
* @return the action[]
*/
public Action[] createActions(final String... definitions) {
final List<Action> actions = new ArrayList<Action>();
for (final String def : definitions) {
if (def.length() == 0)
continue;
try {
actions.add(createAction(def));
} catch (final IllegalArgumentException e) {
LogUtil.logWarning("[NoCheatPlus] Failed to create action: " + e.getMessage());
actions.add(new DummyAction(def));
}
}
return actions.toArray(new Action[actions.size()]);
}
/**
* Parses the cmd action.
*
* @param definition
* the definition
* @return the action
*/
protected Action parseCmdAction(final String definition) {
final String[] parts = definition.split(":");
final String name = parts[0];
final Object command = lib.get(parts[0]);
int delay = 0;
int repeat = 0;
if (command == null)
throw new IllegalArgumentException("NoCheatPlus doesn't know command '" + name
+ "'. Have you forgotten to define it?");
if (parts.length > 1)
try {
delay = Integer.parseInt(parts[1]);
repeat = Integer.parseInt(parts[2]);
} catch (final Exception e) {
LogUtil.logWarning("[NoCheatPlus] Couldn't parse details of command '" + definition
+ "', will use default values instead.");
delay = 0;
repeat = 0;
}
return new CommandAction(name, delay, repeat, command.toString());
}
/**
* Parses the log action.
@ -168,7 +65,7 @@ public class ActionFactory {
* the definition
* @return the action
*/
protected Action parseLogAction(final String definition) {
protected Action<ViolationData, ActionList> parseLogAction(final String definition) {
final String[] parts = definition.split(":");
final String name = parts[0];
final Object message = lib.get(parts[0]);

View File

@ -1,13 +1,7 @@
package fr.neatmonster.nocheatplus.actions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.config.ConfigFile;
/*
@ -25,115 +19,19 @@ import fr.neatmonster.nocheatplus.config.ConfigFile;
* <hr>
* TODO: refactor to an array of Actions entries (threshold + Action[]) + sort that one.
*/
public class ActionList {
/** Something to return if nothing is set. */
private static final Action[] emptyArray = new Action[0];
public class ActionList extends AbstractActionList<ViolationData, ActionList>{
/** This is a very bad design decision, but it's also really convenient to define this here. */
public final String permissionSilent;
public static final ActionListFactory<ViolationData, ActionList> listFactory = new ActionListFactory<ViolationData, ActionList>() {
/** The actions of this ActionList, "bundled" by treshold (violation level). */
private final Map<Integer, Action[]> actions = new HashMap<Integer, Action[]>();
/** The thresholds of this list. **/
private final List<Integer> thresholds = new ArrayList<Integer>();
/**
* Instantiates a new action list.
*
* @param permissionSilent
* the permission
*/
public ActionList(final String permissionSilent) {
this.permissionSilent = permissionSilent + ".silent";
}
/**
* Get a list of actions that match the violation level. The only method that has to be called by a check.
*
* @param violationLevel
* the violation level that should be matched
* @return the array of actions whose threshold was closest to the violation level but not bigger
*/
public Action[] getActions(final double violationLevel) {
Integer result = null;
for (final Integer threshold : thresholds)
if (threshold <= violationLevel)
result = threshold;
if (result != null)
return actions.get(result);
else
return emptyArray;
}
/**
* Get a sorted list of the thresholds/violation levels that were used in this list.
*
* @return the sorted list of thresholds.
*/
public List<Integer> getThresholds() {
return thresholds;
}
/**
* Add an entry to this actionList. The list will be sorted by thresholds automatically after the insertion.
*
* @param threshold
* the minimum violation level a player needs to have to be suspected to the given actions
* @param actions
* the actions that will be used if the player reached the accompanying threshold/violation level
*/
public void setActions(final Integer threshold, final Action[] actions) {
if (!thresholds.contains(threshold)) {
thresholds.add(threshold);
Collections.sort(thresholds);
}
this.actions.put(threshold, actions);
}
/**
* Return a copy of this list, but optimize it, i.e. remove entries that are
* never called, possibly do other optimizations which are possible given
* the specific configuration.
*
* @param config Configuration to adapt to.
* @return Optimized ActionList, individual Actions can be identical instances, altered Action instances must always be new instances, arrays are always new arrays.
*/
public ActionList getOptimizedCopy(final ConfigFile config) {
final ActionList newList = new ActionList(this.permissionSilent);
for (final Entry<Integer, Action[]> entry : actions.entrySet()){
final Integer t = entry.getKey();
final Action[] a = getOptimizedCopy(config, t, entry.getValue());
if (a != null && a.length > 0){
newList.setActions(t, a);
}
@Override
public ActionList getNewActionList(String permissionSilent) {
return new ActionList(permissionSilent);
}
return newList;
}
/**
* Get an optimized copy of the Actions array, given the config in use.
* @param config
* @param threshold
* @param actions
* @return Copy with optimized entries, null or empty arrays are possible. Contained Actions might be identical to the given ones, just changed actions must be new instances to preserve consistency, Action instances are not to be altered.
*/
public Action[] getOptimizedCopy(final ConfigFile config, final Integer threshold, final Action[] actions)
{
if (actions == null || actions.length == 0) return null;
final ArrayList<Action> optimized = new ArrayList<Action>();
for (final Action action : actions){
final Action optAction = action.getOptimizedCopy(config, threshold);
if (optAction != null) optimized.add(optAction);
}
if (optimized.isEmpty()) return null;
final Action[] optActions = new Action[optimized.size()];
optimized.toArray(optActions);
return optActions;
};
public ActionList(String permissionSilent) {
super(permissionSilent, listFactory);
}
}

View File

@ -4,9 +4,10 @@ import org.bukkit.ChatColor;
import fr.neatmonster.nocheatplus.NoCheatPlus;
import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.actions.ActionList;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.config.ConfPaths;
import fr.neatmonster.nocheatplus.config.ConfigFile;
import fr.neatmonster.nocheatplus.config.ConfigFileWithActions;
import fr.neatmonster.nocheatplus.logging.LogUtil;
import fr.neatmonster.nocheatplus.logging.StaticLogFile;
import fr.neatmonster.nocheatplus.utilities.ColorUtil;
@ -24,7 +25,10 @@ import fr.neatmonster.nocheatplus.utilities.ColorUtil;
/**
* Print a log message to various locations.
*/
public class LogAction extends ActionWithParameters {
public class LogAction extends ActionWithParameters<ViolationData, ActionList> {
// TODO: pull down to providers for (console), !chat!, (file) - then move to NCPCompat.
// Some flags to decide where the log message should show up, based on the configuration file.
/** Log to chat? */
public final boolean toChat;
@ -92,7 +96,7 @@ public class LogAction extends ActionWithParameters {
}
@Override
public Action getOptimizedCopy(final ConfigFile config, final Integer threshold) {
public Action<ViolationData, ActionList> getOptimizedCopy(final ConfigFileWithActions<ViolationData, ActionList> config, final Integer threshold) {
if (!config.getBoolean(ConfPaths.LOGGING_ACTIVE)) return null;
final boolean toConsole = this.toConsole && config.getBoolean(ConfPaths.LOGGING_CONSOLE);
final boolean toFile = this.toFile&& config.getBoolean(ConfPaths.LOGGING_FILE);

View File

@ -5,6 +5,7 @@ import java.util.Map;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.actions.ActionData;
import fr.neatmonster.nocheatplus.actions.ActionList;
import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.actions.types.CancelAction;
@ -27,13 +28,13 @@ import fr.neatmonster.nocheatplus.logging.LogUtil;
* TODO: Re-think visibility questions.
* @author asofold
*/
public class ViolationData implements IViolationInfo{
public class ViolationData implements IViolationInfo, ActionData{
/** The actions to be executed. */
public final ActionList actions;
/** The actions applicable for the violation level. */
public final Action[] applicableActions;
public final Action<ViolationData, ActionList>[] applicableActions;
/** The violation level added. */
public final double addedVL;
@ -87,7 +88,7 @@ public class ViolationData implements IViolationInfo{
*
* @return the actions
*/
public Action[] getActions() {
public Action<ViolationData, ActionList> [] getActions() {
return applicableActions;
}
@ -103,7 +104,7 @@ public class ViolationData implements IViolationInfo{
// TODO: the time is taken here, which makes sense for delay, but otherwise ?
final long time = System.currentTimeMillis() / 1000L;
boolean cancel = false;
for (final Action action : getActions())
for (final Action<ViolationData, ActionList> action : getActions())
if (Check.getHistory(player).executeAction(this, action, time))
// The execution history said it really is time to execute the action, find out what it is and do
// what is needed.
@ -123,17 +124,13 @@ public class ViolationData implements IViolationInfo{
*/
@Override
public boolean hasCancel(){
for (final Action action : applicableActions){
for (final Action<ViolationData, ActionList> action : applicableActions){
if (action instanceof CancelAction) return true;
}
return false;
}
/**
* Get the parameters value for this violation.
* @param parameterName
* @return Will always return some string, if not set: "<?PARAMETERNAME>".
*/
@Override
public String getParameter(final ParameterName parameterName){
if (parameterName == null) return "<???>";
switch (parameterName) {
@ -151,6 +148,7 @@ public class ViolationData implements IViolationInfo{
return(value == null) ? ("<?" + parameterName + ">") : value;
}
@Override
public void setParameter(final ParameterName parameterName, String value){
if (parameters != null) parameters.put(parameterName, value);
}

View File

@ -1,11 +1,13 @@
package fr.neatmonster.nocheatplus.checks.access;
import fr.neatmonster.nocheatplus.actions.ParameterHolder;
/**
* Access interface for extended information about violations.
* @author mc_dev
*
*/
public interface IViolationInfo {
public interface IViolationInfo extends ParameterHolder{
/**
* Get the violation level just added by this violation.
* @return
@ -21,9 +23,5 @@ public interface IViolationInfo {
* @return
*/
boolean hasCancel();
/**
* Check if any of the actions needs parameters.
* @return If true, actions are likely to contian command or logging actions.
*/
boolean needsParameters();
}

View File

@ -2,9 +2,8 @@ package fr.neatmonster.nocheatplus.config;
import org.bukkit.configuration.MemorySection;
import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.actions.ActionFactory;
import fr.neatmonster.nocheatplus.actions.ActionList;
import fr.neatmonster.nocheatplus.checks.ViolationData;
/*
* MM'""""'YMM .8888b oo MM""""""""`M oo dP
@ -19,67 +18,11 @@ import fr.neatmonster.nocheatplus.actions.ActionList;
/**
* A special configuration class created to handle the loading/saving of actions lists. This is for normal use with the plugin.
*/
public class ConfigFile extends RawConfigFile {
/** The factory. */
private ActionFactory factory;
/**
* A convenience method to get an optimized action list from the configuration.
*
* @param path
* the path
* @param permission
* the permission
* @return the action list
*/
public ActionList getOptimizedActionList(final String path, final String permission)
{
final String value = this.getString(path);
return factory.createActionList(value, permission).getOptimizedCopy(this);
}
/**
* A convenience method to get default action lists from the configuration, without
* applying any optimization.
*
* @param path
* the path
* @param permission
* the permission
* @return the action list
*/
public ActionList getDefaultActionList(final String path, final String permission)
{
final String value = this.getString(path);
return factory.createActionList(value, permission);
}
/**
* Do this after reading new data.
*/
public class ConfigFile extends ConfigFileWithActions<ViolationData, ActionList> {
@Override
public void regenerateActionLists() {
factory = ConfigManager.getActionFactory(((MemorySection) this.get(ConfPaths.STRINGS)).getValues(false));
}
/**
* Safely store ActionLists back into the yml file.
*
* @param path
* the path
* @param list
* the list
*/
public void set(final String path, final ActionList list) {
final StringBuffer string = new StringBuffer();
for (final int threshold : list.getThresholds()) {
if (threshold > 0)
string.append(" vl>").append(threshold);
for (final Action action : list.getActions(threshold))
string.append(" ").append(action);
}
set(path, string.toString().trim());
}
}

View File

@ -4,6 +4,7 @@ import java.util.HashMap;
import java.util.Map;
import fr.neatmonster.nocheatplus.actions.Action;
import fr.neatmonster.nocheatplus.actions.ActionList;
import fr.neatmonster.nocheatplus.checks.ViolationData;
/*
@ -25,7 +26,8 @@ import fr.neatmonster.nocheatplus.checks.ViolationData;
* d8888P
*/
/**
* Store amount of action executions for last 60 seconds for various actions.
* Store amount of action executions for last 60 seconds for various actions.<br>
* TODO: Once away from static access, could put this to generic (Action<D extends ActionData>).
*/
public class ExecutionHistory {
@ -140,13 +142,13 @@ public class ExecutionHistory {
}
/** Store data between events (time + action + action-counter). **/
private final Map<Action, ExecutionHistoryEntry> entries;
private final Map<Action<ViolationData, ActionList>, ExecutionHistoryEntry> entries;
/**
* Instantiates a new execution history.
*/
public ExecutionHistory() {
entries = new HashMap<Action, ExecutionHistoryEntry>();
entries = new HashMap<Action<ViolationData, ActionList>, ExecutionHistoryEntry>();
}
/**
@ -162,7 +164,7 @@ public class ExecutionHistory {
* a time IN SECONDS
* @return true, if the action is to be executed.
*/
public boolean executeAction(final ViolationData violationData, final Action action, final long time)
public boolean executeAction(final ViolationData violationData, final Action<ViolationData, ActionList> action, final long time)
{
if (action.executesAlways()) return true;
ExecutionHistoryEntry entry = entries.get(action);
@ -192,7 +194,7 @@ public class ExecutionHistory {
* @param time
* @return
*/
public boolean wouldExecute(final ViolationData violationData, final Action action, final long time)
public boolean wouldExecute(final ViolationData violationData, final Action<ViolationData, ActionList> action, final long time)
{
if (action.executesAlways()) return true;
ExecutionHistoryEntry entry = entries.get(action);
@ -214,7 +216,7 @@ public class ExecutionHistory {
* @param action
* @return
*/
public ExecutionHistoryEntry getEntry(final Action action){
public ExecutionHistoryEntry getEntry(final Action<ViolationData, ActionList> action){
return entries.get(action);
}
}