diff --git a/manifest b/manifest new file mode 100644 index 00000000..f0c7423f --- /dev/null +++ b/manifest @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: cc.co.evenprime.bukkit.nocheat.Main +Class-Path: snakeyaml.jar \ No newline at end of file diff --git a/src/cc/co/evenprime/bukkit/nocheat/ConfigurationException.java b/src/cc/co/evenprime/bukkit/nocheat/ConfigurationException.java new file mode 100644 index 00000000..56f6bbc0 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/ConfigurationException.java @@ -0,0 +1,13 @@ +package cc.co.evenprime.bukkit.nocheat; + +public class ConfigurationException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -457634587532590464L; + + public ConfigurationException(String message) { + super(message); + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/Main.java b/src/cc/co/evenprime/bukkit/nocheat/Main.java new file mode 100644 index 00000000..fbfd9094 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/Main.java @@ -0,0 +1,15 @@ +package cc.co.evenprime.bukkit.nocheat; + +import cc.co.evenprime.bukkit.nocheat.wizard.Wizard; + +public class Main { + + /** + * @param args + */ + public static void main(String[] args) { + + Wizard w = new Wizard(); + w.setVisible(true); + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java b/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java index b3ae1dea..ebd05402 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java +++ b/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java @@ -13,7 +13,7 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; -import cc.co.evenprime.bukkit.nocheat.actions.Action; +import cc.co.evenprime.bukkit.nocheat.actions.CustomAction; import cc.co.evenprime.bukkit.nocheat.checks.AirbuildCheck; import cc.co.evenprime.bukkit.nocheat.checks.BedteleportCheck; import cc.co.evenprime.bukkit.nocheat.checks.BogusitemsCheck; @@ -21,6 +21,7 @@ import cc.co.evenprime.bukkit.nocheat.checks.Check; import cc.co.evenprime.bukkit.nocheat.checks.ItemdupeCheck; import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck; import cc.co.evenprime.bukkit.nocheat.checks.SpeedhackCheck; +import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration; import cc.co.evenprime.bukkit.nocheat.data.PermissionData; import com.ensifera.animosity.craftirc.CraftIRC; @@ -37,14 +38,14 @@ import org.bukkit.util.config.Configuration; * * @author Evenprime */ -public class NoCheat extends JavaPlugin { +public class NoCheat extends JavaPlugin implements CommandSender { - public MovingCheck movingCheck; - public BedteleportCheck bedteleportCheck; - public SpeedhackCheck speedhackCheck; - public AirbuildCheck airbuildCheck; - public ItemdupeCheck itemdupeCheck; - public BogusitemsCheck bogusitemsCheck; + private MovingCheck movingCheck; + private BedteleportCheck bedteleportCheck; + private SpeedhackCheck speedhackCheck; + private AirbuildCheck airbuildCheck; + private ItemdupeCheck itemdupeCheck; + private BogusitemsCheck bogusitemsCheck; private Check[] checks; @@ -66,6 +67,12 @@ public class NoCheat extends JavaPlugin { private CraftIRC irc; private boolean allowFlightSet; + private Level chatLevel; + private Level ircLevel; + private Level consoleLevel; + private String ircTag; + + public NoCheat() { } @@ -119,12 +126,15 @@ public class NoCheat extends JavaPlugin { public void onEnable() { - movingCheck = new MovingCheck(this); - bedteleportCheck = new BedteleportCheck(this); - speedhackCheck = new SpeedhackCheck(this); - airbuildCheck = new AirbuildCheck(this); - itemdupeCheck = new ItemdupeCheck(this); - bogusitemsCheck = new BogusitemsCheck(this); + // parse the nocheat.yml config file + setupConfig(); + + movingCheck = new MovingCheck(this, config); + bedteleportCheck = new BedteleportCheck(this, config); + speedhackCheck = new SpeedhackCheck(this, config); + airbuildCheck = new AirbuildCheck(this, config); + itemdupeCheck = new ItemdupeCheck(this, config); + bogusitemsCheck = new BogusitemsCheck(this, config); // just for convenience checks = new Check[] { movingCheck, bedteleportCheck, speedhackCheck, airbuildCheck, itemdupeCheck, bogusitemsCheck }; @@ -242,7 +252,7 @@ public class NoCheat extends JavaPlugin { } private void logToChat(Level l, String message) { - if(config.chatLevel.intValue() <= l.intValue()) { + if(chatLevel.intValue() <= l.intValue()) { for(Player player : getServer().getOnlinePlayers()) { if(hasPermission(player, PermissionData.PERMISSION_NOTIFY)) { player.sendMessage("["+l.getName()+"] " + message); @@ -252,13 +262,13 @@ public class NoCheat extends JavaPlugin { } private void logToIRC(Level l, String message) { - if(irc != null && config.ircLevel.intValue() <= l.intValue()) { - irc.sendMessageToTag("["+l.getName()+"] " + message , config.ircTag); + if(irc != null && ircLevel.intValue() <= l.intValue()) { + irc.sendMessageToTag("["+l.getName()+"] " + message , ircTag); } } private void logToConsole(Level l, String message) { - if( config.consoleLevel.intValue() <= l.intValue()) { + if( consoleLevel.intValue() <= l.intValue()) { Logger.getLogger("Minecraft").log(l, message); } } @@ -301,9 +311,22 @@ public class NoCheat extends JavaPlugin { */ private void setupConfig() { if(this.config == null) - this.config = new NoCheatConfiguration(this); + this.config = new NoCheatConfiguration(new File(NoCheatConfiguration.configFile)); else - this.config.config(); + this.config.config(new File(NoCheatConfiguration.configFile)); + + config.setupFileLogger(); + + try { + this.chatLevel = config.getLogLevelValue("logging.logtochat"); + this.ircLevel = config.getLogLevelValue("logging.logtoirc"); + this.consoleLevel = config.getLogLevelValue("logging.logtoconsole"); + this.ircTag = config.getStringValue("logging.logtoirctag"); + } catch (ConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + this.setEnabled(false); + } Configuration serverConfig = new Configuration(new File("server.properties")); @@ -349,8 +372,24 @@ public class NoCheat extends JavaPlugin { return this.serverLagInMilliSeconds; } - public void handleCustomAction(Action a, Player player) { - // TODO Auto-generated method stub + public void handleCustomAction(CustomAction a, Player player) { + + Bukkit.getServer().dispatchCommand(this, a.command.replace("[player]", player.getName())); + System.out.println("Would execute "+a.command + " now for Player " + player.getName() ); } + + + + @Override + public void sendMessage(String message) { + // we don't receive messages + + } + + @Override + public boolean isOp() { + // We declare ourselves to be OP to be allowed to do more commands + return true; + } } \ No newline at end of file diff --git a/src/cc/co/evenprime/bukkit/nocheat/NoCheatConfiguration.java b/src/cc/co/evenprime/bukkit/nocheat/NoCheatConfiguration.java deleted file mode 100644 index c4c0666a..00000000 --- a/src/cc/co/evenprime/bukkit/nocheat/NoCheatConfiguration.java +++ /dev/null @@ -1,302 +0,0 @@ -package cc.co.evenprime.bukkit.nocheat; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; -import java.util.logging.FileHandler; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bukkit.util.config.Configuration; - -import cc.co.evenprime.bukkit.nocheat.actions.Action; -import cc.co.evenprime.bukkit.nocheat.actions.CancelAction; -import cc.co.evenprime.bukkit.nocheat.actions.LogAction; - -/** - * Central location for everything that's described in the configuration file - * - * @author Evenprime - * - */ -public class NoCheatConfiguration { - - - private final static String configFile = "plugins/NoCheat/nocheat.yml"; - - // Our personal logger - private final static String loggerName = "cc.co.evenprime.nocheat"; - public final Logger logger = Logger.getLogger(loggerName); - - // The log level above which information gets logged to the specified logger - public Level chatLevel = Level.WARNING; - public Level ircLevel = Level.WARNING; - public Level consoleLevel = Level.SEVERE; - public Level fileLevel = Level.INFO; - - public String fileName = "plugins/NoCheat/nocheat.log"; - - public String ircTag = "nocheat"; - - // Our log output to a file - private FileHandler fh = null; - - private final NoCheat plugin; - - public NoCheatConfiguration(NoCheat plugin) { - - this.plugin = plugin; - - config(); - } - - /** - * Read the configuration file and assign either standard values or whatever is declared in the file - * @param configurationFile - */ - public void config() { - - File configurationFile = new File(configFile); - - if(!configurationFile.exists()) { - createStandardConfigFile(configurationFile); - } - - Configuration c = new Configuration(configurationFile); - c.load(); - - logger.setLevel(Level.INFO); - logger.setUseParentHandlers(false); - - chatLevel = stringToLevel(c.getString("logging.logtochat"), chatLevel); - consoleLevel = stringToLevel(c.getString("logging.logtoconsole"), consoleLevel); - fileLevel = stringToLevel(c.getString("logging.logtofile"), fileLevel); - ircLevel = stringToLevel(c.getString("logging.logtoirc"), ircLevel); - ircTag = c.getString("logging.logtoirctag", ircTag); - - if(fh == null) { - try { - fh = new FileHandler(fileName, true); - fh.setLevel(fileLevel); - fh.setFormatter(new LogFileFormatter()); - logger.addHandler(fh); - - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - plugin.speedhackCheck.limits[0] = c.getInt("speedhack.limits.low", plugin.speedhackCheck.limits[0]); - plugin.speedhackCheck.limits[1] = c.getInt("speedhack.limits.med", plugin.speedhackCheck.limits[1]); - plugin.speedhackCheck.limits[2] = c.getInt("speedhack.limits.high", plugin.speedhackCheck.limits[2]); - - plugin.speedhackCheck.logMessage = c.getString("speedhack.logmessage", plugin.speedhackCheck.logMessage); - - plugin.movingCheck.actions[0] = stringToActions(c.getString("moving.action.low"), plugin.movingCheck.actions[0]); - plugin.movingCheck.actions[1] = stringToActions(c.getString("moving.action.med"), plugin.movingCheck.actions[1]); - plugin.movingCheck.actions[2] = stringToActions(c.getString("moving.action.high"), plugin.movingCheck.actions[2]); - - - plugin.movingCheck.logMessage = c.getString("moving.logmessage", plugin.movingCheck.logMessage); - plugin.movingCheck.summaryMessage = c.getString("moving.summarymessage", plugin.movingCheck.summaryMessage); - - plugin.movingCheck.allowFlying = c.getBoolean("moving.allowflying", plugin.movingCheck.allowFlying); - plugin.movingCheck.allowFakeSneak = c.getBoolean("moving.allowfakesneak", plugin.movingCheck.allowFakeSneak); - - plugin.speedhackCheck.actions[0] = stringToActions(c.getString("speedhack.action.low"), plugin.speedhackCheck.actions[0]); - plugin.speedhackCheck.actions[1] = stringToActions(c.getString("speedhack.action.med"), plugin.speedhackCheck.actions[1]); - plugin.speedhackCheck.actions[2] = stringToActions(c.getString("speedhack.action.high"), plugin.speedhackCheck.actions[2]); - - plugin.airbuildCheck.limits[0] = c.getInt("airbuild.limits.low", plugin.airbuildCheck.limits[0]); - plugin.airbuildCheck.limits[1] = c.getInt("airbuild.limits.med", plugin.airbuildCheck.limits[1]); - plugin.airbuildCheck.limits[2] = c.getInt("airbuild.limits.high", plugin.airbuildCheck.limits[2]); - - plugin.airbuildCheck.actions[0] = stringToActions(c.getString("airbuild.action.low"), plugin.airbuildCheck.actions[0]); - plugin.airbuildCheck.actions[1] = stringToActions(c.getString("airbuild.action.med"), plugin.airbuildCheck.actions[1]); - plugin.airbuildCheck.actions[2] = stringToActions(c.getString("airbuild.action.high"), plugin.airbuildCheck.actions[2]); - - plugin.speedhackCheck.setActive(c.getBoolean("active.speedhack", true)); - plugin.movingCheck.setActive(c.getBoolean("active.moving", true)); - plugin.airbuildCheck.setActive(c.getBoolean("active.airbuild", false)); - plugin.bedteleportCheck.setActive(c.getBoolean("active.bedteleport", true)); - plugin.itemdupeCheck.setActive(c.getBoolean("active.itemdupe", true)); - plugin.bogusitemsCheck.setActive(c.getBoolean("active.bogusitems", false)); - } - - public void cleanup() { - - if(fh != null) { - try { - logger.removeHandler(fh); - fh.flush(); - fh.close(); - - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - private Action[] stringToActions(String string, Action[] def) { - - if(string == null) return def; - - List as = new LinkedList(); - String[] parts = string.split(" "); - - for(String s : parts) { - if(s.equals("loglow")) - as.add(LogAction.loglow); - else if(s.equals("logmed")) - as.add(LogAction.logmed); - else if(s.equals("loghigh")) - as.add(LogAction.loghigh); - else if(s.equals("deny")) - as.add(CancelAction.cancel); - else if(s.equals("reset")) - as.add(CancelAction.cancel); - else if(s.equals("cancel")) - as.add(CancelAction.cancel); - else if(s.startsWith("custom")) { - try { - // TODO: Implement Custom Action - //as.add(new CustomAction(Integer.parseInt(s.substring(6)))); - } - catch(Exception e) { - System.out.println("NC: Couldn't parse number of custom action '" + s + "'"); - } - } - else { - System.out.println("NC: Can't parse action "+ s); - } - } - - - return as.toArray(def); - } - - private String actionsToString(Action[] actions) { - - StringBuffer s = new StringBuffer(); - - if(actions != null) { - for(Action a : actions) { - s.append(' ').append(a.getName()); - } - } - - return s.toString().trim(); - } - /** - * Convert a string into a log level - * @param string - * @return - */ - private static Level stringToLevel(String string, Level def) { - - if(string == null) { - return def; - } - - if(string.trim().equals("info") || string.trim().equals("low")) return Level.INFO; - if(string.trim().equals("warn") || string.trim().equals("med")) return Level.WARNING; - if(string.trim().equals("severe")|| string.trim().equals("high")) return Level.SEVERE; - - return Level.OFF; - } - - private static String levelToString(Level level) { - - if(level == null) { - return "off"; - } - - if(level.equals(Level.INFO)) return "low"; - else if(level.equals(Level.WARNING)) return "med"; - else if(level.equals(Level.SEVERE)) return "high"; - - return "off"; - } - - /** - * Standard configuration file for people who haven't got one yet - * @param f - */ - private void createStandardConfigFile(File f) { - try { - f.getParentFile().mkdirs(); - f.createNewFile(); - BufferedWriter w = new BufferedWriter(new FileWriter(f)); - - w.write("# Logging: potential log levels are low (info), med (warn), high (severe), off"); w.newLine(); - w.write("logging:"); w.newLine(); - w.write(" filename: "+fileName); w.newLine(); - w.write(" logtofile: "+levelToString(fileLevel)); w.newLine(); - w.write(" logtoconsole: "+levelToString(consoleLevel)); w.newLine(); - w.write(" logtochat: "+levelToString(chatLevel)); w.newLine(); - w.write(" logtoirc: "+levelToString(ircLevel)); w.newLine(); - w.write(" logtoirctag: "+ircTag); w.newLine(); - w.write("# Checks and Bugfixes that are activated (true or false)"); w.newLine(); - w.write("active:"); w.newLine(); - w.write(" speedhack: true"); w.newLine(); - w.write(" moving: true"); w.newLine(); - w.write(" airbuild: false"); w.newLine(); - w.write(" bedteleport: true"); w.newLine(); - w.write(" itemdupe: true"); w.newLine(); - w.write(" bogusitems: false"); w.newLine(); - w.write("# Speedhack specific options"); w.newLine(); - w.write("speedhack:"); w.newLine(); - w.write(" logmessage: \"" + plugin.speedhackCheck.logMessage+"\""); w.newLine(); - w.write(" limits:"); w.newLine(); - w.write(" low: "+plugin.speedhackCheck.limits[0]); w.newLine(); - w.write(" med: "+plugin.speedhackCheck.limits[1]); w.newLine(); - w.write(" high: "+plugin.speedhackCheck.limits[2]); w.newLine(); - w.write("# Speedhack Action, one or more of 'loglow logmed loghigh cancel'"); w.newLine(); - w.write(" action:"); w.newLine(); - w.write(" low: "+actionsToString(plugin.speedhackCheck.actions[0])); w.newLine(); - w.write(" med: "+actionsToString(plugin.speedhackCheck.actions[1])); w.newLine(); - w.write(" high: "+actionsToString(plugin.speedhackCheck.actions[2])); w.newLine(); - w.write("# Moving specific options") ; w.newLine(); - w.write("moving:"); w.newLine(); - w.write(" logmessage: \"" + plugin.movingCheck.logMessage+"\""); w.newLine(); - w.write(" summarymessage: \"" + plugin.movingCheck.summaryMessage+"\""); w.newLine(); - w.write("# Should (normal speed) flying be generally allowed?"); w.newLine(); - w.write(" allowflying: " + plugin.movingCheck.allowFlying); w.newLine(); - w.write("# Should sneaking with normal walking speed be generally allowed?"); w.newLine(); - w.write(" allowfakesneak: " + plugin.movingCheck.allowFakeSneak); w.newLine(); - w.write("# Moving Action, one or more of 'loglow logmed loghigh cancel'"); w.newLine(); - w.write(" action:"); w.newLine(); - w.write(" low: "+actionsToString(plugin.movingCheck.actions[0])); w.newLine(); - w.write(" med: "+actionsToString(plugin.movingCheck.actions[1])); w.newLine(); - w.write(" high: "+actionsToString(plugin.movingCheck.actions[2])); w.newLine(); - w.write("# Airbuild specific options"); w.newLine(); - w.write("airbuild:"); w.newLine(); - w.write("# How many blocks per second are placed by the player in midair to trigger corresponding action"); w.newLine(); - w.write(" limits:"); w.newLine(); - w.write(" low: "+plugin.airbuildCheck.limits[0]); w.newLine(); - w.write(" med: "+plugin.airbuildCheck.limits[1]); w.newLine(); - w.write(" high: "+plugin.airbuildCheck.limits[2]); w.newLine(); - w.write("# Airbuild Action, one or more of 'loglow logmed loghigh cancel'"); w.newLine(); - w.write(" action:"); w.newLine(); - w.write(" low: "+actionsToString(plugin.airbuildCheck.actions[0])); w.newLine(); - w.write(" med: "+actionsToString(plugin.airbuildCheck.actions[1])); w.newLine(); - w.write(" high: "+actionsToString(plugin.airbuildCheck.actions[2])); w.newLine(); - w.write("# Bedteleport specific options (none exist yet)"); w.newLine(); - w.write("bedteleport:"); w.newLine(); - w.write("# Itemdupe specific options (none exist yet)"); w.newLine(); - w.write("itemdupe:"); w.newLine(); - w.write("# Bogusitems specific options (none exist yet)"); w.newLine(); - w.write("bogusitems:"); w.newLine(); - - w.flush(); w.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } -} diff --git a/src/cc/co/evenprime/bukkit/nocheat/actions/CustomAction.java b/src/cc/co/evenprime/bukkit/nocheat/actions/CustomAction.java index ca9c89e0..ba7c2670 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/actions/CustomAction.java +++ b/src/cc/co/evenprime/bukkit/nocheat/actions/CustomAction.java @@ -18,4 +18,16 @@ public class CustomAction extends Action { public String getName() { return "custom"; } + + public String getValue() { + if(firstAfter <= 1 && repeat) { + return command; + } + else if(repeat) { + return "["+firstAfter+"] "+ command; + } + else { + return "["+firstAfter+","+repeat+"] "+ command; + } + } } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java index d1d8855a..e047d9ec 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java @@ -9,11 +9,13 @@ import org.bukkit.event.Event.Priority; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.plugin.PluginManager; +import cc.co.evenprime.bukkit.nocheat.ConfigurationException; import cc.co.evenprime.bukkit.nocheat.NoCheat; import cc.co.evenprime.bukkit.nocheat.actions.Action; import cc.co.evenprime.bukkit.nocheat.actions.CancelAction; import cc.co.evenprime.bukkit.nocheat.actions.CustomAction; import cc.co.evenprime.bukkit.nocheat.actions.LogAction; +import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration; import cc.co.evenprime.bukkit.nocheat.data.AirbuildData; import cc.co.evenprime.bukkit.nocheat.data.PermissionData; import cc.co.evenprime.bukkit.nocheat.listeners.AirbuildBlockListener; @@ -28,15 +30,12 @@ import cc.co.evenprime.bukkit.nocheat.listeners.AirbuildBlockListener; public class AirbuildCheck extends Check { // How should airbuild violations be treated? - public final Action actions[][] = { - { LogAction.loglow, CancelAction.cancel }, - { LogAction.logmed, CancelAction.cancel }, - { LogAction.loghigh, CancelAction.cancel } }; + private Action actions[][]; - public final int limits[] = { 1, 3, 10 }; + private int limits[]; - public AirbuildCheck(NoCheat plugin) { - super(plugin, "airbuild", PermissionData.PERMISSION_AIRBUILD); + public AirbuildCheck(NoCheat plugin, NoCheatConfiguration config) { + super(plugin, "airbuild", PermissionData.PERMISSION_AIRBUILD, config); } public void check(BlockPlaceEvent event) { @@ -60,52 +59,42 @@ public class AirbuildCheck extends Check { } }; - // Give a summary in 20 ticks ~ 1 second - plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, data.summaryTask, 20); + // Give a summary in 100 ticks ~ 1 second + plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, data.summaryTask, 100); } - data.perSecond++; + data.perFiveSeconds++; // which limit has been reached for(int i = limits.length-1; i >= 0; i--) { - if(data.perSecond >= limits[i]) { - // Only explicitly log certain "milestones" - if(data.perSecond == limits[i]) { - action(actions[i], event, true); - } - else { - action(actions[i], event, false); - } + if(data.perFiveSeconds >= limits[i]) { + action(actions[i], event, data.perFiveSeconds - limits[i]+1); break; } } } } - private void action(Action actions[], BlockPlaceEvent event, boolean loggingAllowed) { + private void action(Action actions[], BlockPlaceEvent event, int violations) { if(actions == null) return; - boolean cancelled = false; - - // Prepare log message if needed - String logMessage = null; - if(loggingAllowed) { - final Location l = event.getBlockPlaced().getLocation(); - logMessage = "Airbuild: "+event.getPlayer().getName()+" tried to place block " + event.getBlockPlaced().getType() + " in the air at " + l.getBlockX() + "," + l.getBlockY() +"," + l.getBlockZ(); - } - // Execute actions in order for(Action a : actions) { - if(loggingAllowed && a instanceof LogAction) { - plugin.log(((LogAction)a).level, logMessage); - } - else if(!cancelled && a instanceof CancelAction) { - event.setCancelled(true); - cancelled = true; - } - else if(a instanceof CustomAction) { - plugin.handleCustomAction(a, event.getPlayer()); + if(a.firstAfter <= violations) { + if(a.firstAfter == violations || a.repeat) { + if(a instanceof LogAction) { + final Location l = event.getBlockPlaced().getLocation(); + String logMessage = "Airbuild: "+event.getPlayer().getName()+" tried to place block " + event.getBlockPlaced().getType() + " in the air at " + l.getBlockX() + "," + l.getBlockY() +"," + l.getBlockZ(); + plugin.log(((LogAction)a).level, logMessage); + } + else if(a instanceof CancelAction) { + event.setCancelled(true); + } + else if(a instanceof CustomAction) { + plugin.handleCustomAction((CustomAction)a, event.getPlayer()); + } + } } } } @@ -114,13 +103,37 @@ public class AirbuildCheck extends Check { // Give a summary according to the highest violation level we encountered in that second for(int i = limits.length-1; i >= 0; i--) { - if(data.perSecond >= limits[i]) { - plugin.log(LogAction.log[i].level, "Airbuild summary: " +player.getName() + " total violations per second: " + data.perSecond); + if(data.perFiveSeconds >= limits[i]) { + plugin.log(LogAction.log[i].level, "Airbuild summary: " +player.getName() + " total violations per 5 seconds: " + data.perFiveSeconds); break; } } - data.perSecond = 0; + data.perFiveSeconds = 0; + } + + @Override + public void configure(NoCheatConfiguration config) { + + try { + limits = new int[3]; + + limits[0] = config.getIntegerValue("airbuild.limits.low"); + limits[1] = config.getIntegerValue("airbuild.limits.med"); + limits[2] = config.getIntegerValue("airbuild.limits.high"); + + actions = new Action[3][]; + + actions[0] = config.getActionValue("airbuild.action.low"); + actions[1] = config.getActionValue("airbuild.action.med"); + actions[2] = config.getActionValue("airbuild.action.high"); + + setActive(config.getBooleanValue("active.airbuild")); + + } catch (ConfigurationException e) { + setActive(false); + e.printStackTrace(); + } } @Override diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/BedteleportCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/BedteleportCheck.java index 885d2df6..e63507be 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/BedteleportCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/BedteleportCheck.java @@ -6,7 +6,9 @@ import org.bukkit.event.Event.Priority; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.plugin.PluginManager; +import cc.co.evenprime.bukkit.nocheat.ConfigurationException; import cc.co.evenprime.bukkit.nocheat.NoCheat; +import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration; import cc.co.evenprime.bukkit.nocheat.data.PermissionData; import cc.co.evenprime.bukkit.nocheat.listeners.BedteleportPlayerListener; @@ -18,8 +20,8 @@ import cc.co.evenprime.bukkit.nocheat.listeners.BedteleportPlayerListener; public class BedteleportCheck extends Check { - public BedteleportCheck(NoCheat plugin) { - super(plugin, "bedteleport", PermissionData.PERMISSION_BEDTELEPORT); + public BedteleportCheck(NoCheat plugin, NoCheatConfiguration config) { + super(plugin, "bedteleport", PermissionData.PERMISSION_BEDTELEPORT, config); } public void check(PlayerMoveEvent event) { @@ -31,7 +33,18 @@ public class BedteleportCheck extends Check { if(event.getPlayer().isSleeping()) event.setCancelled(true); } - + + @Override + public void configure(NoCheatConfiguration config) { + + try { + setActive(config.getBooleanValue("active.bedteleport")); + } catch (ConfigurationException e) { + setActive(false); + e.printStackTrace(); + } + } + @Override protected void registerListeners() { PluginManager pm = Bukkit.getServer().getPluginManager(); diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/BogusitemsCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/BogusitemsCheck.java index dc764dbd..87ca949b 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/BogusitemsCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/BogusitemsCheck.java @@ -15,14 +15,16 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.PluginManager; +import cc.co.evenprime.bukkit.nocheat.ConfigurationException; import cc.co.evenprime.bukkit.nocheat.NoCheat; +import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration; import cc.co.evenprime.bukkit.nocheat.data.PermissionData; import cc.co.evenprime.bukkit.nocheat.listeners.BogusitemsPlayerListener; public class BogusitemsCheck extends Check { - public BogusitemsCheck(NoCheat plugin){ - super(plugin, "bogusitems", PermissionData.PERMISSION_BOGUSITEMS); + public BogusitemsCheck(NoCheat plugin, NoCheatConfiguration config){ + super(plugin, "bogusitems", PermissionData.PERMISSION_BOGUSITEMS, config); } public void check(PlayerPickupItemEvent event) { @@ -86,11 +88,22 @@ public class BogusitemsCheck extends Check { for(int i = 0; i < stacks.length; i++) { if(stacks[i] != null && stacks[i].getAmount() <= 0) { inv.clear(i); - plugin.log(Level.WARNING, "Removed illegal item from inventory of " + player.getName()); + plugin.log(Level.WARNING, "Removed invalid item from inventory of " + player.getName()); } } } + @Override + public void configure(NoCheatConfiguration config) { + + try { + setActive(config.getBooleanValue("active.bogusitems")); + } catch (ConfigurationException e) { + setActive(false); + e.printStackTrace(); + } + } + @Override protected void registerListeners() { PluginManager pm = Bukkit.getServer().getPluginManager(); diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/Check.java b/src/cc/co/evenprime/bukkit/nocheat/checks/Check.java index 3826ae49..1156e3c7 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/Check.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/Check.java @@ -4,6 +4,7 @@ package cc.co.evenprime.bukkit.nocheat.checks; import org.bukkit.entity.Player; import cc.co.evenprime.bukkit.nocheat.NoCheat; +import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration; /** * @@ -18,16 +19,20 @@ public abstract class Check { private String name; protected NoCheat plugin; - public Check(NoCheat plugin, String name, int permission) { + protected Check(NoCheat plugin, String name, int permission, NoCheatConfiguration config) { this.plugin = plugin; this.permission = permission; this.name = name; + + configure(config); } public boolean skipCheck(Player player) { // Should we check at all? return !active || plugin.hasPermission(player, permission); } + + protected abstract void configure(NoCheatConfiguration config); protected abstract void registerListeners(); @@ -35,7 +40,7 @@ public abstract class Check { return active; } - public void setActive(boolean active) { + protected void setActive(boolean active) { synchronized(this) { if(active && !listenersRegistered) { listenersRegistered = true; @@ -50,4 +55,6 @@ public abstract class Check { public String getName() { return name; } + + } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/ItemdupeCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/ItemdupeCheck.java index b5b092dd..0eb2edca 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/ItemdupeCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/ItemdupeCheck.java @@ -8,14 +8,16 @@ import org.bukkit.event.Event.Priority; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.plugin.PluginManager; +import cc.co.evenprime.bukkit.nocheat.ConfigurationException; import cc.co.evenprime.bukkit.nocheat.NoCheat; +import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration; import cc.co.evenprime.bukkit.nocheat.data.PermissionData; import cc.co.evenprime.bukkit.nocheat.listeners.ItemdupeEntityListener; public class ItemdupeCheck extends Check { - public ItemdupeCheck(NoCheat plugin){ - super(plugin, "itemdupe", PermissionData.PERMISSION_ITEMDUPE); + public ItemdupeCheck(NoCheat plugin, NoCheatConfiguration config){ + super(plugin, "itemdupe", PermissionData.PERMISSION_ITEMDUPE, config); } @@ -28,6 +30,16 @@ public class ItemdupeCheck extends Check { } } + @Override + public void configure(NoCheatConfiguration config) { + + try { + setActive(config.getBooleanValue("active.itemdupe")); + } catch (ConfigurationException e) { + setActive(false); + e.printStackTrace(); + } + } @Override protected void registerListeners() { diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java index c0789ca1..36a1546a 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java @@ -16,11 +16,13 @@ import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.plugin.PluginManager; import org.bukkit.util.Vector; +import cc.co.evenprime.bukkit.nocheat.ConfigurationException; import cc.co.evenprime.bukkit.nocheat.NoCheat; import cc.co.evenprime.bukkit.nocheat.actions.Action; import cc.co.evenprime.bukkit.nocheat.actions.CancelAction; import cc.co.evenprime.bukkit.nocheat.actions.CustomAction; import cc.co.evenprime.bukkit.nocheat.actions.LogAction; +import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration; import cc.co.evenprime.bukkit.nocheat.data.MovingData; import cc.co.evenprime.bukkit.nocheat.data.PermissionData; import cc.co.evenprime.bukkit.nocheat.listeners.MovingEntityListener; @@ -35,8 +37,9 @@ import cc.co.evenprime.bukkit.nocheat.listeners.MovingPlayerMonitor; */ public class MovingCheck extends Check { - public MovingCheck(NoCheat plugin) { - super(plugin, "moving", PermissionData.PERMISSION_MOVING); + public MovingCheck(NoCheat plugin, NoCheatConfiguration config) { + super(plugin, "moving", PermissionData.PERMISSION_MOVING, config); + } // How many move events can a player have in air before he is expected to lose altitude (or land somewhere) @@ -51,21 +54,18 @@ public class MovingCheck extends Check { private final static double stepWidth = 0.6D; private final static double sneakStepWidth = 0.25D; - public int ticksBeforeSummary = 100; + private int ticksBeforeSummary = 100; public long statisticElapsedTimeNano = 0; - public boolean allowFlying = false; - public boolean allowFakeSneak = true; + public boolean allowFlying; + public boolean allowFakeSneak; + + private String logMessage; + private String summaryMessage; // How should moving violations be treated? - public final Action actions[][] = { - { LogAction.loglow, CancelAction.cancel }, - { LogAction.logmed, CancelAction.cancel }, - { LogAction.loghigh, CancelAction.cancel } }; - - public String logMessage = "Moving violation: %1$s from %2$s (%4$.1f, %5$.1f, %6$.1f) to %3$s (%7$.1f, %8$.1f, %9$.1f)"; - public String summaryMessage = "Moving summary of last ~%2$d seconds: %1$s total Violations: (%3$d,%4$d,%5$d)"; + private Action actions[][]; public long statisticTotalEvents = 1; // Prevent accidental division by 0 at some point @@ -259,10 +259,9 @@ public class MovingCheck extends Check { if(violationLevel >= 0) { setupSummaryTask(event.getPlayer(), data); - boolean log = !(data.violationsInARow[violationLevel] > 0); data.violationsInARow[violationLevel]++; - action(event, event.getPlayer(), from, to, actions[violationLevel], log, data); + action(event, event.getPlayer(), from, to, actions[violationLevel], data.violationsInARow[violationLevel], data); } /****** Violation Handling END *****/ @@ -447,30 +446,33 @@ public class MovingCheck extends Check { * @param event * @param action */ - private void action(PlayerMoveEvent event, Player player, Location from, Location to, Action[] actions, boolean loggingAllowed, MovingData data) { + private void action(PlayerMoveEvent event, Player player, Location from, Location to, Action[] actions, int violations, MovingData data) { if(actions == null) return; boolean cancelled = false; - // prepare log message if necessary - String log = null; - - if(loggingAllowed) { - log = String.format(logMessage, player.getName(), from.getWorld().getName(), to.getWorld().getName(), from.getX(), from.getY(), from.getZ(), to.getX(), to.getY(), to.getZ()); - } - + for(Action a : actions) { - if(loggingAllowed && a instanceof LogAction) { - plugin.log(((LogAction)a).level, log); - if(data.highestLogLevel == null) data.highestLogLevel = Level.ALL; - if(data.highestLogLevel.intValue() < ((LogAction)a).level.intValue()) data.highestLogLevel = ((LogAction)a).level; + if(a.firstAfter <= violations) { + if(a.firstAfter == violations || a.repeat) { + if(a instanceof LogAction) { + // prepare log message if necessary + String log = String.format(logMessage, player.getName(), from.getWorld().getName(), to.getWorld().getName(), from.getX(), from.getY(), from.getZ(), to.getX(), to.getY(), to.getZ()); + + plugin.log(((LogAction)a).level, log); + + // Remember the highest log level we encountered to determine what level the summary log message should have + if(data.highestLogLevel == null) data.highestLogLevel = Level.ALL; + if(data.highestLogLevel.intValue() < ((LogAction)a).level.intValue()) data.highestLogLevel = ((LogAction)a).level; + } + else if(!cancelled && a instanceof CancelAction) { + resetPlayer(event, from); + cancelled = true; + } + else if(a instanceof CustomAction) + plugin.handleCustomAction((CustomAction)a, player); + } } - else if(!cancelled && a instanceof CancelAction) { - resetPlayer(event, from); - cancelled = true; - } - else if(a instanceof CustomAction) - plugin.handleCustomAction(a, player); } } @@ -646,6 +648,30 @@ public class MovingCheck extends Check { data.teleportTo = null; } + @Override + public void configure(NoCheatConfiguration config) { + + try { + allowFlying = config.getBooleanValue("moving.allowflying"); + allowFakeSneak = config.getBooleanValue("moving.allowfakesneak"); + + logMessage = config.getStringValue("moving.logmessage"); + summaryMessage = config.getStringValue("moving.summarymessage"); + + actions = new Action[3][]; + + actions[0] = config.getActionValue("moving.action.low"); + actions[1] = config.getActionValue("moving.action.med"); + actions[2] = config.getActionValue("moving.action.high"); + + setActive(config.getBooleanValue("active.moving")); + } catch (ConfigurationException e) { + setActive(false); + e.printStackTrace(); + } + + } + @Override protected void registerListeners() { PluginManager pm = Bukkit.getServer().getPluginManager(); diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java index 3274a8c2..4b4cb321 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java @@ -10,11 +10,13 @@ import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.plugin.PluginManager; +import cc.co.evenprime.bukkit.nocheat.ConfigurationException; import cc.co.evenprime.bukkit.nocheat.NoCheat; import cc.co.evenprime.bukkit.nocheat.actions.Action; import cc.co.evenprime.bukkit.nocheat.actions.CancelAction; import cc.co.evenprime.bukkit.nocheat.actions.CustomAction; import cc.co.evenprime.bukkit.nocheat.actions.LogAction; +import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration; import cc.co.evenprime.bukkit.nocheat.data.PermissionData; import cc.co.evenprime.bukkit.nocheat.data.SpeedhackData; import cc.co.evenprime.bukkit.nocheat.listeners.SpeedhackPlayerListener; @@ -27,22 +29,19 @@ import cc.co.evenprime.bukkit.nocheat.listeners.SpeedhackPlayerListener; */ public class SpeedhackCheck extends Check { - public SpeedhackCheck(NoCheat plugin) { - super(plugin, "speedhack", PermissionData.PERMISSION_SPEEDHACK); + public SpeedhackCheck(NoCheat plugin, NoCheatConfiguration config) { + super(plugin, "speedhack", PermissionData.PERMISSION_SPEEDHACK, config); } private static final int violationsLimit = 2; // Limits for the speedhack check per second - public int limits[] = { 30, 45, 60 }; + private int limits[]; + + private String logMessage; // How should speedhack violations be treated? - public Action actions[][] = { - { LogAction.loglow, CancelAction.cancel }, - { LogAction.logmed, CancelAction.cancel }, - { LogAction.loghigh, CancelAction.cancel } }; - - public String logMessage = "%1$s sent %2$d move events, but only %3$d were allowed. Speedhack?"; + private Action actions[][]; public void check(PlayerMoveEvent event) { @@ -84,16 +83,21 @@ public class SpeedhackCheck extends Check { final int med = (limits[1]+1) / 2; final int high = (limits[2]+1) / 2; - if(data.eventsSinceLastCheck > high) action = actions[2]; - else if(data.eventsSinceLastCheck > med) action = actions[1]; - else if(data.eventsSinceLastCheck > low) action = actions[0]; + int level = -1; + + if(data.eventsSinceLastCheck > high) level = 2; + else if(data.eventsSinceLastCheck > med) level = 1; + else if(data.eventsSinceLastCheck > low) level = 0; else resetData(data, event.getFrom(), ticks); - if(action != null) data.violationsInARow++; + if(level >= 0) { + data.violationsInARowTotal++; + } - if(data.violationsInARow >= violationsLimit) { - action(action, event, data); + if(data.violationsInARowTotal >= violationsLimit) { + data.violationsInARow[level]++; + action(action, event, data.violationsInARow[level], data); } // Reset value for next check @@ -110,25 +114,34 @@ public class SpeedhackCheck extends Check { } private static void resetData(SpeedhackData data, Location l, int ticks) { - data.violationsInARow = 0; + data.violationsInARow[0] = 0; + data.violationsInARow[1] = 0; + data.violationsInARow[2] = 0; + data.violationsInARowTotal = 0; data.eventsSinceLastCheck = 0; data.setBackPoint = l; data.lastCheckTicks = ticks; } - private void action(Action actions[], PlayerMoveEvent event, SpeedhackData data) { + private void action(Action actions[], PlayerMoveEvent event, int violations, SpeedhackData data) { if(actions == null) return; - String log = String.format(logMessage, event.getPlayer().getName(), data.eventsSinceLastCheck*2, limits[0]); - for(Action a : actions) { - if(a instanceof LogAction) - plugin.log(((LogAction)a).level, log); - else if(a instanceof CancelAction) - resetPlayer(event, data); - else if(a instanceof CustomAction) - plugin.handleCustomAction(a, event.getPlayer()); + if(a.firstAfter <= violations) { + if(a.firstAfter == violations || a.repeat) { + if(a instanceof LogAction) { + String log = String.format(logMessage, event.getPlayer().getName(), data.eventsSinceLastCheck*2, limits[0]); + plugin.log(((LogAction)a).level, log); + } + else if(a instanceof CancelAction) { + resetPlayer(event, data); + } + else if(a instanceof CustomAction) { + plugin.handleCustomAction((CustomAction)a, event.getPlayer()); + } + } + } } } @@ -145,6 +158,34 @@ public class SpeedhackCheck extends Check { } } + @Override + public void configure(NoCheatConfiguration config) { + + try { + + limits = new int[3]; + + limits[0] = config.getIntegerValue("speedhack.limits.low"); + limits[1] = config.getIntegerValue("speedhack.limits.med"); + limits[2] = config.getIntegerValue("speedhack.limits.high"); + + logMessage = config.getStringValue("speedhack.logmessage"); + + actions = new Action[3][]; + + actions[0] = config.getActionValue("speedhack.action.low"); + actions[1] = config.getActionValue("speedhack.action.med"); + actions[2] = config.getActionValue("speedhack.action.high"); + + setActive(config.getBooleanValue("active.speedhack")); + } catch (ConfigurationException e) { + setActive(false); + e.printStackTrace(); + } + } + + + @Override protected void registerListeners() { PluginManager pm = Bukkit.getServer().getPluginManager(); diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/BooleanOption.java b/src/cc/co/evenprime/bukkit/nocheat/config/BooleanOption.java new file mode 100644 index 00000000..5d709c61 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/BooleanOption.java @@ -0,0 +1,31 @@ +package cc.co.evenprime.bukkit.nocheat.config; + + +public class BooleanOption extends ChildOption { + + /** + * + */ + private static final long serialVersionUID = 2258827414736580449L; + + private boolean value; + + public BooleanOption(String name, boolean initialValue) { + + super(name); + this.value = initialValue; + } + + public void setValue(boolean value) { + this.value = value; + } + + @Override + public String getValue() { + return Boolean.toString(value); + } + + public boolean getBooleanValue() { + return value; + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/ChildOption.java b/src/cc/co/evenprime/bukkit/nocheat/config/ChildOption.java new file mode 100644 index 00000000..9d04c007 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/ChildOption.java @@ -0,0 +1,22 @@ +package cc.co.evenprime.bukkit.nocheat.config; + +public abstract class ChildOption extends Option { + + /** + * + */ + private static final long serialVersionUID = -4648294833934457776L; + + public ChildOption(String identifier) { + + super(identifier); + } + + + public abstract String getValue(); + + @Override + public String toYAMLString(String prefix) { + return prefix + getIdentifier() + ": \"" + getValue() + "\"\r\n"; + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/CustomActionOption.java b/src/cc/co/evenprime/bukkit/nocheat/config/CustomActionOption.java new file mode 100644 index 00000000..0f4afdc9 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/CustomActionOption.java @@ -0,0 +1,86 @@ +package cc.co.evenprime.bukkit.nocheat.config; + +import cc.co.evenprime.bukkit.nocheat.actions.CustomAction; + +public class CustomActionOption extends ChildOption { + + private int firstAfter; + private boolean repeat; + private String command; + + + public CustomActionOption(String identifier, String command) { + + super(identifier); + + this.parseCommand(command); + } + + private void parseCommand(String com) { + + if(com.matches("\\[[0-9]*,[a-z]*\\] .*")) { + String s[] = com.split(" ", 2); + String s2[] = s[0].replace("[", "").replace("]", "").split(","); + firstAfter = Integer.parseInt(s2[0]); + repeat = Boolean.parseBoolean(s2[1]); + command = s[1]; + } + else if(com.matches("\\[[0-9]*\\] .*")) { + String s[] = com.split(" ", 2); + firstAfter = Integer.parseInt(s[0].replace("[", "").replace("]", "")); + repeat = true; + command = s[1]; + } + else + { + firstAfter = 1; + repeat = true; + command = com; + } + } + + @Override + public String getValue() { + if(firstAfter <= 1 && repeat) { + return command; + } + else if(repeat) { + return "["+firstAfter+"] "+ command; + } + else { + return "["+firstAfter+","+repeat+"] "+ command; + } + } + + + public CustomAction getCustomActionValue() { + return new CustomAction(firstAfter, repeat, command); + } + + public String getCommandValue() { + return command; + } + + public void setCommandValue(String command) { + this.command = command; + } + + public void setRepeatValue(boolean value) { + this.repeat = value; + + } + + public boolean getRepeatValue() { + return repeat; + } + + public int getFirstAfterValue() { + return firstAfter; + } + + public void setFirsttAfterValue(int value) { + this.firstAfter = value; + + } + +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/IntegerOption.java b/src/cc/co/evenprime/bukkit/nocheat/config/IntegerOption.java new file mode 100644 index 00000000..27f88eeb --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/IntegerOption.java @@ -0,0 +1,33 @@ +package cc.co.evenprime.bukkit.nocheat.config; + + +public class IntegerOption extends TextFieldOption { + + /** + * + */ + private static final long serialVersionUID = 2258827414736580449L; + + public IntegerOption(String name, int initialValue) { + + super(name, String.valueOf(initialValue), 5); + } + + @Override + public boolean isValid(String value) { + + if(!super.isValid(value)) return false; + + try { + Integer.parseInt(value); + return true; + } + catch(Exception e) { + return false; + } + } + + public int getIntegerValue() { + return Integer.parseInt(this.getValue()); + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/LevelOption.java b/src/cc/co/evenprime/bukkit/nocheat/config/LevelOption.java new file mode 100644 index 00000000..771ba0a7 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/LevelOption.java @@ -0,0 +1,82 @@ +package cc.co.evenprime.bukkit.nocheat.config; + +import java.util.logging.Level; + + +public class LevelOption extends ChildOption { + + /** + * + */ + private static final long serialVersionUID = -1609308017422576285L; + + private LogLevel option; + + public enum LogLevel { + + + OFF("off", "never", Level.OFF), + LOW("low", "all messages", Level.INFO), + MED("med", "important messages", Level.WARNING), + HIGH("high", "very important messages", Level.SEVERE); + + private final String value; + private String description; + private Level level; + + private LogLevel(String value, String description, Level level) { + this.value = value; + this.description = description; + this.level = level; + } + + public String asString() { return this.value; } + + public static LogLevel getLogLevelFromString(String s) { + if(s == null) return OFF; + if("off".equals(s)) + return OFF; + else if("low".equals(s)) + return LOW; + else if("med".equals(s)) + return MED; + else if("high".equals(s)) + return HIGH; + else + return OFF; + } + + + public String toString() { + return this.name() + ": " + description; + } + + public Level getLevel() { + return level; + } + } + + public LevelOption(String identifier, LogLevel initialValue) { + + super(identifier); + this.option = initialValue; + } + + + @Override + public String getValue() { + return option.asString(); + } + + public void setValue(LogLevel value) { + this.option = value; + } + + public LogLevel getOptionValue() { + return this.option; + } + + public Level getLevelValue() { + return this.option.getLevel(); + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/LongStringOption.java b/src/cc/co/evenprime/bukkit/nocheat/config/LongStringOption.java new file mode 100644 index 00000000..4254ca75 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/LongStringOption.java @@ -0,0 +1,13 @@ +package cc.co.evenprime.bukkit.nocheat.config; + +public class LongStringOption extends TextFieldOption { + + /** + * + */ + private static final long serialVersionUID = 2258827414736580449L; + + public LongStringOption(String name, String initialValue) { + super(name, initialValue, 60); + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/MediumStringOption.java b/src/cc/co/evenprime/bukkit/nocheat/config/MediumStringOption.java new file mode 100644 index 00000000..6c57029f --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/MediumStringOption.java @@ -0,0 +1,13 @@ +package cc.co.evenprime.bukkit.nocheat.config; + +public class MediumStringOption extends TextFieldOption { + + /** + * + */ + private static final long serialVersionUID = 2258827414736580449L; + + public MediumStringOption(String name, String initialValue) { + super(name, initialValue, 30); + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java b/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java new file mode 100644 index 00000000..29f6cd32 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/NoCheatConfiguration.java @@ -0,0 +1,409 @@ +package cc.co.evenprime.bukkit.nocheat.config; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.FileHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +import cc.co.evenprime.bukkit.nocheat.ConfigurationException; +import cc.co.evenprime.bukkit.nocheat.actions.Action; +import cc.co.evenprime.bukkit.nocheat.actions.CancelAction; +import cc.co.evenprime.bukkit.nocheat.actions.LogAction; +import cc.co.evenprime.bukkit.nocheat.config.LevelOption.LogLevel; +import cc.co.evenprime.bukkit.nocheat.yaml.SimpleYaml; + +/** + * Central location for everything that's described in the configuration file + * + * @author Evenprime + * + */ +public class NoCheatConfiguration { + + + public final static String configFile = "plugins/NoCheat/nocheat.yml"; + + private ParentOption root; + + private Map actionMap = new HashMap(); + + private Map yamlContent = new HashMap(); + + // Our personal logger + private final static String loggerName = "cc.co.evenprime.nocheat"; + public final Logger logger = Logger.getLogger(loggerName); + + // Our log output to a file + private FileHandler fh = null; + + public NoCheatConfiguration(File configurationFile) { + + // Setup the configuration tree + config(configurationFile); + } + + /** + * Read the configuration file and assign either standard values or whatever is declared in the file + * @param configurationFile + */ + public void config(File configurationFile) { + + + try { + yamlContent = (Map) SimpleYaml.read(configurationFile); + } catch (Exception e) { + yamlContent = new HashMap(); + } + + + root = new ParentOption("", false); + + + /*** LOGGING section ***/ + { + ParentOption loggingNode = new ParentOption("logging", false); + root.add(loggingNode); + + loggingNode.add(new MediumStringOption("filename", + SimpleYaml.getString("logging.filename", "plugins/NoCheat/nocheat.log", yamlContent))); + + loggingNode.add(new LevelOption("logtofile", + LogLevel.getLogLevelFromString(SimpleYaml.getString("logging.logtofile", LogLevel.LOW.asString(), yamlContent)))); + loggingNode.add(new LevelOption("logtoconsole", + LogLevel.getLogLevelFromString(SimpleYaml.getString("logging.logtoconsole", LogLevel.HIGH.asString(), yamlContent)))); + loggingNode.add(new LevelOption("logtochat", + LogLevel.getLogLevelFromString(SimpleYaml.getString("logging.logtochat", LogLevel.MED.asString(), yamlContent)))); + loggingNode.add(new LevelOption("logtoirc", + LogLevel.getLogLevelFromString(SimpleYaml.getString("logging.logtoirc", LogLevel.MED.asString(), yamlContent)))); + + loggingNode.add(new ShortStringOption("logtoirctag", + SimpleYaml.getString("logging.logtoirctag", "nocheat", yamlContent))); + } + + /*** ACTIVE section ***/ + { + ParentOption activeNode = new ParentOption("active", false); + root.add(activeNode); + + activeNode.add(new BooleanOption("speedhack", + SimpleYaml.getBoolean("active.speedhack", true, yamlContent))); + activeNode.add(new BooleanOption("moving", + SimpleYaml.getBoolean("active.moving", true, yamlContent))); + activeNode.add(new BooleanOption("airbuild", + SimpleYaml.getBoolean("active.airbuild", false, yamlContent))); + activeNode.add(new BooleanOption("bedteleport", + SimpleYaml.getBoolean("active.bedteleport", true, yamlContent))); + activeNode.add(new BooleanOption("itemdupe", + SimpleYaml.getBoolean("active.itemdupe", true, yamlContent))); + activeNode.add(new BooleanOption("bogusitems", + SimpleYaml.getBoolean("active.bogusitems", false, yamlContent))); + } + + /*** SPEEDHACK section ***/ + { + ParentOption speedhackNode = new ParentOption("speedhack", false); + root.add(speedhackNode); + + speedhackNode.add(new LongStringOption("logmessage", + SimpleYaml.getString("logging.filename", "%1$s sent %2$d move events, but only %3$d were allowed. Speedhack?", yamlContent))); + + /*** SPEEDHACK LIMITS section ***/ + { + ParentOption speedhackLimitsNode = new ParentOption("limits", false); + speedhackNode.add(speedhackLimitsNode); + + speedhackLimitsNode.add(new IntegerOption("low", + SimpleYaml.getInt("speedhack.limits.low", 30, yamlContent))); + speedhackLimitsNode.add(new IntegerOption("med", + SimpleYaml.getInt("speedhack.limits.med", 45, yamlContent))); + speedhackLimitsNode.add(new IntegerOption("high", + SimpleYaml.getInt("speedhack.limits.high", 60, yamlContent))); + } + + /*** SPEEDHACK ACTIONS section ***/ + { + ParentOption speedhackActionNode = new ParentOption("action", false); + speedhackNode.add(speedhackActionNode); + + speedhackActionNode.add(new MediumStringOption("low", + SimpleYaml.getString("speedhack.action.low", "loglow cancel", yamlContent))); + speedhackActionNode.add(new MediumStringOption("med", + SimpleYaml.getString("speedhack.action.med", "logmed cancel", yamlContent))); + speedhackActionNode.add(new MediumStringOption("high", + SimpleYaml.getString("speedhack.action.high", "loghigh cancel", yamlContent))); + } + } + + /*** MOVING section ***/ + { + ParentOption movingNode = new ParentOption("moving", false); + root.add(movingNode); + + movingNode.add(new LongStringOption("logmessage", + SimpleYaml.getString("moving.logmessage", "Moving violation: %1$s from %2$s (%4$.1f, %5$.1f, %6$.1f) to %3$s (%7$.1f, %8$.1f, %9$.1f)", yamlContent))); + movingNode.add(new LongStringOption("summarymessage", + SimpleYaml.getString("moving.summarymessage", "Moving summary of last ~%2$d seconds: %1$s total Violations: (%3$d,%4$d,%5$d)", yamlContent))); + movingNode.add(new BooleanOption("allowflying", + SimpleYaml.getBoolean("moving.allowflying", false, yamlContent))); + movingNode.add(new BooleanOption("allowfakesneak", + SimpleYaml.getBoolean("moving.allowfakesneak", true, yamlContent))); + + /*** MOVING ACTION section ***/ + { + ParentOption movingActionNode = new ParentOption("action", false); + movingNode.add(movingActionNode); + + movingActionNode.add(new MediumStringOption("low", + SimpleYaml.getString("moving.action.low", "loglow cancel", yamlContent))); + movingActionNode.add(new MediumStringOption("med", + SimpleYaml.getString("moving.action.med", "logmed cancel", yamlContent))); + movingActionNode.add(new MediumStringOption("high", + SimpleYaml.getString("moving.action.high", "loghigh cancel", yamlContent))); + } + } + + /*** AIRBUILD section ***/ + { + ParentOption airbuildNode = new ParentOption("airbuild", false); + root.add(airbuildNode); + + /*** AIRBUILD LIMITS section ***/ + { + ParentOption airbuildLimitsNode = new ParentOption("limits", false); + airbuildNode.add(airbuildLimitsNode); + + airbuildLimitsNode.add(new IntegerOption("low", + SimpleYaml.getInt("airbuild.limits.low", 1, yamlContent))); + airbuildLimitsNode.add(new IntegerOption("med", + SimpleYaml.getInt("airbuild.limits.med", 3, yamlContent))); + airbuildLimitsNode.add(new IntegerOption("high", + SimpleYaml.getInt("airbuild.limits.high", 10, yamlContent))); + } + + /*** AIRBUILD ACTION section ***/ + { + ParentOption airbuildActionNode = new ParentOption("action", false); + airbuildNode.add(airbuildActionNode); + + airbuildActionNode.add(new MediumStringOption("low", + SimpleYaml.getString("airbuild.action.low", "loglow cancel", yamlContent))); + airbuildActionNode.add(new MediumStringOption("med", + SimpleYaml.getString("airbuild.action.med", "logmed cancel", yamlContent))); + airbuildActionNode.add(new MediumStringOption("high", + SimpleYaml.getString("airbuild.action.high", "loghigh cancel", yamlContent))); + } + } + + /*** BEDTELEPORT section ***/ + { + ParentOption bedteleportNode = new ParentOption("bedteleport", false); + root.add(bedteleportNode); + } + + /*** ITEMDUPE section ***/ + { + ParentOption itemdupeNode = new ParentOption("itemdupe", false); + root.add(itemdupeNode); + } + + /*** BOGUSITEMS section ***/ + { + ParentOption bogusitemsNode = new ParentOption("bogusitems", false); + root.add(bogusitemsNode); + } + + /*** CUSTOMACTIONS section ***/ + { + ParentOption customActionsNode = new ParentOption("customactions", true); + root.add(customActionsNode); + + Set customs = SimpleYaml.getKeys("customactions", yamlContent); + + for(String s : customs) { + + CustomActionOption o = new CustomActionOption(s, SimpleYaml.getString("customactions."+s, "unknown", yamlContent)); + + customActionsNode.add(o); + actionMap.put(s, o.getCustomActionValue()); + } + } + + if(!configurationFile.exists()) { + writeConfigFile(configurationFile, this); + } + } + + public void setupFileLogger() { + + logger.setLevel(Level.INFO); + logger.setUseParentHandlers(false); + + if(fh == null) { + try { + fh = new FileHandler(getStringValue("logging.filename"), true); + fh.setLevel(getLogLevelValue("logging.logtofile")); + fh.setFormatter(Logger.getLogger("Minecraft").getHandlers()[0].getFormatter()); + logger.addHandler(fh); + + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public void cleanup() { + + if(fh != null) { + try { + logger.removeHandler(fh); + fh.flush(); + fh.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public Action[] stringToActions(String string) { + + List as = new LinkedList(); + String[] parts = string.split(" "); + + for(String s : parts) { + if(s.equals("loglow")) + as.add(LogAction.loglow); + else if(s.equals("logmed")) + as.add(LogAction.logmed); + else if(s.equals("loghigh")) + as.add(LogAction.loghigh); + else if(s.equals("cancel")) + as.add(CancelAction.cancel); + else if(actionMap.get(s) != null) + as.add(actionMap.get(s)); + else + { + System.out.println("NC: Couldn't parse custom action '" + s + "'"); + } + } + + return as.toArray(new Action[as.size()]); + } + + /** + * Write configuration file to specific filename + * @param f + */ + public static void writeConfigFile(File f, NoCheatConfiguration configuration) { + try { + if(f.getParentFile() != null) + f.getParentFile().mkdirs(); + + f.createNewFile(); + BufferedWriter w = new BufferedWriter(new FileWriter(f)); + + w.write(configuration.getRoot().toYAMLString("")); + + w.flush(); w.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public Action[] getActionValue(String optionName) throws ConfigurationException { + return stringToActions(getStringOption(optionName).getValue()); + } + + + public int getIntegerValue(String optionName) throws ConfigurationException { + return getIntegerOption(optionName).getIntegerValue(); + } + public IntegerOption getIntegerOption(String optionName) throws ConfigurationException { + + Option o = getOption(optionName) ; + if(o instanceof IntegerOption) { + return (IntegerOption)o; + } + + throw new ConfigurationException("Config Node " + optionName + " is not an integer"); + } + + public String getStringValue(String optionName) throws ConfigurationException { + return getStringOption(optionName).getValue(); + } + public TextFieldOption getStringOption(String optionName) throws ConfigurationException { + + Option o = getOption(optionName); + if(o instanceof TextFieldOption) { + return (TextFieldOption)o; + } + + throw new ConfigurationException("Config Node " + optionName + " is not a string"); + } + + public Level getLogLevelValue(String optionName) throws ConfigurationException { + return getLogLevelOption(optionName).getLevelValue(); + } + public LevelOption getLogLevelOption(String optionName) throws ConfigurationException { + + Option o = getOption(optionName); + if(o instanceof LevelOption) { + return (LevelOption)o; + } + + throw new ConfigurationException("Config Node " + optionName + " is not a loglevel"); + } + + + public boolean getBooleanValue(String optionName) throws ConfigurationException { + return getBooleanOption(optionName).getBooleanValue(); + } + public BooleanOption getBooleanOption(String optionName) throws ConfigurationException { + + Option o = getOption(optionName); + if(o instanceof BooleanOption) { + return (BooleanOption)o; + } + + throw new ConfigurationException("Config Node " + optionName + " is not a boolean"); + } + + + private Option getOption(String optionName) throws ConfigurationException { + LinkedList l = new LinkedList(); + for(String s : optionName.split("\\.")) { + l.addLast(s); + } + return getOption(root, l); + } + + private Option getOption(Option parent, LinkedList names) throws ConfigurationException { + + if(names.size() == 0) { + return parent; + } + else if(parent instanceof ParentOption) { + for(Option o2 : ((ParentOption)parent).getChildOptions()) { + if(o2.getIdentifier().equals(names.getFirst())) { + + names.removeFirst(); + return getOption(o2, names); + } + } + } + + throw new ConfigurationException("Config Node doesn't exist"); + } + + public ParentOption getRoot() { + return root; + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/Option.java b/src/cc/co/evenprime/bukkit/nocheat/config/Option.java new file mode 100644 index 00000000..219411c9 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/Option.java @@ -0,0 +1,19 @@ +package cc.co.evenprime.bukkit.nocheat.config; + + +public abstract class Option { + + private final String identifier; + + public Option(String identifier) { + this.identifier = identifier; + } + + public String getIdentifier() { + return identifier; + } + + public String toYAMLString(String prefix) { + return prefix + "\r\n"; + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/ParentOption.java b/src/cc/co/evenprime/bukkit/nocheat/config/ParentOption.java new file mode 100644 index 00000000..c4442419 --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/config/ParentOption.java @@ -0,0 +1,62 @@ +package cc.co.evenprime.bukkit.nocheat.config; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; + + +public class ParentOption extends Option { + + /** + * + */ + private static final long serialVersionUID = 3162246550749560727L; + + private LinkedList