NoCheat 2.0 initial Commit

This commit is contained in:
Evenprime 2011-08-31 15:26:07 +02:00
parent 6d0da77e7d
commit 92620c4fd4
110 changed files with 4985 additions and 4160 deletions

View File

@ -1,3 +1,2 @@
Manifest-Version: 1.0
Main-Class: cc.co.evenprime.bukkit.nocheat.Main
Class-Path: snakeyaml.jar
Main-Class: cc.co.evenprime.bukkit.nocheat.wizard.Wizard

View File

@ -3,64 +3,69 @@ name: NoCheat
author: Evenprime
main: cc.co.evenprime.bukkit.nocheat.NoCheat
version: 1.14e
softdepend: [ Permissions, CraftIRC ]
commands:
nocheat:
description: Provides information about the current status of the NoCheat plugin
usage: |
/<command>
Example: /<command> | Displays version, enabled checks and bugfixes
Example: /<command> -p | Get your permissions, * = check disabled globally
Example: /<command> -p [player] | Get permissions of the player, * = check disabled globally
version: 2.00
permissions:
nocheat.*:
description: Allow the player to do everything (and get log messages)
description: Allow a player to bypass all checks and give him all admin permissions
children:
nocheat.all: true
nocheat.notify: true
nocheat.all:
description: Allow the player to do everything (except for getting log messages)
nocheat.checks.*: true
nocheat.admin.*: true
nocheat.checks.*:
description: Allow the player to bypass all checks
children:
nocheat.moving: true
nocheat.speedhack: true
nocheat.airbuild: true
nocheat.bogusitems: true
nocheat.nuke: true
nocheat.flying: true
nocheat.fakesneak: true
nocheat.fastswim: true
nocheat.infinitedurability: true
nocheat.moving:
description: Allow to player to move/fly without getting checked at all
nocheat.checks.moving.*: true
nocheat.checks.blockbreak.*: true
nocheat.checks.moving.*:
description: Allow the player to bypass all moving checks
children:
nocheat.checks.moving.flying: true
nocheat.checks.moving.running: true
nocheat.checks.moving.swimming: true
nocheat.checks.moving.sneaking: true
nocheat.checks.moving.noclip: true
nocheat.checks.moving.morepackets: true
nocheat.checks.blockbreak.*:
description: Allow the player to bypass all blockbreak checks
children:
nocheat.checks.blockbreak.reach: true
nocheat.checks.blockbreak.direction: true
nocheat.checks.moving.flying:
description: Allow a player to move free through the air (implicitly deactivates the "running" check)
default: op
nocheat.speedhack:
description: Don't observe the number of move events sent by the player
nocheat.checks.moving.running:
description: Allow a player to move free, only limited by the flying check, if active (implicitly deactivates the "swimming" and "sneaking" check)
default: op
nocheat.airbuild:
description: Allow placing blocks against air/in midair
nocheat.checks.moving.swimming:
description: Allow a player to move at normal running speed through water
default: op
nocheat.bogusitems:
description: Allow the use of items with invalid values e.g. negative stacksize
nocheat.checks.moving.sneaking:
description: Allow a player to move at normal running speed while sneaking
default: op
nocheat.nuke:
description: Allow breaking of blocks that are not in the field of view of the player
nocheat.checks.moving.noclip:
description: Allow a player to walk through walls
default: op
nocheat.notify:
description: Receive log messages in chat
nocheat.checks.moving.morepackets:
description: Allow a player to send more move-event-packets than normal
default: op
nocheat.flying:
description: Allow the player to fly at normal walking speed
nocheat.checks.blockbreak.reach:
description: Allow a player to break blocks at maximum range (about 6-7 blocks)
default: op
nocheat.fakesneak:
description: Allow the player to sneak at normal walking speed
default: op
nocheat.fastswim:
description: Allow the player to swim at normal walking speed
default: op
nocheat.infinitedurability:
description: Allow the player to use a known infinite item durability hack
nocheat.checks.blockbreak.direction:
description: Allow a player to break blocks that are not in front of them
default: op
nocheat.admin.*:
description: Give a player all admin rights
children:
nocheat.admin.chatlog: true
nocheat.admin.chatlog:
description: Show log messages in the players chat
default: op

View File

@ -1,13 +0,0 @@
package cc.co.evenprime.bukkit.nocheat;
public class ConfigurationException extends Exception {
/**
*
*/
private static final long serialVersionUID = -457634587532590464L;
public ConfigurationException(String message) {
super(message);
}
}

View File

@ -1,104 +0,0 @@
package cc.co.evenprime.bukkit.nocheat;
import java.util.Set;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
public class CustomCommandSender implements CommandSender {
private final Server server;
public CustomCommandSender(Server server) {
this.server = server;
}
@Override
public boolean isPermissionSet(String name) {
// Just pretend that we have a permission, no matter which one
return true;
}
@Override
public boolean isPermissionSet(Permission perm) {
// Just pretend that we have a permission, no matter which one
return true;
}
@Override
public boolean hasPermission(String name) {
// Just pretend that we have a permission, no matter which one
return true;
}
@Override
public boolean hasPermission(Permission perm) {
// Just pretend that we have a permission, no matter which one
return true;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
// Whatever it is, I don't care
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin) {
// Whatever it is, I don't care
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
// Whatever it is, I don't care
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
// Whatever it is, I don't care
return null;
}
@Override
public void removeAttachment(PermissionAttachment attachment) {
// Whatever it is, I don't care
}
@Override
public void recalculatePermissions() {
// Nothing to calculate
}
@Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
// Nothing
return null;
}
@Override
public void setOp(boolean value) {
// Nothing
}
@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;
}
@Override
public Server getServer() {
return server;
}
}

View File

@ -1,180 +0,0 @@
package cc.co.evenprime.bukkit.nocheat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.data.AirbuildData;
import cc.co.evenprime.bukkit.nocheat.data.InfinitedurabilityData;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
import cc.co.evenprime.bukkit.nocheat.data.NoCheatData;
import cc.co.evenprime.bukkit.nocheat.data.NukeData;
import cc.co.evenprime.bukkit.nocheat.data.PermissionData;
import cc.co.evenprime.bukkit.nocheat.data.SpeedhackData;
public class DataManager {
// Store data between Events
private final Map<Player, NoCheatData> playerData = new HashMap<Player, NoCheatData>();
public DataManager() {}
/**
* Go through the playerData HashMap and remove players that are no longer
* online
* from the map. This should be called in long, regular intervals (e.g.
* every 10 minutes)
* to keep the memory footprint of the plugin low
*/
public void cleanPlayerDataCollection() {
synchronized(playerData) {
Iterator<Map.Entry<Player, NoCheatData>> it = playerData.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<Player, NoCheatData> pairs = (Map.Entry<Player, NoCheatData>) it.next();
if(!pairs.getKey().isOnline()) {
// Cancel all referenced tasks before removing the entry
cancelTasks(pairs.getValue());
it.remove();
}
}
}
}
/**
* Main access to data that needs to be stored between different events.
* Always returns a NoCheatData object, because if there isn't one
* for the specified player, one will be created.
*
* @param p
* @return
*/
private NoCheatData getPlayerData(final Player p) {
NoCheatData data = playerData.get(p);
if(data == null) {
synchronized(playerData) {
// If we have no data for the player, create some
data = new NoCheatData();
playerData.put(p, data);
}
}
return data;
}
public AirbuildData getAirbuildData(Player p) {
NoCheatData data = getPlayerData(p);
if(data.airbuild == null) {
data.airbuild = new AirbuildData();
}
return data.airbuild;
}
public MovingData getMovingData(final Player p) {
final NoCheatData data = getPlayerData(p);
if(data.moving == null) {
data.moving = new MovingData();
}
return data.moving;
}
public NukeData getNukeData(Player p) {
NoCheatData data = getPlayerData(p);
if(data.nuke == null) {
data.nuke = new NukeData();
}
return data.nuke;
}
public PermissionData getPermissionData(Player p) {
NoCheatData data = getPlayerData(p);
if(data.permission == null) {
data.permission = new PermissionData();
}
return data.permission;
}
public SpeedhackData getSpeedhackData(Player p) {
NoCheatData data = getPlayerData(p);
if(data.speedhack == null) {
data.speedhack = new SpeedhackData();
}
return data.speedhack;
}
public InfinitedurabilityData getInfiniteData(Player p) {
NoCheatData data = getPlayerData(p);
if(data.infinite == null) {
data.infinite = new InfinitedurabilityData();
}
return data.infinite;
}
/**
* Go through the playerData HashMap and remove players that are no longer
* online
* from the map. This should be called in long, regular intervals (e.g.
* every 10 minutes)
* to keep the memory footprint of the plugin low
*/
public void cancelPlayerDataTasks() {
synchronized(playerData) {
Iterator<Map.Entry<Player, NoCheatData>> it = playerData.entrySet().iterator();
while(it.hasNext()) {
cancelTasks(it.next().getValue());
}
}
}
private void cancelTasks(NoCheatData data) {
AirbuildData d = data.airbuild;
if(d != null) {
int id = d.summaryTask;
if(id != -1) {
Bukkit.getServer().getScheduler().cancelTask(id);
} else {
// To prevent accidentially creating a new one while cleaning up
d.summaryTask = 1;
}
}
MovingData d2 = data.moving;
if(d2 != null) {
int id = d2.summaryTask;
if(id != -1) {
Bukkit.getServer().getScheduler().cancelTask(id);
} else {
// To prevent accidentially creating a new one while cleaning up
d2.summaryTask = 1;
}
}
}
}

View File

@ -0,0 +1,274 @@
package cc.co.evenprime.bukkit.nocheat;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import cc.co.evenprime.bukkit.nocheat.config.tree.ActionListOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.BooleanOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationTree;
import cc.co.evenprime.bukkit.nocheat.config.tree.IntegerOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.LogLevelOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.MediumStringOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ParentOption;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
/**
* The place where the structure of the configuration tree is defined, the
* default settings are defined, the default files are defined.
*
* @author Evenprime
*
*/
public class DefaultConfiguration {
/**
* Create a full default options tree
*
* @return
*/
public static ConfigurationTree buildDefaultConfigurationTree() {
ConfigurationTree root = new ConfigurationTree();
/*** LOGGING section ***/
{
ParentOption loggingNode = new ParentOption("logging");
root.add(loggingNode);
loggingNode.add(new BooleanOption("active", true, true));
loggingNode.add(new MediumStringOption("filename", "plugins/NoCheat/nocheat.log"));
loggingNode.add(new LogLevelOption("filelevel", LogLevel.LOW));
loggingNode.add(new LogLevelOption("consolelevel", LogLevel.HIGH));
loggingNode.add(new LogLevelOption("chatlevel", LogLevel.MED));
}
/*** MOVING ***/
{
ParentOption movingNode = new ParentOption("moving");
root.add(movingNode);
movingNode.add(new BooleanOption("check", true, true));
/**** MOVING.FLYING ****/
{
ParentOption flyingNode = new ParentOption("flying");
movingNode.add(flyingNode);
flyingNode.add(new BooleanOption("check", true, true));
flyingNode.add(new IntegerOption("speedlimitvertical", 100));
flyingNode.add(new IntegerOption("speedlimithorizontal", 22));
ActionListOption actions = new ActionListOption("actions");
flyingNode.add(actions);
actions.add(0, "moveLogLowShort moveCancel");
actions.add(100, "moveLogMedShort moveCancel");
actions.add(400, "moveLogHighShort moveCancel");
}
/**** MOVING.RUNNING ****/
{
ParentOption runningNode = new ParentOption("running");
movingNode.add(runningNode);
runningNode.add(new BooleanOption("check", true, true));
runningNode.add(new IntegerOption("speedlimit", 22));
/**** MOVING.RUNNING.SWIMMING ****/
{
ParentOption swimmingNode = new ParentOption("swimming");
runningNode.add(swimmingNode);
swimmingNode.add(new BooleanOption("check", true, true));
swimmingNode.add(new IntegerOption("speedlimit", 18));
}
/**** MOVING.RUNNING.SNEAKING ****/
{
ParentOption sneakingNode = new ParentOption("sneaking");
runningNode.add(sneakingNode);
sneakingNode.add(new BooleanOption("check", true, true));
sneakingNode.add(new IntegerOption("speedlimit", 14));
}
ActionListOption actions = new ActionListOption("actions");
runningNode.add(actions);
actions.add(0, "moveLogLowShort moveCancel");
actions.add(100, "moveLogMedShort moveCancel");
actions.add(400, "moveLogHighShort moveCancel");
}
/**** MOVING.MOREPACKETS ****/
{
ParentOption morePacketsNode = new ParentOption("morepackets");
movingNode.add(morePacketsNode);
morePacketsNode.add(new BooleanOption("check", true, true));
ActionListOption actions = new ActionListOption("actions");
morePacketsNode.add(actions);
actions.add(0, "morepacketsLow moveCancel");
actions.add(15, "morepacketsMed moveCancel");
actions.add(30, "morepacketsHigh moveCancel");
}
/**** MOVING.NOCLIP ****/
{
ParentOption noclipNode = new ParentOption("noclip");
movingNode.add(noclipNode);
noclipNode.add(new BooleanOption("check", true, true));
ActionListOption actions = new ActionListOption("actions");
noclipNode.add(actions);
actions.add(1, "noclipLog moveCancel");
}
}
/****** BLOCKBREAK ******/
{
ParentOption interactNode = new ParentOption("blockbreak");
root.add(interactNode);
interactNode.add(new BooleanOption("check", true, true));
/**** BLOCKBREAK.REACH ****/
{
ParentOption reachNode = new ParentOption("reach");
interactNode.add(reachNode);
reachNode.add(new BooleanOption("check", true, true));
reachNode.add(new IntegerOption("reachlimit", 485));
ActionListOption actions = new ActionListOption("actions");
reachNode.add(actions);
actions.add(0, "reachLog blockbreakCancel");
}
/**** BLOCKBREAK.DIRECTION ****/
{
ParentOption directionNode = new ParentOption("direction");
interactNode.add(directionNode);
directionNode.add(new BooleanOption("check", true, true));
ActionListOption actions = new ActionListOption("actions");
directionNode.add(actions);
actions.add(0, "directionLog blockbreakCancel");
}
}
return root;
}
public static void writeActionFile(File file) {
BufferedWriter w;
try {
if(!file.exists())
file.createNewFile();
w = new BufferedWriter(new FileWriter(file));
w(w, "# This file contains the definitions of the default actions of NoCheat.");
w(w, "# DO NOT EDIT THIS FILE DIRECTLY. If you want to change any of these, copy");
w(w, "# them to your \"actions.txt\" file and modify them there. If an action with");
w(w, "# the same name exists here and in your file, yours will be used.");
w(w, "");
w.flush();
w.close();
} catch(IOException e) {
e.printStackTrace();
}
}
public static void writeDefaultActionFile(File file) {
BufferedWriter w;
try {
if(!file.exists())
file.createNewFile();
w = new BufferedWriter(new FileWriter(file));
w(w, "# This file contains the definitions of the default actions of NoCheat.");
w(w, "# DO NOT EDIT THIS FILE DIRECTLY. If you want to change any of these, copy");
w(w, "# them to your \"actions.txt\" file and modify them there. If an action with");
w(w, "# the same name exists here and in your file, yours will be used.");
w(w, "#");
w(w, "# LOG Actions: They will print messages in your log file, console, chat, ...");
w(w, "# - They start with the word 'log'");
w(w, "# - Then comes their name. That name is used in the config file to identify them");
w(w, "# - Then comes the 'delay', that is how often has this action to be called before it really gets executed");
w(w, "# - Then comes the 'repeat', that is how many seconds have to be between two executions of the action");
w(w, "# - Then comes the 'loglevel', that is how the log message gets categorized (low, med, high)");
w(w, "# - Then comes the 'message', depending on where the action is used, different keywords in [ ] may be used");
w(w, "");
w(w, "# Gives a very short log message of the violation, only containing name, violation type and total violation value, at most once every 15 seconds, only if more than 3 violations happened within the last minute (low) and immediatly (med,high)");
w(w, "log moveLogLowShort 3 15 low NC: [player] failed [check]");
w(w, "log moveLogMedShort 0 15 med NC: [player] failed [check]");
w(w, "log moveLogHighShort 0 15 high NC: [player] failed [check]");
w(w, "");
w(w, "# Gives a log message of the violation, only containing name, violation type and total violation value, at most once every second, only if more than 5 violations happened within the last minute (low) and immediatly (med,high)");
w(w, "log morepacketsLow 5 1 low NC: [player] failed [check]: Sent [packets] more packets than expected. Total violation level [violations].");
w(w, "log morepacketsMed 0 1 med NC: [player] failed [check]: Sent [packets] more packets than expected. Total violation level [violations].");
w(w, "log morepacketsHigh 0 1 high NC: [player] failed [check]: Sent [packets] more packets than expected. Total violation level [violations].");
w(w, "");
w(w, "# Gives a lengthy log message of the violation, containing name, location, violation type and total violation, at most once every 15 seconds, only if more than 3 violations happened within the last minute (low) and immediatly (med,high)");
w(w, "log moveLogLowLong 3 15 low NC: [player] in [world] at [location] moving to [locationto] over distance [distance] failed check [check]. Total violation level so far [violations].");
w(w, "log moveLogMedLong 0 15 med NC: [player] in [world] at [location] moving to [locationto] over distance [distance] failed check [check]. Total violation level so far [violations].");
w(w, "log moveLogHighLong 0 15 high NC: [player] in [world] at [location] moving to [locationto] over distance [distance] failed check [check]. Total violation level so far [violations].");
w(w, "");
w(w, "# Some other log messages that are limited a bit by default, to avoid too extreme spam");
w(w, "log noclipLog 0 1 high NC: [player] failed [check]: at [location] to [locationto].");
w(w, "log reachLog 0 1 med NC: [player] failed [check]: tried to destroy a block over distance [distance].");
w(w, "log directionLog 2 1 med NC: [player] failed [check]: tried to destroy a block out of line of sight.");
w(w, "");
w(w, "# SPECIAL Actions: They will do something check dependant, usually cancel an event.");
w(w, "# - They start with the word 'special'");
w(w, "# - Then comes their name. That name is used in the config file to identify them");
w(w, "# - Then comes the 'delay', that is how often has this action to be called before it really gets executed");
w(w, "# - Then comes the 'repeat', that is how many seconds have to be between two executions of the action");
w(w, "# - Then come further instructions, if necessary");
w(w, "");
w(w, "# Cancels the event in case of an violation. Always. No delay. These are equivalent. The different names are just for better readability");
w(w, "special moveCancel 0 0");
w(w, "special blockbreakCancel 0 0");
w(w, "");
w(w, "# CONSOLECOMMAND Actions: They will execute a command as if it were typed into the console.");
w(w, "# - They start with the word 'consolecommand'");
w(w, "# - Then comes their name. That name is used in the config file to identify them");
w(w, "# - Then comes the 'delay', that is how often has this action to be called before it really gets executed");
w(w, "# - Then comes the 'repeat', that is how many seconds have to be between two executions of the action");
w(w, "# - Then comes the command. You can use the same [ ] that you use for log actions. You'll most likely want to use [player] at some point.");
w(w, "");
w(w, "# E.g. Kick a player");
w(w, "consolecommand kick 0 0 kick [player]");
w.flush();
w.close();
} catch(IOException e) {
e.printStackTrace();
}
}
private static void w(BufferedWriter writer, String text) throws IOException {
writer.write(text);
writer.newLine();
}
}

View File

@ -0,0 +1,70 @@
package cc.co.evenprime.bukkit.nocheat;
import java.util.HashMap;
import java.util.Map;
/**
* Textual explainations of options, will be displayed in the gui tool and the
* descriptions.txt file.
*
* @author Evenprime
*
*/
public class Explainations {
private static final Map<String, String> explainations = new HashMap<String, String>();
static {
set("logging.active", "Should NoCheat related messages get logged at all. Some messages may still appear, e.g. error\n messages, even if this option is deactivated");
set("logging.filename", "Where logs that go to the logfile are stored. You can have different files for different worlds.");
set("logging.filelevel", "What log-level need messages to have to get stored in the logfile. Values are:\n low: all messages\n med: med and high messages only\n high: high messages only\n off: no messages at all.");
set("logging.consolelevel", "What log-level need messages to have to get displayed in your server console. Values are:\n low: all messages\n med: med and high messages only\n high: high messages only\n off: no messages at all.");
set("logging.chatlevel", "What log-level need messages to have to get displayed in the ingame chat. Values are:\n low: all messages\n med: med and high messages only\n high: high messages only\n off: no messages at all.");
set("moving.check", "If true, do various checks on PlayerMove events.");
set("moving.flying.check", "If true, check if a player is flying too fast.\nIf this and 'running.check' are true, running check will be done instead.");
set("moving.flying.speedlimitvertical", "Set the speed limit for moving vertical while flying.\nUnit is 1/100 of a block, default is 100.");
set("moving.flying.speedlimithorizontal", "Set the speed limit for moving horizontal while flying.\nUnit is 1/100 of a block, default is 22.");
set("moving.flying.actions", "What should be done if a player flies faster than the speed limit(s). \nUnits are in 1/100 of a block above the limit.");
set("moving.running.check", "If true, check if a player is running too fast/jumping too high.\nIf this is true, 'flying.check' is ignored.");
set("moving.running.speedlimit", "Set the speed limit for moving horizontal under 'normal' conditions.\nUnit is 1/100 of a block, default is 22.");
set("moving.running.swimming.check", "If 'running.check' and this are active, use a seperate speed limit for swimming players.");
set("moving.running.swimming.speedlimit", "Set the speed limit for moving horizontal while in water.\nUnit is 1/100 of a block, default is 18");
set("moving.running.sneaking.check", "If 'running.check' and this are active, use a seperate speed limit for sneaking players.");
set("moving.running.sneaking.speedlimit", "Set the speed limit for moving horizontal while sneaking.\nUnit is 1/100 of a block, default is 14");
set("moving.running.actions", "What should be done if a player moves faster than the speed limit(s) or jumps higher than allowed.\nUnits are in 1/100 of a block above the limit.");
set("moving.morepackets.check", "If true, check if a player is sending too many 'move-packets' per second. In a normal game, the player won't send more than 22 packets per second.");
set("moving.morepackets.actions", "What should be done if a player sends more 'move-packets' than normal.\nUnits are packets per second above the limit.");
set("moving.noclip.check", "If true, check if a player is moving into a solid wall. EXPERIMENTAL!");
set("moving.noclip.actions", "What should be done if a player moves into a wall.\nUnit is number of walls a player walks into/through.");
set("blockbreak.check", "If true, do various checks on PlayerInteract events.");
set("blockbreak.reach.check", "If true, check if a player is breaking blocks that are too far away.");
set("blockbreak.reach.reachlimit", "Set the distance limit for breaking blocks.\nUnit is 1/100 of a block, default is 485");
set("blockbreak.reach.actions", "What should be done if a player is breaking blocks that are too far away.\nUnit is number of break(attempt)s beyond the limit.");
set("blockbreak.direction.check", "If true, check if a player is looking at the block that he's breaking.");
set("blockbreak.direction.actions", "What should be done if a player is breaking blocks that are not in his line of sight.\nUnit is number of break(attempt)s outside the line of sight.");
}
private static void set(String id, String text) {
explainations.put(id, text);
}
public static String get(String id) {
String result = explainations.get(id);
if(result == null) {
result = "No description available";
}
return result;
}
}

View File

@ -1,38 +0,0 @@
package cc.co.evenprime.bukkit.nocheat;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
public class LogFileFormatter extends Formatter {
private final SimpleDateFormat date;
public LogFileFormatter() {
date = new SimpleDateFormat("yy.MM.dd HH:mm:ss");
}
@Override
public String format(LogRecord record) {
StringBuilder builder = new StringBuilder();
Throwable ex = record.getThrown();
builder.append(date.format(record.getMillis()));
builder.append(" [");
builder.append(record.getLevel().getLocalizedName().toUpperCase());
builder.append("] ");
builder.append(record.getMessage());
builder.append('\n');
if(ex != null) {
StringWriter writer = new StringWriter();
ex.printStackTrace(new PrintWriter(writer));
builder.append(writer);
}
return builder.toString();
}
}

View File

@ -1,15 +0,0 @@
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);
}
}

View File

@ -1,464 +1,90 @@
package cc.co.evenprime.bukkit.nocheat;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import cc.co.evenprime.bukkit.nocheat.actions.CustomAction;
import cc.co.evenprime.bukkit.nocheat.checks.AirbuildCheck;
import cc.co.evenprime.bukkit.nocheat.checks.BogusitemsCheck;
import cc.co.evenprime.bukkit.nocheat.checks.Check;
import cc.co.evenprime.bukkit.nocheat.checks.InfinitedurabilityCheck;
import cc.co.evenprime.bukkit.nocheat.checks.NukeCheck;
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 cc.co.evenprime.bukkit.nocheat.actions.ActionManager;
import cc.co.evenprime.bukkit.nocheat.config.ConfigurationManager;
import cc.co.evenprime.bukkit.nocheat.data.DataManager;
import com.ensifera.animosity.craftirc.CraftIRC;
import com.nijikokun.bukkit.Permissions.Permissions;
import com.nijiko.permissions.PermissionHandler;
import org.bukkit.plugin.Plugin;
import cc.co.evenprime.bukkit.nocheat.events.BlockPlaceEventManager;
import cc.co.evenprime.bukkit.nocheat.events.BlockBreakEventManager;
import cc.co.evenprime.bukkit.nocheat.events.PlayerMoveEventManager;
import cc.co.evenprime.bukkit.nocheat.events.PlayerTeleportEventManager;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
import cc.co.evenprime.bukkit.nocheat.log.LogManager;
/**
*
* NoCheat
*
* Check various player events for their plausibility and log/deny them based on
* configuration
* Check various player events for their plausibility and log/deny them/react to
* them based on configuration
*
* @author Evenprime
*/
public class NoCheat extends JavaPlugin {
private MovingCheck movingCheck;
private SpeedhackCheck speedhackCheck;
private AirbuildCheck airbuildCheck;
private BogusitemsCheck bogusitemsCheck;
private ConfigurationManager conf;
private LogManager log;
private DataManager data;
private Check[] checks;
private PlayerMoveEventManager eventPlayerMoveManager;
private PlayerTeleportEventManager eventPlayerTeleportManager;
private BlockBreakEventManager eventBlockBreakManager;
private NoCheatConfiguration config;
private boolean useNewPermissionSystem = false;
private long exceptionWithPermissions = 0;
private int cleanUpTaskId = -1;
private int serverLagMeasureTaskSetup = -1;
private int serverTicks = 0;
private long serverLagInMilliSeconds = 0;
private long lastServerTime = 0;
// Permissions, if available
private PermissionHandler permissions;
// CraftIRC, if available
private CraftIRC irc;
private Level chatLevel;
private Level ircLevel;
private Level consoleLevel;
private String ircTag;
private NukeCheck nukeCheck;
private InfinitedurabilityCheck infiniteCheck;
private DataManager dataManager;
private CustomCommandSender sender;
private boolean showStartupMessages = true;
private BlockPlaceEventManager eventBlockPlaceManager;
private ActionManager action;
public NoCheat() {
}
public String[] getMessagesOfTheDay() {
return new String[] {"This version of NoCheat was written for CraftBukkit RB #1060", "NoCheat supports the new \"SuperPerms\" system. You can activate it in the config file."};
}
@Override
public boolean onCommand(CommandSender sender, Command command, String commandLabel, String[] args) {
if(args.length == 0) {
sender.sendMessage("NC: Using " + ((permissions == null) ? "isOp()" : "Permissions") + ". Activated checks/bugfixes: " + getActiveChecksAsString() + ". Total time used for moving check so far: " + (movingCheck.statisticElapsedTimeNano / 1000000L + " ms. Average time per move event: " + (movingCheck.statisticElapsedTimeNano / 1000L) / movingCheck.statisticTotalEvents + " us"));
return true;
} else if(args.length == 1 && args[0] != null && args[0].trim().equals("-p")) {
if(sender instanceof Player) {
Player p = (Player) sender;
sender.sendMessage("NC: You have permissions: " + getPermissionsForPlayerAsString(p));
return true;
} else {
sender.sendMessage("NC: You have to be a player to use this command");
return true;
}
} else if(args.length == 2 && args[0] != null && args[0].trim().equals("-p")) {
Player p = getServer().getPlayer(args[1]);
if(p != null) {
sender.sendMessage("NC: " + p.getName() + " has permissions: " + getPermissionsForPlayerAsString(p));
return true;
} else {
sender.sendMessage("NC: Player " + args[1] + " was not found.");
return true;
}
}
return false;
}
public void onDisable() {
PluginDescriptionFile pdfFile = this.getDescription();
if(config != null)
config.cleanup();
if(conf != null)
conf.cleanup();
try {
dataManager.cancelPlayerDataTasks();
teardownCleanupTask();
teardownServerLagMeasureTask();
} catch(Exception e) { /* Can't do much in case of error here... */
}
Logger.getLogger("Minecraft").info("[NoCheat] version [" + pdfFile.getVersion() + "] is disabled.");
log.logToConsole(LogLevel.LOW, "[NoCheat] version [" + pdfFile.getVersion() + "] is disabled.");
}
public void onEnable() {
dataManager = new DataManager();
// First set up logging
this.log = new LogManager(this);
this.data = new DataManager();
sender = new CustomCommandSender(getServer());
this.action = new ActionManager(log);
// parse the nocheat.yml config file
setupConfig();
this.conf = new ConfigurationManager(ConfigurationManager.rootConfigFolder, action);
for(String s : getMessagesOfTheDay()) {
if(showStartupMessages)
Logger.getLogger("Minecraft").info("(NoCheat) Did you know? " + s);
}
movingCheck = new MovingCheck(this, config);
speedhackCheck = new SpeedhackCheck(this, config);
airbuildCheck = new AirbuildCheck(this, config);
bogusitemsCheck = new BogusitemsCheck(this, config);
nukeCheck = new NukeCheck(this, config);
infiniteCheck = new InfinitedurabilityCheck(this, config);
// just for convenience
checks = new Check[] {movingCheck, speedhackCheck, airbuildCheck, bogusitemsCheck, nukeCheck, infiniteCheck};
if(!this.getServer().getAllowFlight() && movingCheck.isActive()) {
Logger.getLogger("Minecraft").warning("[NoCheat] you have set \"allow-flight=false\" in your server.properties file. That builtin anti-flying-mechanism will likely conflict with this plugin. Please consider deactivating it by setting it to \"true\"");
}
eventPlayerMoveManager = new PlayerMoveEventManager(this);
eventPlayerTeleportManager = new PlayerTeleportEventManager(this);
eventBlockBreakManager = new BlockBreakEventManager(this);
eventBlockPlaceManager = new BlockPlaceEventManager(this);
PluginDescriptionFile pdfFile = this.getDescription();
// Get, if available, the Permissions and irc plugin
if(!useNewPermissionSystem) {
setupPermissions();
}
else {
Logger.getLogger("Minecraft").info("[NoCheat] is using SuperPerms system.");
}
setupIRC();
log.logToConsole(LogLevel.LOW, "[NoCheat] version [" + pdfFile.getVersion() + "] is enabled.");
}
Logger.getLogger("Minecraft").info("[NoCheat] version [" + pdfFile.getVersion() + "] is enabled with the following checks: " + getActiveChecksAsString());
public ConfigurationManager getConfigurationManager() {
return conf;
}
setupCleanupTask();
setupServerLagMeasureTask();
public LogManager getLogManager() {
return log;
}
public DataManager getDataManager() {
return dataManager;
return data;
}
private void setupCleanupTask() {
if(cleanUpTaskId != -1) {
return;
}
try {
cleanUpTaskId = Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() {
@Override
public void run() {
try {
if(getDataManager() != null) {
getDataManager().cleanPlayerDataCollection();
}
} catch(Exception e) {}
}
}, 5000, 5000);
} catch(Exception e) {
// It's not THAT important, so if it fails for whatever reason, just
// let it be.
}
public ActionManager getActionManager() {
return action;
}
private void teardownCleanupTask() {
if(cleanUpTaskId != -1) {
Bukkit.getServer().getScheduler().cancelTask(cleanUpTaskId);
}
}
private void setupServerLagMeasureTask() {
if(serverLagMeasureTaskSetup != -1) {
return;
}
serverLagMeasureTaskSetup = Bukkit.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() {
@Override
public void run() {
serverTicks += 10;
long time = System.currentTimeMillis();
serverLagInMilliSeconds = Math.abs((time - lastServerTime - 500) * 2);
lastServerTime = time;
}
}, 10, 10);
}
private void teardownServerLagMeasureTask() {
if(serverLagMeasureTaskSetup != -1) {
Bukkit.getServer().getScheduler().cancelTask(serverLagMeasureTaskSetup);
}
}
/**
* Get, if available, a reference to the Permissions-plugin
*/
private void setupPermissions() {
Plugin permissionsPlugin = this.getServer().getPluginManager().getPlugin("Permissions");
if(this.permissions == null) {
if(permissionsPlugin != null) {
this.permissions = ((Permissions) permissionsPlugin).getHandler();
} else {
PluginDescriptionFile pdfFile = this.getDescription();
Logger.getLogger("Minecraft").warning("[NoCheat] version [" + pdfFile.getVersion() + "] couldn't find \"Permissions\" plugin. Falling back to SuperPerms system.");
useNewPermissionSystem = true;
}
}
}
/**
* Get, if available, a reference to the Permissions-plugin
*/
private void setupIRC() {
CraftIRC p = null;
Plugin test = this.getServer().getPluginManager().getPlugin("CraftIRC");
if(test != null && test instanceof CraftIRC) {
p = (CraftIRC) test;
}
if(p == null) {
PluginDescriptionFile pdfFile = this.getDescription();
Logger.getLogger("Minecraft").info("[NoCheat] version [" + pdfFile.getVersion() + "] couldn't find CrafTIRC plugin. Disabling logging to IRC.");
}
irc = p;
}
/**
* Log a violation message to all locations declared in the config file
*
* @param message
*/
public void log(Level l, String message) {
if(l != null && message != null) {
message = "NC: " + message;
config.logger.log(l, message);
logToConsole(l, message);
logToChat(l, message);
logToIRC(l, message);
}
}
private void logToChat(Level l, String message) {
if(chatLevel.intValue() <= l.intValue()) {
for(Player player : getServer().getOnlinePlayers()) {
if(hasPermission(player, PermissionData.PERMISSION_NOTIFY, false)) {
player.sendMessage("[" + l.getName() + "] " + message);
}
}
}
}
private void logToIRC(Level l, String message) {
if(irc != null && ircLevel.intValue() <= l.intValue()) {
irc.sendMessageToTag("[" + l.getName() + "] " + message, ircTag);
}
}
private void logToConsole(Level l, String message) {
if(consoleLevel.intValue() <= l.intValue()) {
Logger.getLogger("Minecraft").log(l, message);
}
}
public boolean hasPermission(Player player, int permission, boolean ignoreOPstatus) {
if(player == null)
return false;
if(useNewPermissionSystem) {
return player.hasPermission(PermissionData.permissionNames[permission]);
}
try {
if(permissions == null) {
if(ignoreOPstatus) {
// OPs don't get special treatment
return false;
} else {
return player.isOp();
}
} else {
PermissionData data = dataManager.getPermissionData(player);
long time = System.currentTimeMillis();
if(data.lastUpdate[permission] + 10000 < time) {
data.lastUpdate[permission] = time;
data.cache[permission] = permissions.has(player, PermissionData.permissionNames[permission]);
}
return data.cache[permission];
}
} catch(Throwable e) {
if(this.exceptionWithPermissions + 60000 < System.currentTimeMillis()) {
// Prevent spam and recursion by definitely doing this only once
this.exceptionWithPermissions = System.currentTimeMillis();
String logtext = "Asking Permissions-Plugin if " + player.getName() + " has permission " + PermissionData.permissionNames[permission] + " caused an Exception " + e.getMessage() + ". Please review your permissions config file. This message is displayed at most once every 60 seconds.";
log(Level.SEVERE, logtext);
for(StackTraceElement s : e.getStackTrace()) {
config.logger.log(Level.SEVERE, s.toString());
}
}
return false;
}
}
/**
* Read the config file
*/
private void setupConfig() {
if(this.config == null)
this.config = new NoCheatConfiguration(new File(NoCheatConfiguration.configFile), new File(NoCheatConfiguration.descriptionsFile));
else
this.config.config(new File(NoCheatConfiguration.configFile), new File(NoCheatConfiguration.descriptionsFile));
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");
this.useNewPermissionSystem = this.config.getBooleanValue("newpermsystem");
this.showStartupMessages = this.config.getBooleanValue("showinfomessages");
} catch(ConfigurationException e) {
e.printStackTrace();
this.setEnabled(false);
}
}
private String getActiveChecksAsString() {
String s = "";
for(Check c : checks) {
s = s + (c.isActive() ? c.getName() + " " : "");
}
s = s + (movingCheck.isActive() && !movingCheck.allowFlying ? "flying " : "");
s = s + (movingCheck.isActive() && !movingCheck.allowFakeSneak ? "fakesneak " : "");
s = s + (movingCheck.isActive() && !movingCheck.allowFastSwim ? "fastswim " : "");
return s;
}
private String getPermissionsForPlayerAsString(Player p) {
String s = "";
for(Check c : checks) {
s = s + (!c.isActive() ? c.getName() + "* " : (c.skipCheck(p) ? c.getName() + " " : ""));
}
s = s + (!movingCheck.isActive() || movingCheck.allowFlying ? "flying* " : (hasPermission(p, PermissionData.PERMISSION_FLYING, movingCheck.checkOPs) ? "flying " : ""));
s = s + (!movingCheck.isActive() || movingCheck.allowFakeSneak ? "fakesneak* " : (hasPermission(p, PermissionData.PERMISSION_FAKESNEAK, movingCheck.checkOPs) ? "fakesneak " : ""));
s = s + (!movingCheck.isActive() || movingCheck.allowFastSwim ? "fastswim* " : (hasPermission(p, PermissionData.PERMISSION_FASTSWIM, movingCheck.checkOPs) ? "fastswim " : ""));
s = s + (hasPermission(p, PermissionData.PERMISSION_NOTIFY, false) ? "notify " : "");
return s;
}
public int getServerTicks() {
return serverTicks;
}
public long getServerLag() {
return this.serverLagInMilliSeconds;
}
public void handleCustomAction(CustomAction a, Player player) {
String command = a.command.replace("[player]", player.getName());
try {
String[] commandParts = command.split(" ", 2);
String commandName = commandParts[0];
PluginCommand com = Bukkit.getServer().getPluginCommand(commandName);
// If there's a plugin that can handle it
if(com != null) {
if(commandParts.length > 1) { // Command + parameters
String[] commandArgs = commandParts[1].split(" ");
com.execute(sender, commandName, commandArgs);
} else {
String[] commandArgs = new String[0];
com.execute(sender, commandName, commandArgs);
}
} else {
// The standard server should do it
Bukkit.getServer().dispatchCommand(sender, command);
}
} catch(Exception e) {
this.log(Level.WARNING, "NoCheat couldn't execute custom server command: \"" + command + "\"");
}
}
}

View File

@ -0,0 +1,33 @@
package cc.co.evenprime.bukkit.nocheat;
/**
* The various permission nodes used by NoCheat
*
* @author Evenprime
*
*/
public class Permissions {
private final static String _NOCHEAT = "nocheat";
private final static String _CHECKS = _NOCHEAT + ".checks";
private final static String _MOVE = _CHECKS + ".moving";
private final static String _BLOCKBREAK = _CHECKS + ".blockbreak";
public final static String MOVE = _CHECKS + ".moving.*";
public final static String MOVE_FLY = _MOVE + ".flying";
public final static String MOVE_RUN = _MOVE + ".running";
public final static String MOVE_SNEAK = _MOVE + ".sneaking";
public final static String MOVE_SWIM = _MOVE + ".swimming";
public final static String MOVE_NOCLIP = _MOVE + ".noclip";
public final static String MOVE_MOREPACKETS = _MOVE + ".morepackets";
public static final String BLOCKBREAK = _CHECKS + ".blockbreak.*";
public final static String BLOCKBREAK_REACH = _BLOCKBREAK + ".reach";
public final static String BLOCKBREAK_DIRECTION = _BLOCKBREAK + ".direction";
private final static String _ADMIN = _NOCHEAT + ".admin";
public final static String ADMIN_CHATLOG = _ADMIN + ".chatlog";
private Permissions() {}
}

View File

@ -1,20 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.actions;
/**
*
* @author Evenprime
*
*/
public abstract class Action {
public final int firstAfter;
public final boolean repeat;
public Action(int firstAfter, boolean repeat) {
this.firstAfter = firstAfter;
this.repeat = repeat;
}
public abstract String getName();
}

View File

@ -0,0 +1,19 @@
package cc.co.evenprime.bukkit.nocheat.actions;
import java.util.HashMap;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
/**
* An ActionExecutor does exactly that, executing actions.
*
* @author Evenprime
*
*/
public interface ActionExecutor {
public abstract boolean executeActions(Player player, ActionList actions, int violationLevel, HashMap<String, String> hashMap, ConfigurationCache cc);
}

View File

@ -0,0 +1,112 @@
package cc.co.evenprime.bukkit.nocheat.actions;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.actions.history.ActionHistory;
import cc.co.evenprime.bukkit.nocheat.actions.types.Action;
import cc.co.evenprime.bukkit.nocheat.actions.types.ConsolecommandAction;
import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction;
import cc.co.evenprime.bukkit.nocheat.actions.types.SpecialAction;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
import cc.co.evenprime.bukkit.nocheat.log.LogManager;
/**
* Implementation of ActionExecutor, that will trace the history of action
* executions to decide if an action 'really' gets executed.
*
* @author Evenprime
*
*/
public class ActionExecutorWithHistory implements ActionExecutor {
private final Map<Player, ActionHistory> actionHistory = new HashMap<Player, ActionHistory>();
private final ActionManager actionManager;
private final LogManager log;
private final ConsoleCommandSender ccsender;
public ActionExecutorWithHistory(NoCheat plugin) {
this.actionManager = plugin.getActionManager();
this.log = plugin.getLogManager();
this.ccsender = new ConsoleCommandSender(plugin.getServer());
}
/*
* (non-Javadoc)
*
* @see
* cc.co.evenprime.bukkit.nocheat.actions.ActionExecutor#executeActions(
* org.bukkit.entity.Player,
* cc.co.evenprime.bukkit.nocheat.actions.ActionList, double,
* java.util.HashMap,
* cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache)
*/
@Override
public boolean executeActions(Player player, ActionList actions, int violationLevel, HashMap<String, String> hashMap, ConfigurationCache cc) {
boolean special = false;
for(String a : actions.getActions(violationLevel)) {
Action ac = actionManager.getActionByName(a);
Map<String, String> map = null;
if(ac != null) {
if(getHistory(player).executeAction(ac, System.currentTimeMillis())) {
if(ac instanceof LogAction) {
if(map == null)
map = generateHashMap(player, violationLevel, hashMap);
LogAction l = (LogAction) ac;
log.log(l.level, l.getLogMessage(map), cc);
} else if(ac instanceof SpecialAction) {
special = true;
} else if(ac instanceof ConsolecommandAction) {
if(map == null)
map = generateHashMap(player, violationLevel, hashMap);
executeConsoleCommand(((ConsolecommandAction) ac).getCommand(map));
}
}
} else {
log.logToConsole(LogLevel.HIGH, "NoCheat: Couldn't find action " + a + ". You need to define it properly to use it in your config file!");
}
}
return special;
}
private HashMap<String, String> generateHashMap(Player player, double violationLevel, HashMap<String, String> map) {
HashMap<String, String> newMap = new HashMap<String, String>();
newMap.put(LogAction.PLAYER, player.getName());
Location l = player.getLocation();
newMap.put(LogAction.LOCATION, String.format(Locale.US, "%.2f,%.2f,%.2f", l.getX(), l.getY(), l.getZ()));
newMap.put(LogAction.WORLD, player.getWorld().getName());
newMap.put(LogAction.VIOLATIONS, String.format(Locale.US, "%.2f", violationLevel));
newMap.putAll(map);
return newMap;
}
private ActionHistory getHistory(Player player) {
ActionHistory history = actionHistory.get(player);
if(history == null) {
history = new ActionHistory();
actionHistory.put(player, history);
}
return history;
}
private void executeConsoleCommand(String command) {
ccsender.executeConsoleCommand(command);
}
}

View File

@ -0,0 +1,82 @@
package cc.co.evenprime.bukkit.nocheat.actions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A list of actions, that associates actions and a treshold. It allows to
* retrieve all actions that match a certain treshold.
*
* @author Evenprime
*
*/
public class ActionList {
public ActionList() {}
private final List<ActionListEntry> actionList = new ArrayList<ActionListEntry>();
private class ActionListEntry implements Comparable<ActionListEntry> {
public final ArrayList<String> actions = new ArrayList<String>();
public final double treshold;
public ActionListEntry(double treshold, String[] actionNames) {
this.treshold = treshold;
for(String actionName : actionNames) {
if(actionName != null && actionName.length() > 0) {
actions.add(actionName.toLowerCase());
}
}
}
@Override
public int compareTo(ActionListEntry entry) {
if(treshold < entry.treshold) {
return -1;
} else if(treshold == entry.treshold) {
return 0;
} else
return 1;
}
}
/**
* Add an entry to this actionList. The list will be sorted by tresholds
* automatically after the insertion.
*
* @param treshold
* @param actionNames
*/
public void addEntry(double treshold, String[] actionNames) {
this.actionList.add(new ActionListEntry(treshold, actionNames));
Collections.sort(this.actionList);
}
/**
* Get a list of actions that match the violation level.
* The only method that has to be called by a check, besides
* a call to Action
*
* @param violationLevel
* @return
*/
public List<String> getActions(int vl) {
ActionListEntry result = null;
for(ActionListEntry entry : actionList) {
if(entry.treshold <= vl) {
result = entry;
}
}
if(result != null)
return result.actions;
else
return Collections.emptyList();
}
}

View File

@ -0,0 +1,126 @@
package cc.co.evenprime.bukkit.nocheat.actions;
import java.util.HashMap;
import java.util.Map;
import cc.co.evenprime.bukkit.nocheat.actions.types.Action;
import cc.co.evenprime.bukkit.nocheat.actions.types.SpecialAction;
import cc.co.evenprime.bukkit.nocheat.actions.types.ConsolecommandAction;
import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
import cc.co.evenprime.bukkit.nocheat.log.LogManager;
/**
* The ActionManager creates the specific actions and stores them with their
* unique name.
*
* @author Evenprime
*
*/
public class ActionManager {
private final Map<String, Action> actionIdsToActionMap = new HashMap<String, Action>();
private final LogManager log;
private final String[] knownTypes = {"log", "consolecommand", "special"};
public ActionManager(LogManager log) {
this.log = log;
}
/**
*
* @param name
* To identify the action by a name. Same name means same action
*
* @param actionId
* Actual string describing the action (may be more than a string
* in future)
* @return
*/
public void createActionFromStrings(String type, String actionId, String stringDelay, String stringRepeat, String theRest) {
Action action = null;
type = type.toLowerCase();
actionId = actionId.toLowerCase();
int delay;
try {
delay = Integer.parseInt(stringDelay);
} catch(NumberFormatException e) {
log.logToConsole(LogLevel.HIGH, "Can't parse action: \"" + actionId + "\", first parameter " + stringDelay + " not a number");
return;
}
int repeat;
try {
repeat = Integer.parseInt(stringRepeat);
} catch(NumberFormatException e) {
log.logToConsole(LogLevel.HIGH, "Can't parse action: \"" + actionId + "\", second parameter " + stringRepeat + " not a number");
return;
}
// Log actions have the form delay|repeat|level|message
if(type.equals("log")) {
String[] pieces = null;
if(theRest != null) {
pieces = theRest.split("\\s+", 2);
if(pieces == null || pieces.length < 2) {
log.logToConsole(LogLevel.HIGH, "Can't parse log action: \"" + actionId + "\", missing parameters");
return;
}
}
action = createLogActionFromString(delay, repeat, pieces[0], pieces[1]);
} else if(type.equals("special")) {
action = createCancelActionFromString(delay, repeat);
} else if(type.equals("consolecommand")) {
if(theRest == null) {
log.logToConsole(LogLevel.HIGH, "Can't parse consolecommand action: \"" + actionId + "\", missing parameter");
return;
}
action = createConsolecommandActionFromString(delay, repeat, theRest);
} else {
log.logToConsole(LogLevel.HIGH, "Can't parse action: \"" + actionId + "\", unknown action type");
return;
}
if(action != null) {
this.actionIdsToActionMap.put(actionId, action);
}
}
public String[] getKnownTypes() {
return knownTypes;
}
private ConsolecommandAction createConsolecommandActionFromString(int delay, int repeat, String command) {
return new ConsolecommandAction(delay, repeat, command);
}
private SpecialAction createCancelActionFromString(int delay, int repeat) {
return new SpecialAction(delay, repeat);
}
private Action createLogActionFromString(int delay, int repeat, String logLevel, String message) {
LogLevel level = LogLevel.getLogLevelFromString(logLevel);
if(level.equals(LogLevel.OFF)) {
return null;
}
return new LogAction(delay, repeat, level, message);
}
public Action getActionByName(String name) {
return actionIdsToActionMap.get(name.toLowerCase());
}
}

View File

@ -1,19 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.actions;
/**
*
* @author Evenprime
*
*/
public class CancelAction extends Action {
public final static CancelAction cancel = new CancelAction();
private CancelAction() {
super(1, true);
}
public String getName() {
return "cancel";
}
}

View File

@ -0,0 +1,100 @@
package cc.co.evenprime.bukkit.nocheat.actions;
import java.util.Set;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.PermissibleBase;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
/**
* The ConsoleCommandSender imitates the admin writing commands into the server
* console. It is used to execute consolecommand actions.
*
* @author Evenprime
*
*/
public class ConsoleCommandSender implements CommandSender {
private Server server;
private final PermissibleBase perm = new PermissibleBase(this);
public ConsoleCommandSender(Server server) {
this.server = server;
}
public void sendMessage(String message) {
// We have no interest in returning messages
}
public boolean isOp() {
return true;
}
public void setOp(boolean value) {
// We are OP, or at least we claim to be :)
}
public boolean isPlayer() {
return false;
}
public Server getServer() {
return server;
}
public boolean isPermissionSet(String name) {
return perm.isPermissionSet(name);
}
public boolean isPermissionSet(Permission perm) {
return this.perm.isPermissionSet(perm);
}
public boolean hasPermission(String name) {
return true; // We have ALL permissions ;)
}
public boolean hasPermission(Permission perm) {
return true; // We have ALL permissions ;)
}
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
return perm.addAttachment(plugin, name, value);
}
public PermissionAttachment addAttachment(Plugin plugin) {
return perm.addAttachment(plugin);
}
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
return perm.addAttachment(plugin, name, value, ticks);
}
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
return perm.addAttachment(plugin, ticks);
}
public void removeAttachment(PermissionAttachment attachment) {
perm.removeAttachment(attachment);
}
public void recalculatePermissions() {
perm.recalculatePermissions();
}
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
return perm.getEffectivePermissions();
}
public void executeConsoleCommand(String command) {
try {
server.dispatchCommand(this, command);
} catch(Exception e) {
// TODO: Better error handling
}
}
}

View File

@ -1,31 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.actions;
/**
*
* @author Evenprime
*
*/
public class CustomAction extends Action {
public final String command;
public CustomAction(int firstAfter, boolean repeat, String command) {
super(firstAfter, repeat);
this.command = command.trim();
}
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;
}
}
}

View File

@ -1,35 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.actions;
/**
*
* @author Evenprime
*
*/
import java.util.logging.Level;
public class LogAction extends Action {
public final Level level;
public final static LogAction loglow = new LogAction(1, false, Level.INFO);
public final static LogAction logmed = new LogAction(1, false, Level.WARNING);
public final static LogAction loghigh = new LogAction(1, false, Level.SEVERE);
public final static LogAction[] log = {loglow, logmed, loghigh};
private LogAction(int firstAfter, boolean repeat, Level level) {
super(firstAfter, repeat);
this.level = level;
}
public String getName() {
if(level.equals(Level.INFO))
return "loglow";
else if(level.equals(Level.WARNING))
return "logmed";
else if(level.equals(Level.SEVERE))
return "loghigh";
else
return "";
}
}

View File

@ -0,0 +1,88 @@
package cc.co.evenprime.bukkit.nocheat.actions.history;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import cc.co.evenprime.bukkit.nocheat.actions.types.Action;
/**
* Store last 60 seconds of action executions
*
* @author Evenprime
*
*/
public class ActionHistory {
private class ExecutionHistoryEntry {
private final LinkedList<Long> executionTimes = new LinkedList<Long>();
private final long monitoredTimeFrame = 60000;
private long lastExecution = 0;
public ExecutionHistoryEntry() {}
public void addCounter(Long time) {
synchronized(executionTimes) {
while(executionTimes.size() > 0 && executionTimes.getFirst() < time - monitoredTimeFrame) {
executionTimes.removeFirst();
}
executionTimes.add(time);
}
}
public int getCounter() {
return executionTimes.size();
}
public long getLastExecution() {
return lastExecution;
}
public void setLastExecution(long time) {
this.lastExecution = time;
}
}
// Store data between Events
// time + action + action-counter
private final Map<Action, ExecutionHistoryEntry> executionHistory = new HashMap<Action, ExecutionHistoryEntry>();
public ActionHistory() {}
/**
* Returns true, if the action should be executed, because all time
* criteria have been met. Will add a entry with the time to a list
* which will influence further requests, so only use once per
* check!
*
* @param action
* @param time
* @return
*/
public boolean executeAction(Action action, long time) {
ExecutionHistoryEntry entry = executionHistory.get(action);
if(entry == null) {
entry = new ExecutionHistoryEntry();
executionHistory.put(action, entry);
}
// update entry
entry.addCounter(time);
if(entry.getCounter() > action.delay) {
// Execute action?
if(entry.getLastExecution() < time - action.repeat * 1000) {
// Execute action!
entry.setLastExecution(time);
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,29 @@
package cc.co.evenprime.bukkit.nocheat.actions.types;
/**
* An action gets executed as the result of a failed check. If it 'really' gets
* executed depends on how many executions have occured within the last 60
* seconds and how much time was between this and the previous execution
*
* @author Evenprime
*
*/
public abstract class Action {
/**
* Delay in violations (only do if there were more than "delay" exceptions
* in last 60 seconds)
*/
public final int delay;
/**
* Repeat only every "repeat" seconds
*/
public final int repeat;
public Action(int delay, int repeat) {
this.delay = delay;
this.repeat = repeat;
}
}

View File

@ -0,0 +1,33 @@
package cc.co.evenprime.bukkit.nocheat.actions.types;
import java.util.Map;
import java.util.Map.Entry;
/**
* Execute a command by imitating an admin typing the command directly into the
* console
*
* @author Evenprime
*
*/
public class ConsolecommandAction extends Action {
private final String command;
public ConsolecommandAction(int delay, int repeat, String command) {
super(delay, repeat);
this.command = command;
}
public String getCommand(Map<String, String> map) {
String com = command;
for(Entry<String, String> entry : map.entrySet()) {
com = com.replaceAll(entry.getKey(), entry.getValue());
}
return com;
}
}

View File

@ -0,0 +1,48 @@
package cc.co.evenprime.bukkit.nocheat.actions.types;
import java.util.Map;
import java.util.Map.Entry;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
/**
* Print a message to various locations
*
* @author Evenprime
*
*/
public class LogAction extends Action {
// Default stuff
public static final String PLAYER = "\\[player\\]";
public static final String LOCATION = "\\[location\\]";
public static final String WORLD = "\\[world\\]";
public static final String VIOLATIONS = "\\[violations\\]";
// Event dependent stuff
public static final String DISTANCE = "\\[distance\\]";
public static final String LOCATION_TO = "\\[locationto\\]";
public static final String CHECK = "\\[check\\]";
public static final String PACKETS = "\\[packets\\]"; ;
public final LogLevel level;
private final String message;
public LogAction(int delay, int repeat, LogLevel level, String message) {
super(delay, repeat);
this.level = level;
this.message = message;
}
public String getLogMessage(Map<String, String> values) {
String log = message;
for(Entry<String, String> entry : values.entrySet()) {
log = log.replaceAll(entry.getKey(), entry.getValue());
}
return log;
}
}

View File

@ -0,0 +1,15 @@
package cc.co.evenprime.bukkit.nocheat.actions.types;
/**
* Do something check-specific. Usually that is to cancel the event, undo
* something the player did, or do something the server should've done
*
* @author Evenprime
*
*/
public class SpecialAction extends Action {
public SpecialAction(int delay, int repeat) {
super(delay, repeat);
}
}

View File

@ -1,150 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
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;
/**
* Check if the player tries to place blocks in midair (which shouldn't be
* possible)
*
* @author Evenprime
*
*/
public class AirbuildCheck extends Check {
// How should airbuild violations be treated?
private Action actions[][];
private int limits[];
public AirbuildCheck(NoCheat plugin, NoCheatConfiguration config) {
super(plugin, "airbuild", PermissionData.PERMISSION_AIRBUILD, config);
}
public void check(BlockPlaceEvent event) {
// Should we check at all?
if(skipCheck(event.getPlayer()))
return;
// Are all 6 sides "air-blocks" -> cancel the event
if(event.getBlockAgainst().getType() == Material.AIR && event.getBlockPlaced().getType() != Material.AIR) {
final AirbuildData data = plugin.getDataManager().getAirbuildData(event.getPlayer());
final Player p = event.getPlayer();
if(data.summaryTask == -1) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
summary(p, data);
// deleting its own reference
data.summaryTask = -1;
} catch(Exception e) {}
}
};
// Give a summary in 100 ticks ~ 1 second
data.summaryTask = plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, r, 100);
}
data.perFiveSeconds++;
// which limit has been reached
for(int i = limits.length - 1; i >= 0; i--) {
if(data.perFiveSeconds >= limits[i]) {
action(actions[i], event, data.perFiveSeconds - limits[i] + 1);
break;
}
}
}
}
private void action(Action actions[], BlockPlaceEvent event, int violations) {
if(actions == null)
return;
// Execute actions in order
for(Action a : actions) {
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());
}
}
}
}
}
private void summary(Player player, AirbuildData data) {
// 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.perFiveSeconds >= limits[i]) {
plugin.log(LogAction.log[i].level, "Airbuild summary: " + player.getName() + " total violations per 5 seconds: " + data.perFiveSeconds);
break;
}
}
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
protected void registerListeners() {
PluginManager pm = Bukkit.getServer().getPluginManager();
// Register listeners for airbuild check
pm.registerEvent(Event.Type.BLOCK_PLACE, new AirbuildBlockListener(this), Priority.Low, plugin);
}
}

View File

@ -1,123 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
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, NoCheatConfiguration config) {
super(plugin, "bogusitems", PermissionData.PERMISSION_BOGUSITEMS, config);
}
public void check(PlayerPickupItemEvent event) {
// Should we check at all?
if(skipCheck(event.getPlayer()))
return;
Item i = event.getItem();
if(i != null) {
ItemStack s = i.getItemStack();
if(s != null) {
if(s.getAmount() < 0) {// buggy item
event.getItem().remove();
event.setCancelled(true);
plugin.log(Level.WARNING, event.getPlayer().getName() + " tried to pick up an invalid item. Item was removed.");
cleanPlayerInventory(event.getPlayer());
}
}
}
}
public void check(PlayerInteractEvent event) {
if(skipCheck(event.getPlayer()))
return;
if(event.hasItem() && event.getItem().getAmount() <= 0) {// buggy item
event.setCancelled(true);
plugin.log(Level.WARNING, event.getPlayer().getName() + " tried to use an invalid item. Item was removed.");
event.getPlayer().getInventory().remove(event.getItem());
cleanPlayerInventory(event.getPlayer());
}
}
public void check(PlayerDropItemEvent event) {
if(skipCheck(event.getPlayer()))
return;
Item item = event.getItemDrop();
if(item.getItemStack() != null) {
ItemStack stack = item.getItemStack();
if(stack.getAmount() <= 0) {
plugin.log(Level.WARNING, event.getPlayer().getName() + " tried to drop an invalid item. Dropped item was changed to dirt.");
stack.setTypeId(3); // dirt
stack.setAmount(1);
cleanPlayerInventory(event.getPlayer());
}
}
}
private void cleanPlayerInventory(Player player) {
Inventory inv = player.getInventory();
ItemStack stacks[] = inv.getContents();
for(int i = 0; i < stacks.length; i++) {
if(stacks[i] != null && stacks[i].getAmount() <= 0) {
inv.clear(i);
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();
// Register listeners for itemdupe check
Listener bogusitemsPlayerListener = new BogusitemsPlayerListener(this);
// Register listeners for itemdupe check
pm.registerEvent(Event.Type.PLAYER_PICKUP_ITEM, bogusitemsPlayerListener, Priority.Lowest, plugin);
pm.registerEvent(Event.Type.PLAYER_DROP_ITEM, bogusitemsPlayerListener, Priority.Lowest, plugin);
pm.registerEvent(Event.Type.PLAYER_INTERACT, bogusitemsPlayerListener, Priority.Lowest, plugin);
}
}

View File

@ -1,68 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.ConfigurationException;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration;
/**
*
* @author Evenprime
*
*/
public abstract class Check {
private boolean active = false;
private boolean listenersRegistered = false;
private final int permission;
private final String name;
protected final NoCheat plugin;
// Should OPs be checked if Permissions plugin is not available?
public boolean checkOPs;
protected Check(NoCheat plugin, String name, int permission, NoCheatConfiguration config) {
this.plugin = plugin;
this.permission = permission;
this.name = name;
try {
checkOPs = config.getBooleanValue(name + ".checkops");
} catch(ConfigurationException e) {
checkOPs = false;
}
configure(config);
}
public boolean skipCheck(Player player) {
// Should we check at all?
return !active || plugin.hasPermission(player, permission, checkOPs);
}
protected abstract void configure(NoCheatConfiguration config);
protected abstract void registerListeners();
public boolean isActive() {
return active;
}
protected void setActive(boolean active) {
synchronized(this) {
if(active && !listenersRegistered) {
listenersRegistered = true;
registerListeners();
}
}
// There is no way to unregister listeners ...
this.active = active;
}
public String getName() {
return name;
}
}

View File

@ -1,98 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* Check if the player should be allowed to make that move, e.g. is he allowed
* to jump here or move that far in one step
*
* @author Evenprime
*
*/
public class FlyingCheck {
public FlyingCheck() {}
// How many move events can a player have in air before he is expected to
// lose altitude (or eventually land somewhere)
private final static int jumpingLimit = 6;
// How high may a player get compared to his last location with ground
// contact
private final static double jumpHeight = 1.35D;
/**
* Calculate if and how much the player "failed" this check. The check
* should not
* modify any data
*
* @param fromInGround
*
*/
public double check(final Player player, final Location from, final boolean groundContact, final Location to, final MovingData data) {
// How much higher did the player move than expected??
double distanceAboveLimit = 0.0D;
final double toY = to.getY();
final double fromY = from.getY();
double limit = calculateVerticalLimit(data, groundContact) + jumpHeight;
final Location l;
if(data.setBackPoint == null)
l = from;
else
l = data.setBackPoint;
if(data.jumpPhase > jumpingLimit) {
limit -= (data.jumpPhase - jumpingLimit) * 0.15D;
}
distanceAboveLimit = toY - l.getY() - limit;
return distanceAboveLimit;
}
private double calculateVerticalLimit(final MovingData data, final boolean groundContact) {
// A halfway lag-resistant method of allowing vertical acceleration
// without allowing blatant cheating
// FACT: Minecraft server sends player "velocity" to the client and lets
// the client calculate the movement
// PROBLEM: There may be an arbitrary amount of other move events
// between the server sending the data
// and the client accepting it/reacting to it. The server can't know
// when the client starts to
// consider the sent "velocity" in its movement.
// SOLUTION: Give the client at least 10 events after sending "velocity"
// to actually use the velocity for
// its movement, plus additional events if the "velocity" was big and
// can cause longer flights
// The server sent the player a "velocity" packet a short time ago
// consume a counter for this client
if(data.vertFreedomCounter > 0) {
data.vertFreedomCounter--;
data.vertFreedom += data.maxYVelocity * 2D;
data.maxYVelocity *= 0.90D;
}
final double limit = data.vertFreedom;
// If the event counter has been consumed, remove the vertical movement
// limit increase when landing the next time
if(groundContact && data.vertFreedomCounter <= 0) {
data.vertFreedom = 0.0D;
}
return limit;
}
}

View File

@ -1,121 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
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.InfinitedurabilityData;
import cc.co.evenprime.bukkit.nocheat.data.PermissionData;
import cc.co.evenprime.bukkit.nocheat.listeners.InfinitedurabilityListener;
public class InfinitedurabilityCheck extends Check {
private String logMessage;
private String kickMessage;
private boolean log;
private boolean kick;
private boolean cancel;
public InfinitedurabilityCheck(NoCheat plugin, NoCheatConfiguration config) {
super(plugin, "infinitedurability", PermissionData.PERMISSION_INFINITEDURABILITY, config);
}
public void check(PlayerItemHeldEvent event) {
if(skipCheck(event.getPlayer()))
return;
if(event.getNewSlot() == 9) {
Player player = event.getPlayer();
if(log) {
InfinitedurabilityData data = plugin.getDataManager().getInfiniteData(player);
long thisTime = System.currentTimeMillis();
if(data.lastLog + 5000 < thisTime) {
data.lastLog = thisTime;
String logString = String.format(logMessage, player.getName());
plugin.log(Level.SEVERE, logString);
}
}
if(kick) {
player.kickPlayer(kickMessage);
}
}
}
public void check(PlayerInteractEvent event) {
if(skipCheck(event.getPlayer()))
return;
Player player = event.getPlayer();
if(player.getInventory().getHeldItemSlot() == 9) {
if(log) {
InfinitedurabilityData data = plugin.getDataManager().getInfiniteData(player);
long thisTime = System.currentTimeMillis();
if(data.lastLog + 5000 < thisTime) {
data.lastLog = thisTime;
String logString = String.format(logMessage, player.getName());
plugin.log(Level.SEVERE, logString);
}
}
if(kick) {
player.kickPlayer(kickMessage);
}
if(cancel) {
event.setCancelled(true);
}
}
}
@Override
public void configure(NoCheatConfiguration config) {
try {
setActive(config.getBooleanValue("active.infinitedurability"));
logMessage = config.getStringValue("infinitedurability.logmessage");
logMessage = logMessage.replace("[player]", "%1$s");
kickMessage = config.getStringValue("infinitedurability.kickmessage");
log = config.getBooleanValue("infinitedurability.log");
kick = config.getBooleanValue("infinitedurability.kick");
cancel = config.getBooleanValue("infinitedurability.cancel");
} catch(ConfigurationException e) {
setActive(false);
e.printStackTrace();
}
}
@Override
protected void registerListeners() {
PluginManager pm = Bukkit.getServer().getPluginManager();
// Register listeners for itemdupe check
Listener bogusitemsPlayerListener = new InfinitedurabilityListener(this);
// Register listeners for itemdupe check
pm.registerEvent(Event.Type.PLAYER_ITEM_HELD, bogusitemsPlayerListener, Priority.Lowest, plugin);
pm.registerEvent(Event.Type.PLAYER_INTERACT, bogusitemsPlayerListener, Priority.Lowest, plugin);
}
}

View File

@ -1,447 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import java.util.Locale;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.block.BlockPlaceEvent;
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.MovingBlockMonitor;
import cc.co.evenprime.bukkit.nocheat.listeners.MovingPlayerListener;
import cc.co.evenprime.bukkit.nocheat.listeners.MovingPlayerMonitor;
/**
* Check if the player should be allowed to make that move, e.g. is he allowed
* to jump here or move that far in one step
*
* @author Evenprime
*
*/
public class MovingCheck extends Check {
public MovingCheck(NoCheat plugin, NoCheatConfiguration config) {
super(plugin, "moving", PermissionData.PERMISSION_MOVING, config);
helper = new MovingEventHelper();
flyingCheck = new FlyingCheck();
runningCheck = new RunningCheck();
}
private int ticksBeforeSummary;
public long statisticElapsedTimeNano = 0;
public boolean allowFlying;
public boolean allowFakeSneak;
public boolean allowFastSwim;
public double stepWidth;
public double sneakWidth;
public double swimWidth;
private boolean waterElevators;
private String logMessage;
private String summaryMessage;
// How should moving violations be treated?
private Action actions[][];
public long statisticTotalEvents = 1; // Prevent
// accidental
// division by
// 0 at some
// point
private boolean enforceTeleport;
private final MovingEventHelper helper;
private final FlyingCheck flyingCheck;
private final RunningCheck runningCheck;
/**
* The actual check.
* First find out if the event needs to be handled at all
* Second check if the player moved too far horizontally
* Third check if the player moved too high vertically
* Fourth treat any occured violations as configured
*
* @param event
*/
public Location check(Player player, Location from, Location to, MovingData data) {
Location newToLocation = null;
final long startTime = System.nanoTime();
/************* DECIDE WHICH CHECKS NEED TO BE RUN *************/
final boolean flyCheck = !allowFlying && !plugin.hasPermission(player, PermissionData.PERMISSION_FLYING, checkOPs);
final boolean runCheck = true;
/***************** REFINE EVENT DATA FOR CHECKS ***************/
if(data.setBackPoint == null) {
data.setBackPoint = from;
data.jumpPhase = 0;
}
if(flyCheck || runCheck) {
// In both cases it will be interesting to know the type of
// underground the player
// is in or goes to
final int fromType = helper.isLocationOnGround(from.getWorld(), from.getX(), from.getY(), from.getZ(), waterElevators);
final int toType = helper.isLocationOnGround(to.getWorld(), to.getX(), to.getY(), to.getZ(), waterElevators);
final boolean fromOnGround = helper.isOnGround(fromType);
final boolean fromInGround = helper.isInGround(fromType);
final boolean toOnGround = helper.isOnGround(toType);
final boolean toInGround = helper.isInGround(toType);
// Distribute data to checks in the form needed by the checks
/********************* EXECUTE THE CHECKS ********************/
double result = 0.0D;
if(flyCheck) {
result += Math.max(0D, flyingCheck.check(player, from, fromOnGround || fromInGround, to, data));
} else {
// If players are allowed to fly, there's no need to remember
// the last location on ground
data.setBackPoint = from;
}
if(runCheck) {
result += Math.max(0D, runningCheck.check(from, to, !allowFakeSneak && player.isSneaking(), !allowFastSwim && helper.isLiquid(fromType) && helper.isLiquid(toType), data, this));
}
/********* HANDLE/COMBINE THE RESULTS OF THE CHECKS ***********/
data.jumpPhase++;
if(result <= 0) {
if((toInGround && from.getY() >= to.getY()) || helper.isLiquid(toType)) {
data.setBackPoint = to.clone();
data.setBackPoint.setY(Math.ceil(data.setBackPoint.getY()));
data.jumpPhase = 0;
}
else if(toOnGround && (from.getY() >= to.getY() || data.setBackPoint.getY() <= Math.floor(to.getY()))) {
data.setBackPoint = to.clone();
data.setBackPoint.setY(Math.floor(data.setBackPoint.getY()));
data.jumpPhase = 0;
} else if(fromOnGround || fromInGround || toOnGround || toInGround) {
data.jumpPhase = 0;
}
}
if(result > 0) {
// Increment violation counter
data.violationLevel += result;
}
if(result > 0 && data.violationLevel > 0) {
setupSummaryTask(player, data);
int level = limitCheck(data.violationLevel);
data.violationsInARow[level]++;
newToLocation = action(player, from, to, actions[level], data.violationsInARow[level], data, helper);
}
}
// Slowly reduce the level with each event
data.violationLevel *= 0.97;
data.horizFreedom *= 0.97;
statisticElapsedTimeNano += System.nanoTime() - startTime;
statisticTotalEvents++;
return newToLocation;
}
/**
* Register a task with bukkit that will be run a short time from now,
* displaying how many
* violations happened in that timeframe
*
* @param p
* @param data
*/
private void setupSummaryTask(final Player p, final MovingData data) {
// Setup task to display summary later
if(data.summaryTask == -1) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
if(data.highestLogLevel != null) {
String logString = String.format(summaryMessage, p.getName(), ticksBeforeSummary / 20, data.violationsInARow[0], data.violationsInARow[1], data.violationsInARow[2]);
plugin.log(data.highestLogLevel, logString);
data.highestLogLevel = Level.ALL;
}
// deleting its own reference
data.summaryTask = -1;
data.violationsInARow[0] = 0;
data.violationsInARow[1] = 0;
data.violationsInARow[2] = 0;
} catch(Exception e) {}
}
};
// Give a summary in x ticks. 20 ticks ~ 1 second
data.summaryTask = plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, r, ticksBeforeSummary);
}
}
/**
* Call this when a player got successfully teleported with the
* corresponding event to adjust stored
* data to the new situation
*
* @param event
*/
public void teleported(PlayerTeleportEvent event) {
MovingData data = plugin.getDataManager().getMovingData(event.getPlayer());
// We can enforce a teleport, if that flag is explicitly set (but I'd
// rather have other plugins
// not arbitrarily cancel teleport events in the first place...
// Ok, it seems that now teleports via portals may have "null" as a to location. Nice that nobody told me that...
// So avoid calling methods of the "to" location at all costs
if(data.teleportInitializedByMe != null && event.isCancelled() && enforceTeleport && data.teleportInitializedByMe.equals(event.getTo())) {
event.setCancelled(false);
data.teleportInitializedByMe = null;
}
// reset anyway - if another plugin cancelled our teleport it's no use
// to try and be precise
data.setBackPoint = null;
data.jumpPhase = 0;
}
/**
* Update the cached values for players velocity to be prepared to
* give them additional movement freedom in their next move events
*
* @param v
* @param data
*/
public void updateVelocity(Vector v, MovingData data) {
// Compare the velocity vector to the existing movement freedom that
// we've from previous events
double tmp = (Math.abs(v.getX()) + Math.abs(v.getZ())) * 3D;
if(tmp > data.horizFreedom)
data.horizFreedom = tmp;
if(v.getY() > 0.0D) {
data.vertFreedomCounter = 50;
data.maxYVelocity += v.getY();
}
}
/** An attempt to work around lag during tower building **/
public void blockPlaced(BlockPlaceEvent event) {
Player player = event.getPlayer();
MovingData data = plugin.getDataManager().getMovingData(player);
if(event.getBlockPlaced() == null || data.setBackPoint == null) {
return;
}
Location lblock = event.getBlockPlaced().getLocation();
Location lplayer = player.getLocation();
if(Math.abs(lplayer.getBlockX() - lblock.getBlockX()) <= 1 && Math.abs(lplayer.getBlockZ() - lblock.getBlockZ()) <= 1 && lplayer.getBlockY() - lblock.getBlockY() >= 0 && lplayer.getBlockY() - lblock.getBlockY()<= 2) {
int type = helper.types[event.getBlockPlaced().getTypeId()];
if(helper.isSolid(type) || helper.isLiquid(type)) {
if(lblock.getBlockY()+1 >= data.setBackPoint.getY()) {
data.setBackPoint.setY(lblock.getBlockY()+1);
data.jumpPhase = 0;
}
}
}
}
/**
* Perform actions that were specified in the config file
*
* @param event
* @param action
* @return
*/
private Location action(Player player, Location from, Location to, Action[] actions, int violations, MovingData data, MovingEventHelper helper) {
Location newToLocation = null;
if(actions == null)
return newToLocation;
boolean cancelled = false;
for(Action a : actions) {
if(a.firstAfter <= violations) {
if(a.firstAfter == violations || a.repeat) {
if(a instanceof LogAction) {
// prepare log message if necessary
String log = String.format(Locale.US, logMessage, player.getName(), from.getWorld().getName(), to.getWorld().getName(), from.getX(), from.getY(), from.getZ(), to.getX(), to.getY(), to.getZ(), Math.abs(from.getX() - to.getX()), to.getY() - from.getY(), Math.abs(from.getZ() - 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) {
// Make a modified copy of the setBackPoint to prevent
// other plugins from accidentally modifying it
// and keep the current pitch and yaw (setbacks "feel"
// better that way). Plus try to adapt the Y-coord
// to place the player close to ground
double y = data.setBackPoint.getY();
/*// search for the first solid block up to 5 blocks below
// the setbackpoint and teleport the player there
int i = 0;
for(; i < 20; i++) {
if(helper.isLocationOnGround(data.setBackPoint.getWorld(), data.setBackPoint.getX(), data.setBackPoint.getY() - 0.5 * i, data.setBackPoint.getZ(), waterElevators) != MovingData.NONSOLID) {
break;
}
}
y -= 0.5 * i;
data.setBackPoint.setY(y);*/
// Remember the location we send the player to, to
// identify teleports that were started by us
data.teleportInitializedByMe = new Location(data.setBackPoint.getWorld(), data.setBackPoint.getX(), y, data.setBackPoint.getZ(), to.getYaw(), to.getPitch());
newToLocation = data.teleportInitializedByMe;
cancelled = true; // just prevent us from treating more
// than one "cancel" action, which
// would make no sense
} else if(a instanceof CustomAction)
plugin.handleCustomAction((CustomAction) a, player);
}
}
}
return newToLocation;
}
/**
* Check a value against an array of sorted values to find out
* where it fits in
*
* @param value
* @param limits
* @return
*/
private static int limitCheck(final double value) {
if(value > 0.0D) {
if(value > 1.0D) {
if(value > 4.0D)
return 2;
return 1;
}
return 0;
}
return -1;
}
@Override
public void configure(NoCheatConfiguration config) {
try {
allowFlying = config.getBooleanValue("moving.allowflying");
allowFakeSneak = config.getBooleanValue("moving.allowfakesneak");
allowFastSwim = config.getBooleanValue("moving.allowfastswim");
waterElevators = config.getBooleanValue("moving.waterelevators");
checkOPs = config.getBooleanValue("moving.checkops");
logMessage = config.getStringValue("moving.logmessage").replace("[player]", "%1$s").replace("[world]", "%2$s").replace("[from]", "(%4$.1f, %5$.1f, %6$.1f)").replace("[to]", "(%7$.1f, %8$.1f, %9$.1f)").replace("[distance]", "(%10$.1f, %11$.1f, %12$.1f)");
summaryMessage = config.getStringValue("moving.summarymessage").replace("[timeframe]", "%2$d").replace("[player]", "%1$s").replace("[violations]", "(%3$d,%4$d,%5$d)");
ticksBeforeSummary = config.getIntegerValue("moving.summaryafter") * 20;
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"));
enforceTeleport = config.getBooleanValue("moving.enforceteleport");
stepWidth = ((double) config.getIntegerValue("moving.limits.walking")) / 100D;
sneakWidth = ((double) config.getIntegerValue("moving.limits.sneaking")) / 100D;
swimWidth = ((double) config.getIntegerValue("moving.limits.swimming")) / 100D;
} catch(ConfigurationException e) {
setActive(false);
e.printStackTrace();
}
}
@Override
protected void registerListeners() {
PluginManager pm = Bukkit.getServer().getPluginManager();
Listener movingPlayerMonitor = new MovingPlayerMonitor(plugin.getDataManager(), this);
Listener movingBlockMonitor = new MovingBlockMonitor(this);
// Register listeners for moving check
pm.registerEvent(Event.Type.PLAYER_MOVE, new MovingPlayerListener(plugin.getDataManager(), this), Priority.Lowest, plugin);
pm.registerEvent(Event.Type.PLAYER_MOVE, movingPlayerMonitor, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.BLOCK_PLACE, movingBlockMonitor, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_TELEPORT, movingPlayerMonitor, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_PORTAL, movingPlayerMonitor, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_RESPAWN, movingPlayerMonitor, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_VELOCITY, movingPlayerMonitor, Priority.Monitor, plugin);
}
}

View File

@ -1,112 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import java.util.Locale;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.block.BlockBreakEvent;
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.config.NoCheatConfiguration;
import cc.co.evenprime.bukkit.nocheat.data.NukeData;
import cc.co.evenprime.bukkit.nocheat.data.PermissionData;
import cc.co.evenprime.bukkit.nocheat.listeners.NukeBlockListener;
public class NukeCheck extends Check {
private String kickMessage;
private String logMessage;
private boolean limitReach;
public NukeCheck(NoCheat plugin, NoCheatConfiguration config) {
super(plugin, "nuke", PermissionData.PERMISSION_NUKE, config);
}
@Override
protected void configure(NoCheatConfiguration config) {
try {
kickMessage = config.getStringValue("nuke.kickmessage");
logMessage = config.getStringValue("nuke.logmessage").replace("[player]", "%1$s");
limitReach = config.getBooleanValue("nuke.limitreach");
setActive(config.getBooleanValue("active.nuke"));
} catch(ConfigurationException e) {
setActive(false);
e.printStackTrace();
}
}
public void check(BlockBreakEvent event) {
if(skipCheck(event.getPlayer())) {
return;
}
NukeData data = plugin.getDataManager().getNukeData(event.getPlayer());
Block block = event.getBlock();
Location eyes = event.getPlayer().getEyeLocation();
Vector direction = eyes.getDirection();
// Because it's not very precise on very short distances,
// consider the length of the side of a block to be 2.0 instead of 1.0
final double x1 = ((double) block.getX()) - eyes.getX() - 0.5;
final double y1 = ((double) block.getY()) - eyes.getY() - 0.5;
final double z1 = ((double) block.getZ()) - eyes.getZ() - 0.5;
final double x2 = x1 + 2;
final double y2 = y1 + 2;
final double z2 = z1 + 2;
double factor = new Vector(x1 + 1, y1 + 1, z1 + 1).length();
boolean tooFarAway = limitReach && factor > 4.85D;
if(!tooFarAway && factor * direction.getX() >= x1 && factor * direction.getY() >= y1 && factor * direction.getZ() >= z1 && factor * direction.getX() <= x2 && factor * direction.getY() <= y2 && factor * direction.getZ() <= z2) {
if(data.counter > 0) {
data.counter--;
}
} else {
data.counter++;
event.setCancelled(true);
if(data.counter > 10) {
String log = String.format(Locale.US, logMessage, event.getPlayer().getName());
plugin.log(Level.SEVERE, log);
event.getPlayer().kickPlayer(kickMessage);
data.counter = 0; // Reset to prevent problems on next login
}
}
}
@Override
protected void registerListeners() {
PluginManager pm = Bukkit.getServer().getPluginManager();
Listener blockListener = new NukeBlockListener(this);
// Register listeners for moving check
pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener, Priority.Lowest, plugin);
pm.registerEvent(Event.Type.BLOCK_DAMAGE, blockListener, Priority.Monitor, plugin);
}
}

View File

@ -1,50 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import org.bukkit.Location;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
public class RunningCheck {
private final static double maxBonus = 1D;
public RunningCheck() {}
public double check(final Location from, final Location to, final boolean isSneaking, final boolean isSwimming, final MovingData data, MovingCheck check) {
// How much further did the player move than expected??
double distanceAboveLimit = 0.0D;
// First calculate the distance the player has moved horizontally
final double xDistance = from.getX() - to.getX();
final double zDistance = from.getZ() - to.getZ();
final double totalDistance = Math.sqrt((xDistance * xDistance + zDistance * zDistance));
if(isSneaking) {
distanceAboveLimit = totalDistance - check.sneakWidth - data.horizFreedom;
} else if(isSwimming) {
distanceAboveLimit = totalDistance - check.swimWidth - data.horizFreedom;
} else {
distanceAboveLimit = totalDistance - check.stepWidth - data.horizFreedom;
}
// Did he go too far?
if(distanceAboveLimit > 0) {
// Try to consume the "buffer"
distanceAboveLimit -= data.horizontalBuffer;
data.horizontalBuffer = 0;
// Put back the "overconsumed" buffer
if(distanceAboveLimit < 0) {
data.horizontalBuffer = -distanceAboveLimit;
}
}
// He was within limits, give the difference as buffer
else {
data.horizontalBuffer = Math.min(maxBonus, data.horizontalBuffer - distanceAboveLimit);
}
return distanceAboveLimit;
}
}

View File

@ -1,212 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.Listener;
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;
import cc.co.evenprime.bukkit.nocheat.listeners.SpeedhackPlayerMonitor;
/**
* Log if a player sends to many move events in a specific time frame, usually
* the result of tinkering with the system clock
*
* @author Evenprime
*
*/
public class SpeedhackCheck extends Check {
public SpeedhackCheck(NoCheat plugin, NoCheatConfiguration config) {
super(plugin, "speedhack", PermissionData.PERMISSION_SPEEDHACK, config);
}
private static final int violationsLimit = 3;
// Limits for the speedhack check per second
private int limits[];
private String logMessage;
// How should speedhack violations be treated?
private Action actions[][];
public void check(PlayerMoveEvent event) {
Player player = event.getPlayer();
// Should we check at all?
if(skipCheck(player))
return;
// Ignore events of players in vehicles (these can be the cause of event
// spam between server and client)
// Ignore events if the player has positive y-Velocity (these can be the
// cause of event spam between server and client)
if(player.isInsideVehicle() || player.getVelocity().getY() > 0.0D) {
return;
}
// During world transfers many events of same location get sent, ignore
// them all
if(event.getFrom().equals(event.getTo())) {
return;
}
// Get the player-specific data
SpeedhackData data = plugin.getDataManager().getSpeedhackData(player);
// Count the event (twice, to interpolate from 0.5 seconds to 1 second
data.eventsSinceLastCheck += 2;
// Get the ticks of the server
int ticks = plugin.getServerTicks();
// Roughly half a second (= 10 ticks) passed
if(data.lastCheckTicks + 10 == ticks) {
// If we haven't already got a setback point, create one now
if(data.setBackPoint == null) {
data.setBackPoint = event.getFrom();
}
if(plugin.getServerLag() > 150) {
// Any data would likely be unreliable with that lag
resetData(data, event.getFrom());
} else {
int level = -1;
if(data.eventsSinceLastCheck > limits[2])
level = 2;
else if(data.eventsSinceLastCheck > limits[1])
level = 1;
else if(data.eventsSinceLastCheck > limits[0])
level = 0;
else {
resetData(data, event.getFrom());
}
if(level >= 0) {
data.violationsInARowTotal++;
}
if(data.violationsInARowTotal >= violationsLimit) {
data.violationsInARow[level]++;
action(actions[level], event, data.violationsInARow[level], data);
}
// Reset value for next check
data.eventsSinceLastCheck = 0;
}
data.lastCheckTicks = ticks;
} else if(data.lastCheckTicks + 10 < ticks) {
// The player didn't move for the last 10 ticks
resetData(data, event.getFrom());
data.lastCheckTicks = ticks;
}
}
private static void resetData(SpeedhackData data, Location l) {
data.violationsInARow[0] = 0;
data.violationsInARow[1] = 0;
data.violationsInARow[2] = 0;
data.violationsInARowTotal = 0;
data.eventsSinceLastCheck = 0;
data.setBackPoint = l;
}
private void action(Action actions[], PlayerMoveEvent event, int violations, SpeedhackData data) {
if(actions == null)
return;
for(Action a : actions) {
if(a.firstAfter <= violations) {
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.firstAfter == violations || a.repeat) {
if(a instanceof CancelAction) {
resetPlayer(event, data);
} else if(a instanceof CustomAction) {
plugin.handleCustomAction((CustomAction) a, event.getPlayer());
}
}
}
}
}
private static void resetPlayer(PlayerMoveEvent event, SpeedhackData data) {
if(data.setBackPoint == null)
data.setBackPoint = event.getFrom();
// If we have stored a location for the player, we put him back there
event.setTo(data.setBackPoint);
}
@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").replace("[player]", "%1$s").replace("[events]", "%2$d").replace("[limit]", "%3$d");
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();
Listener speedhackPlayerListener = new SpeedhackPlayerListener(this);
Listener speedhackPlayerMonitor = new SpeedhackPlayerMonitor(this);
// Register listeners for speedhack check
pm.registerEvent(Event.Type.PLAYER_MOVE, speedhackPlayerListener, Priority.High, plugin);
pm.registerEvent(Event.Type.PLAYER_MOVE, speedhackPlayerMonitor, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_TELEPORT, speedhackPlayerListener, Priority.Monitor, plugin);
}
public void teleported(PlayerTeleportEvent event) {
SpeedhackData data = plugin.getDataManager().getSpeedhackData(event.getPlayer());
resetData(data, event.getTo());
}
public void teleported(Player player) {
SpeedhackData data = plugin.getDataManager().getSpeedhackData(player);
resetData(data, player.getLocation());
}
}

View File

@ -0,0 +1,58 @@
package cc.co.evenprime.bukkit.nocheat.checks.blockbreak;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.Permissions;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.BlockBreakData;
/**
* The main Check class for blockbreak event checking. It will decide which checks
* need to be executed and in which order. It will also precalculate some values
* that are needed by multiple checks.
*
* @author Evenprime
*
*/
public class BlockBreakCheck {
private final ReachCheck reachCheck;
private final DirectionCheck directionCheck;
public BlockBreakCheck(NoCheat plugin) {
this.reachCheck = new ReachCheck(plugin);
this.directionCheck = new DirectionCheck(plugin);
}
public boolean check(final Player player, final Block brokenBlock, final BlockBreakData data, final ConfigurationCache cc) {
boolean cancel = false;
boolean reach = cc.blockbreak.reachCheck && !player.hasPermission(Permissions.BLOCKBREAK_REACH);
boolean direction = cc.blockbreak.directionCheck && !player.hasPermission(Permissions.BLOCKBREAK_DIRECTION);
if((reach || direction) && brokenBlock != null) {
Location eyes = player.getEyeLocation();
final double x1 = ((double) brokenBlock.getX()) - eyes.getX() - 0.5;
final double y1 = ((double) brokenBlock.getY()) - eyes.getY() - 0.5;
final double z1 = ((double) brokenBlock.getZ()) - eyes.getZ() - 0.5;
double factor = new Vector(x1 + 1, y1 + 1, z1 + 1).length();
if(reach) {
cancel = reachCheck.check(player, factor, data, cc);
}
if(!cancel && direction && !brokenBlock.getLocation().equals(data.instaBrokeBlockLocation)) {
cancel = directionCheck.check(player, factor, x1, y1, z1, data, cc);
}
}
return cancel;
}
}

View File

@ -0,0 +1,57 @@
package cc.co.evenprime.bukkit.nocheat.checks.blockbreak;
import java.util.HashMap;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutor;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutorWithHistory;
import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.BlockBreakData;
/**
* The DirectionCheck will find out if a player tried to interact with something
* that's not in his field of view.
*
* @author Evenprime
*
*/
public class DirectionCheck {
private final ActionExecutor action;
public DirectionCheck(NoCheat plugin) {
this.action = new ActionExecutorWithHistory(plugin);
}
public boolean check(Player player, double factor, double x1, double y1, double z1, BlockBreakData data, ConfigurationCache cc) {
boolean cancel = false;
Vector direction = player.getEyeLocation().getDirection();
final double x2 = x1 + 2;
final double y2 = y1 + 2;
final double z2 = z1 + 2;
if(factor * direction.getX() >= x1 && factor * direction.getY() >= y1 && factor * direction.getZ() >= z1 && factor * direction.getX() <= x2 && factor * direction.getY() <= y2 && factor * direction.getZ() <= z2) {
// Player did nothing wrong
// reduce violation counter
data.directionViolationLevel *= 0.9D;
} else {
// Player failed the check
// Increment violation counter
data.directionViolationLevel += 1;
// Prepare some event-specific values for logging and custom actions
HashMap<String, String> params = new HashMap<String, String>();
params.put(LogAction.CHECK, "blockbreak.direction");
cancel = action.executeActions(player, cc.blockbreak.directionActions, (int) data.directionViolationLevel, params, cc);
}
return cancel;
}
}

View File

@ -0,0 +1,52 @@
package cc.co.evenprime.bukkit.nocheat.checks.blockbreak;
import java.util.HashMap;
import java.util.Locale;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutor;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutorWithHistory;
import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.BlockBreakData;
/**
* The reach check will find out if a player interacts with something that's too
* far away
*
* @author Evenprime
*
*/
public class ReachCheck {
private ActionExecutor action;
public ReachCheck(NoCheat plugin) {
this.action = new ActionExecutorWithHistory(plugin);
}
public boolean check(Player player, double distance, BlockBreakData data, ConfigurationCache cc) {
boolean cancel = false;
if(distance > cc.blockbreak.reachDistance) {
// Player failed the check
// Increment violation counter
data.reachViolationLevel += 1;
// Prepare some event-specific values for logging and custom actions
HashMap<String, String> params = new HashMap<String, String>();
params.put(LogAction.CHECK, "blockbreak.reach");
params.put(LogAction.DISTANCE, String.format(Locale.US, "%.2f", distance));
cancel = action.executeActions(player, cc.blockbreak.reachActions, (int) data.reachViolationLevel, params, cc);
} else {
data.reachViolationLevel *= 0.9D;
}
return cancel;
}
}

View File

@ -0,0 +1,85 @@
package cc.co.evenprime.bukkit.nocheat.checks.moving;
import java.util.HashMap;
import java.util.Locale;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutor;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutorWithHistory;
import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* A check designed for people that are allowed to fly, but not as fast as they
* want. The complement to the "RunningCheck", which is for people that aren't
* allowed to fly, and therefore have tighter rules to obey.
*
* @author Evenprime
*
*/
public class FlyingCheck {
private final ActionExecutor action;
public FlyingCheck(NoCheat plugin) {
this.action = new ActionExecutorWithHistory(plugin);
}
public Location check(Player player, Location from, Location to, ConfigurationCache cc, MovingData data) {
if(data.movingsetBackPoint == null) {
data.movingsetBackPoint = player.getLocation().clone();
}
final double yDistance = to.getY() - from.getY();
// Calculate some distances
final double xDistance = to.getX() - from.getX();
final double zDistance = to.getZ() - from.getZ();
final double horizontalDistance = Math.sqrt((xDistance * xDistance + zDistance * zDistance));
double result = 0;
Location newToLocation = null;
// super simple, just check distance compared to max distance
result += Math.max(0.0D, yDistance - data.vertFreedom - cc.moving.flyingSpeedLimitVertical);
result += Math.max(0.0D, horizontalDistance - data.horizFreedom - cc.moving.flyingSpeedLimitHorizontal);
result = result * 100;
if(result > 0) {
// Increment violation counter
data.movingViolationLevel += result;
// Prepare some event-specific values for logging and custom actions
HashMap<String, String> params = new HashMap<String, String>();
params.put(LogAction.DISTANCE, String.format(Locale.US, "%.2f,%.2f,%.2f", xDistance, yDistance, zDistance));
params.put(LogAction.LOCATION_TO, String.format(Locale.US, "%.2f,%.2f,%.2f", to.getX(), to.getY(), to.getZ()));
params.put(LogAction.CHECK, "flyingspeed");
boolean cancel = action.executeActions(player, cc.moving.flyingActions, (int) data.movingViolationLevel, params, cc);
// Was one of the actions a cancel? Then really do it
if(cancel) {
newToLocation = data.movingsetBackPoint;
}
}
// Slowly reduce the level with each event
data.movingViolationLevel *= 0.97;
// Some other cleanup 'n' stuff
if(newToLocation == null) {
data.movingsetBackPoint = to.clone();
}
data.jumpPhase = 0;
return newToLocation;
}
}

View File

@ -0,0 +1,98 @@
package cc.co.evenprime.bukkit.nocheat.checks.moving;
import java.util.HashMap;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.Permissions;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutor;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutorWithHistory;
import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* The morePacketsCheck (previously called SpeedhackCheck) will try to identify
* players that send more than the usual amount of move-packets to the server to
* be able to move faster than normal, without getting caught by the other
* checks (flying/running).
*
* It monitors the number of packets sent to the server within 1 second and
* compares it to the "legal" number of packets for that timeframe (22).
*
* @author Evenprime
*
*/
public class MorePacketsCheck {
private final ActionExecutor action;
private final long timeframe = 1000;
private final double packetsPerTimeframe = 22;
private final double lowLimit = -20;
public MorePacketsCheck(NoCheat plugin) {
this.action = new ActionExecutorWithHistory(plugin);
}
public Location check(Player player, ConfigurationCache cc, MovingData data) {
if(!cc.moving.morePacketsCheck || player.hasPermission(Permissions.MOVE_MOREPACKETS)) {
return null;
}
Location newToLocation = null;
data.morePacketsCounter++;
if(data.morePacketsSetbackPoint == null) {
data.morePacketsSetbackPoint = player.getLocation();
}
long currentTime = System.currentTimeMillis();
// Is at least half a second gone by?
if(currentTime - timeframe > data.morePacketsLastTime) {
// Are we over the 10 event limit for that time frame now?
final double change = data.morePacketsCounter - packetsPerTimeframe * ((double) (currentTime - data.morePacketsLastTime)) / ((double) timeframe);
if(change > 0) {
data.morePacketsOverLimit += change;
} else if(data.morePacketsOverLimit + change > lowLimit) {
data.morePacketsOverLimit += change;
} else if(data.morePacketsOverLimit > lowLimit) {
data.morePacketsOverLimit = lowLimit;
}
if(data.morePacketsOverLimit > 0 && data.morePacketsCounter > packetsPerTimeframe) {
HashMap<String, String> params = new HashMap<String, String>();
params.put(LogAction.PACKETS, String.valueOf(data.morePacketsCounter - packetsPerTimeframe));
params.put(LogAction.CHECK, "morepackets");
boolean cancel = false;
cancel = action.executeActions(player, cc.moving.morePacketsActions, (int) data.morePacketsOverLimit, params, cc);
if(cancel) {
newToLocation = data.morePacketsSetbackPoint != null ? data.morePacketsSetbackPoint : player.getLocation();
}
}
if(newToLocation == null) {
data.morePacketsSetbackPoint = player.getLocation();
}
if(data.morePacketsOverLimit > 0)
data.morePacketsOverLimit *= 0.8; // Shrink the "over limit"
// value by 20 % every second
data.morePacketsLastTime = currentTime;
data.morePacketsCounter = 0;
}
return newToLocation;
}
}

View File

@ -0,0 +1,128 @@
package cc.co.evenprime.bukkit.nocheat.checks.moving;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.Permissions;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* The main Check class for Move event checking. It will decide which checks
* need to be executed and in which order. It will also precalculate some values
* that are needed by multiple checks.
*
* @author Evenprime
*
*/
public class MovingCheck {
private final FlyingCheck flyingCheck;
private final RunningCheck runningCheck;
private final NoclipCheck noclippingCheck;
private final MorePacketsCheck morePacketsCheck;
private final MovingEventHelper helper;
public MovingCheck(NoCheat plugin) {
this.helper = new MovingEventHelper();
this.flyingCheck = new FlyingCheck(plugin);
this.runningCheck = new RunningCheck(plugin);
this.noclippingCheck = new NoclipCheck(plugin);
this.morePacketsCheck = new MorePacketsCheck(plugin);
}
/**
* Return the a new destination location or null
*
* @param event
* @return
*/
public Location check(final Player player, final Location from, final Location to, final MovingData data, final ConfigurationCache cc) {
// Players in vehicles are of no interest
if(player.isInsideVehicle())
return null;
/**
* If not null, this will be used as the new target location
*/
Location newToLocation = null;
/******** DO GENERAL DATA MODIFICATIONS ONCE FOR EACH EVENT *****/
if(data.horizVelocityCounter > 0) {
data.horizVelocityCounter--;
} else {
data.horizFreedom *= 0.90;
}
if(data.vertVelocityCounter > 0) {
data.vertVelocityCounter--;
data.vertFreedom += data.vertVelocity;
data.vertVelocity *= 0.90;
} else {
data.vertFreedom = 0;
}
/************* DECIDE WHICH CHECKS NEED TO BE RUN *************/
final boolean flyCheck = cc.moving.flyingCheck && !player.hasPermission(Permissions.MOVE_FLY);
final boolean runCheck = cc.moving.runningCheck && !player.hasPermission(Permissions.MOVE_RUN);
final boolean morepacketsCheck = cc.moving.morePacketsCheck && !player.hasPermission(Permissions.MOVE_MOREPACKETS);
final boolean noclipCheck = cc.moving.noclipCheck && !player.hasPermission(Permissions.MOVE_NOCLIP);
/********************* EXECUTE THE FLY/JUMP/RUNNING CHECK ********************/
// If the player is not allowed to fly and not allowed to run
if(flyCheck && runCheck) {
newToLocation = runningCheck.check(player, from, to, helper, cc, data);
}
// else if he is not allowed to fly
else if(flyCheck) {
newToLocation = flyingCheck.check(player, from, to, cc, data);
}
// else don't do anything
/********* EXECUTE THE MOREPACKETS CHECK ********************/
if(newToLocation == null && morepacketsCheck) {
newToLocation = morePacketsCheck.check(player, cc, data);
}
/********* EXECUTE THE NOCLIP CHECK ********************/
if(newToLocation == null && noclipCheck) {
newToLocation = noclippingCheck.check(player, from, to, helper, cc, data);
}
return newToLocation;
}
/**
* This is a workaround for people placing blocks below them causing false positives
* with the move check(s).
*
* @param player
* @param data
* @param blockPlaced
*/
public void blockPlaced(Player player, MovingData data, Block blockPlaced) {
if(blockPlaced == null || data.movingsetBackPoint == null) {
return;
}
Location lblock = blockPlaced.getLocation();
Location lplayer = player.getLocation();
if(Math.abs(lplayer.getBlockX() - lblock.getBlockX()) <= 1 && Math.abs(lplayer.getBlockZ() - lblock.getBlockZ()) <= 1 && lplayer.getBlockY() - lblock.getBlockY() >= 0 && lplayer.getBlockY() - lblock.getBlockY() <= 2) {
int type = helper.types[blockPlaced.getTypeId()];
if(helper.isSolid(type) || helper.isLiquid(type)) {
if(lblock.getBlockY() + 1 >= data.movingsetBackPoint.getY()) {
data.movingsetBackPoint.setY(lblock.getBlockY() + 1);
data.jumpPhase = 0;
}
}
}
}
}

View File

@ -1,4 +1,4 @@
package cc.co.evenprime.bukkit.nocheat.checks;
package cc.co.evenprime.bukkit.nocheat.checks.moving;
import net.minecraft.server.Block;
@ -7,7 +7,8 @@ import org.bukkit.Material;
import org.bukkit.World;
/**
* A collection of stuff to process data of move events
* A collection of methods that help to categorize blocks and find out if a
* player at a specific location can be considered "standing" or "swimming".
*
* @author Evenprime
*
@ -49,11 +50,12 @@ public class MovingEventHelper {
}
}
// Special types just for me
// Some exceptions
types[Material.LADDER.getId()] = LADDER;
types[Material.FENCE.getId()] = FENCE;
// Some exceptions
types[Material.WALL_SIGN.getId()] = NONSOLID;
types[Material.DIODE_BLOCK_ON.getId()] |= SOLID | NONSOLID;
types[Material.DIODE_BLOCK_OFF.getId()] |= SOLID | NONSOLID;
types[Material.WOODEN_DOOR.getId()] |= SOLID | NONSOLID;
types[Material.IRON_DOOR_BLOCK.getId()] |= SOLID | NONSOLID;
types[Material.PISTON_EXTENSION.getId()] |= SOLID | NONSOLID;
@ -104,7 +106,8 @@ public class MovingEventHelper {
result = types[world.getBlockTypeIdAt(lowerX + 1, Y + 1, lowerZ + 1)] | types[world.getBlockTypeIdAt(lowerX, Y + 1, lowerZ + 1)] | types[world.getBlockTypeIdAt(lowerX + 1, Y + 1, lowerZ)];
if((result & LIQUID) != 0) {
return INGROUND | ONGROUND; // WaterElevators don't really count as "water"
return INGROUND | ONGROUND; // WaterElevators don't really count
// as "water"
}
}
return result;
@ -123,14 +126,14 @@ public class MovingEventHelper {
int standingIn = types[world.getBlockTypeIdAt(x, y, z)];
int headIn = types[world.getBlockTypeIdAt(x, y + 1, z)];
int result = 0;
// It's either liquid, or something else
if(isLiquid(standingIn) || isLiquid(headIn)) {
return LIQUID;
}
if(isLadder(standingIn) || isLadder(headIn)) {
return LADDER;
}
@ -158,10 +161,10 @@ public class MovingEventHelper {
return (value & LIQUID) == LIQUID;
}
private final boolean isNonSolid(int value) {
final boolean isNonSolid(int value) {
return((value & NONSOLID) == NONSOLID);
}
public final boolean isLadder(int value) {
return((value & LADDER) == LADDER);
}
@ -173,7 +176,7 @@ public class MovingEventHelper {
public boolean isInGround(int fromType) {
return isLadder(fromType) || isLiquid(fromType) || (fromType & INGROUND) == INGROUND;
}
/**
* Personal Rounding function to determine if a player is still touching a
* block or not
@ -214,5 +217,4 @@ public class MovingEventHelper {
return (int) (floor - d4);
}
}

View File

@ -0,0 +1,145 @@
package cc.co.evenprime.bukkit.nocheat.checks.moving;
import java.util.HashMap;
import java.util.Locale;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutor;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutorWithHistory;
import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* A simple NoClip check. It tries to identify players that walk into/through
* walls by remembering their last location and whenever they move into or
* through a wall (with their upper body), this check should identify it.
* EXPERIMENTAL!!
*
* @author Evenprime
*
*/
public class NoclipCheck {
private final double bodyHeight = 1.1;
private final ActionExecutor action;
public NoclipCheck(NoCheat plugin) {
this.action = new ActionExecutorWithHistory(plugin);
}
/**
* Calculate if and how much the player "failed" this check. The check
* should not modify any data
*
*/
public Location check(final Player player, final Location from, final Location to, final MovingEventHelper helper, final ConfigurationCache cc, final MovingData data) {
/*** THE CHECK ***/
Location current = from.clone();
final double distanceX = to.getX() - current.getX();
final double distanceY = to.getY() - current.getY();
final double distanceZ = to.getZ() - current.getZ();
current.setY(current.getY() + bodyHeight);
double distance = Math.abs(distanceX) > Math.abs(distanceY) ? (Math.abs(distanceX) > Math.abs(distanceZ) ? Math.abs(distanceX) : Math.abs(distanceZ)) : (Math.abs(distanceY) > Math.abs(distanceZ) ? Math.abs(distanceY) : Math.abs(distanceZ));
int steps = (int) (distance / 0.1) + 1;
double divideBy = distance * 10D;
final double stepX = distanceX / divideBy;
final double stepY = distanceY / divideBy;
final double stepZ = distanceZ / divideBy;
final World world = from.getWorld();
int oldX, oldY, oldZ;
int newX, newY, newZ;
if(Math.abs(data.noclipX - current.getBlockX()) > 1 || Math.abs(data.noclipY - current.getBlockY()) > 1 || Math.abs(data.noclipZ - current.getBlockZ()) > 1) {
oldX = newX = current.getBlockX();
oldY = newY = current.getBlockY();
oldZ = newZ = current.getBlockZ();
} else {
oldX = newX = data.noclipX;
oldY = newY = data.noclipY;
oldZ = newZ = data.noclipZ;
}
int violationLevel = 0;
for(int i = 0; i < steps; i++) {
newX = current.getBlockX();
newY = current.getBlockY();
newZ = current.getBlockZ();
final boolean xChanged = newX != oldX;
final boolean yChanged = newY != oldY;
final boolean zChanged = newZ != oldZ;
boolean failed = false;
// Looks scarier than it is
if(!failed && (xChanged || yChanged || zChanged)) {
failed = check(helper, world, newX, newY, newZ);
if(!failed && xChanged && (yChanged || zChanged)) {
failed = check(helper, world, oldX, newY, newZ);
}
if(!failed && yChanged && (xChanged || zChanged)) {
failed = check(helper, world, newX, oldY, newZ);
}
if(!failed && zChanged && (xChanged || yChanged)) {
failed = check(helper, world, newX, newY, oldZ);
}
oldX = newX;
oldY = newY;
oldZ = newZ;
}
// Determine if the block can be passed by the player
if(failed) {
violationLevel++;
}
current.add(stepX, stepY, stepZ);
}
if(violationLevel > 0) {
// Prepare some event-specific values for logging and custom
// actions
HashMap<String, String> params = new HashMap<String, String>();
params.put(LogAction.DISTANCE, String.format(Locale.US, "%.2f,%.2f,%.2f", to.getX() - from.getX(), to.getY() - from.getY(), to.getZ() - from.getZ()));
params.put(LogAction.LOCATION_TO, String.format(Locale.US, "%.2f,%.2f,%.2f", to.getX(), to.getY(), to.getZ()));
params.put(LogAction.CHECK, "noclip");
boolean cancelled = action.executeActions(player, cc.moving.noclipActions, violationLevel, params, cc);
if(cancelled) {
return new Location(from.getWorld(), data.noclipX + 0.5, data.noclipY - ((int) bodyHeight), data.noclipZ + 0.5, to.getPitch(), to.getYaw());
}
}
// We didn't cancel the noclipping, so store the new location
data.noclipX = newX;
data.noclipY = newY;
data.noclipZ = newZ;
return null;
}
private final boolean check(MovingEventHelper helper, World world, int x, int y, int z) {
if(y < 0 || y > 127) {
return false;
}
return !helper.isNonSolid(helper.types[world.getBlockAt(x, y, z).getTypeId()]);
}
}

View File

@ -0,0 +1,191 @@
package cc.co.evenprime.bukkit.nocheat.checks.moving;
import java.util.HashMap;
import java.util.Locale;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.Permissions;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutor;
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutorWithHistory;
import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* The counterpart to the FlyingCheck. People that are not allowed to fly at all
* get checked by this. It will try to identify when they are jumping, check if
* they aren't jumping too high or far, check if they aren't moving too fast on
* normal ground, while sneaking or while swimming.
*
* @author Evenprime
*
*/
public class RunningCheck {
private final static double maxBonus = 1D;
// How many move events can a player have in air before he is expected to
// lose altitude (or eventually land somewhere)
private final static int jumpingLimit = 6;
// How high may a player get compared to his last location with ground
// contact
private final static double jumpHeight = 1.35D;
private final ActionExecutor action;
public RunningCheck(NoCheat plugin) {
this.action = new ActionExecutorWithHistory(plugin);
}
public Location check(final Player player, final Location from, final Location to, final MovingEventHelper helper, final ConfigurationCache cc, final MovingData data) {
// Calculate some distances
final double xDistance = to.getX() - from.getX();
final double zDistance = to.getZ() - from.getZ();
final double horizontalDistance = Math.sqrt((xDistance * xDistance + zDistance * zDistance));
if(data.movingsetBackPoint == null) {
data.movingsetBackPoint = player.getLocation().clone();
}
// To know if a player "is on ground" is useful
final int fromType = helper.isLocationOnGround(from.getWorld(), from.getX(), from.getY(), from.getZ(), false);
final int toType = helper.isLocationOnGround(to.getWorld(), to.getX(), to.getY(), to.getZ(), false);
final boolean fromOnGround = helper.isOnGround(fromType);
final boolean fromInGround = helper.isInGround(fromType);
final boolean toOnGround = helper.isOnGround(toType);
final boolean toInGround = helper.isInGround(toType);
Location newToLocation = null;
double resultHoriz = Math.max(0.0D, checkHorizontal(player, helper.isLiquid(fromType) && helper.isLiquid(toType), horizontalDistance, cc, data));
double resultVert = Math.max(0.0D, checkVertical(from, fromOnGround, to, toOnGround, cc, data));
double result = (resultHoriz + resultVert) * 100;
// Slowly reduce the level with each event
data.movingViolationLevel *= 0.97;
if(result > 0) {
// Increment violation counter
data.movingViolationLevel += result;
// Prepare some event-specific values for logging and custom actions
HashMap<String, String> params = new HashMap<String, String>();
params.put(LogAction.DISTANCE, String.format(Locale.US, "%.2f,%.2f,%.2f", xDistance, to.getY() - from.getY(), zDistance));
params.put(LogAction.LOCATION_TO, String.format(Locale.US, "%.2f,%.2f,%.2f", to.getX(), to.getY(), to.getZ()));
if(resultHoriz > 0 && resultVert > 0)
params.put(LogAction.CHECK, "running/both");
else if(resultHoriz > 0)
params.put(LogAction.CHECK, "running/horizontal");
else if(resultVert > 0)
params.put(LogAction.CHECK, "running/vertical");
boolean cancel = action.executeActions(player, cc.moving.runningActions, (int) data.movingViolationLevel, params, cc);
// Was one of the actions a cancel? Then do it
if(cancel) {
newToLocation = data.movingsetBackPoint;
}
} else {
if((toInGround && from.getY() >= to.getY()) || helper.isLiquid(toType)) {
data.movingsetBackPoint = to.clone();
data.movingsetBackPoint.setY(Math.ceil(data.movingsetBackPoint.getY()));
data.jumpPhase = 0;
} else if(toOnGround && (from.getY() >= to.getY() || data.movingsetBackPoint.getY() <= Math.floor(to.getY()))) {
data.movingsetBackPoint = to.clone();
data.movingsetBackPoint.setY(Math.floor(data.movingsetBackPoint.getY()));
data.jumpPhase = 0;
} else if(fromOnGround || fromInGround || toOnGround || toInGround) {
data.jumpPhase = 0;
}
}
return newToLocation;
}
/**
* Calculate how much the player failed this check
*
* @param isSneaking
* @param isSwimming
* @param totalDistance
* @param cc
* @param data
* @return
*/
private double checkHorizontal(final Player player, final boolean isSwimming, final double totalDistance, final ConfigurationCache cc, final MovingData data) {
// How much further did the player move than expected??
double distanceAboveLimit = 0.0D;
if(cc.moving.sneakingCheck && player.isSneaking() && !player.hasPermission(Permissions.MOVE_SNEAK)) {
distanceAboveLimit = totalDistance - cc.moving.sneakingSpeedLimit - data.horizFreedom;
} else if(cc.moving.swimmingCheck && isSwimming && !player.hasPermission(Permissions.MOVE_SWIM)) {
distanceAboveLimit = totalDistance - cc.moving.swimmingSpeedLimit - data.horizFreedom;
} else {
distanceAboveLimit = totalDistance - cc.moving.runningSpeedLimit - data.horizFreedom;
}
// Did he go too far?
if(distanceAboveLimit > 0) {
// Try to consume the "buffer"
distanceAboveLimit -= data.horizontalBuffer;
data.horizontalBuffer = 0;
// Put back the "overconsumed" buffer
if(distanceAboveLimit < 0) {
data.horizontalBuffer = -distanceAboveLimit;
}
}
// He was within limits, give the difference as buffer
else {
data.horizontalBuffer = Math.min(maxBonus, data.horizontalBuffer - distanceAboveLimit);
}
return distanceAboveLimit;
}
/**
* Calculate if and how much the player "failed" this check.
*
*/
private double checkVertical(final Location from, final boolean fromOnGround, final Location to, final boolean toOnGround, final ConfigurationCache cc, final MovingData data) {
// How much higher did the player move than expected??
double distanceAboveLimit = 0.0D;
final double toY = to.getY();
final double fromY = from.getY();
double limit = data.vertFreedom + jumpHeight;
final Location l;
if(fromY - toY > 0.5D) {
distanceAboveLimit = 0;
data.jumpPhase++;
} else {
if(data.movingsetBackPoint == null)
l = from;
else
l = data.movingsetBackPoint;
if(data.jumpPhase > jumpingLimit) {
limit -= (data.jumpPhase - jumpingLimit) * 0.15D;
}
distanceAboveLimit = toY - l.getY() - limit;
}
return distanceAboveLimit;
}
}

View File

@ -1,30 +0,0 @@
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;
}
}

View File

@ -1,27 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.config;
import cc.co.evenprime.bukkit.nocheat.wizard.gui.Explainations;
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";
}
@Override
public String toDescriptionString(String prefix) {
return prefix + getIdentifier() + ": \"" + Explainations.get(getFullIdentifier()).replace("\n", "\r\n" + prefix + "\t\t") + "\"\r\n";
}
}

View File

@ -0,0 +1,24 @@
package cc.co.evenprime.bukkit.nocheat.config;
import cc.co.evenprime.bukkit.nocheat.actions.ActionList;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
/**
* A configuration. It should allow access to settings associated with a string
*
* @author Evenprime
*
*/
public interface Configuration {
public abstract boolean getBoolean(String string);
public abstract ActionList getActionList(String string);
public abstract int getInteger(String string);
public abstract String getString(String string);
public abstract LogLevel getLogLevel(String string);
}

View File

@ -0,0 +1,403 @@
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.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import cc.co.evenprime.bukkit.nocheat.DefaultConfiguration;
import cc.co.evenprime.bukkit.nocheat.actions.ActionManager;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.config.tree.ActionListOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ChildOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationTree;
import cc.co.evenprime.bukkit.nocheat.config.tree.Option;
import cc.co.evenprime.bukkit.nocheat.config.tree.ParentOption;
import cc.co.evenprime.bukkit.nocheat.file.DescriptionGenerator;
import cc.co.evenprime.bukkit.nocheat.file.FlatActionParser;
import cc.co.evenprime.bukkit.nocheat.file.FlatConfigGenerator;
import cc.co.evenprime.bukkit.nocheat.file.FlatConfigParser;
/**
* Central location for everything that's described in the configuration file(s)
*
* @author Evenprime
*
*/
public class ConfigurationManager {
private final static String configFileName = "config.txt";
private final static String actionFileName = "actions.txt";
private final static String defaultActionFileName = "default_actions.txt";
private final static String descriptionsFileName = "descriptions.txt";
public final static String rootConfigFolder = "plugins/NoCheat/";
private final Map<String, ConfigurationCache> worldnameToConfigCacheMap = new HashMap<String, ConfigurationCache>();
// Only use one filehandler per file, therefore keep open filehandlers in a
// map
private final Map<File, FileHandler> fileToFileHandlerMap = new HashMap<File, FileHandler>();
private final ConfigurationTree defaultTree = DefaultConfiguration.buildDefaultConfigurationTree();
private class LogFileFormatter extends Formatter {
private final SimpleDateFormat date;
public LogFileFormatter() {
date = new SimpleDateFormat("yy.MM.dd HH:mm:ss");
}
@Override
public String format(LogRecord record) {
StringBuilder builder = new StringBuilder();
Throwable ex = record.getThrown();
builder.append(date.format(record.getMillis()));
builder.append(" [");
builder.append(record.getLevel().getLocalizedName().toUpperCase());
builder.append("] ");
builder.append(record.getMessage());
builder.append('\n');
if(ex != null) {
StringWriter writer = new StringWriter();
ex.printStackTrace(new PrintWriter(writer));
builder.append(writer);
}
return builder.toString();
}
}
// Our personal logger
// private final static String loggerName = "cc.co.evenprime.nocheat";
// public final Logger logger = Logger.getLogger(loggerName);
public ConfigurationManager(String rootConfigFolder, ActionManager action) {
// Parse actions file
initializeActions(rootConfigFolder, action);
// Setup the configuration tree
initializeConfig(rootConfigFolder, action);
}
public void initializeActions(String rootConfigFolder, ActionManager action) {
FlatActionParser parser = new FlatActionParser();
DefaultConfiguration.writeDefaultActionFile(new File(rootConfigFolder, defaultActionFileName));
parser.read(action, new File(rootConfigFolder, defaultActionFileName));
parser.read(action, new File(rootConfigFolder, actionFileName));
}
/**
* Read the configuration file and assign either standard values or whatever
* is declared in the file
*
* @param configurationFile
*/
private void initializeConfig(String rootConfigFolder, ActionManager actionManager) {
// First try to obtain and parse the global config file
ConfigurationTree root;
File globalConfigFile = getGlobalConfigFile(rootConfigFolder);
try {
root = createFullConfigurationTree(defaultTree, globalConfigFile);
} catch(Exception e) {
root = DefaultConfiguration.buildDefaultConfigurationTree();
}
writeConfigFile(globalConfigFile, root);
// Create a corresponding Configuration Cache
// put the global config on the config map
worldnameToConfigCacheMap.put(null, new ConfigurationCache(root, setupFileLogger(new File(root.getString("logging.filename")))));
// Try to find world-specific config files
Map<String, File> worldFiles = getWorldSpecificConfigFiles(rootConfigFolder);
for(String worldName : worldFiles.keySet()) {
File worldConfigFile = worldFiles.get(worldName);
try {
ConfigurationTree world = createPartialConfigurationTree(root, worldConfigFile);
worldnameToConfigCacheMap.put(worldName, createConfigurationCache(world));
// write the config file back to disk immediately
writeConfigFile(worldFiles.get(worldName), world);
} catch(IOException e) {
System.out.println("NoCheat: Couldn't load world-specific config for " + worldName);
}
}
// Write the descriptions-file for the default tree
writeDescriptionFile(new File(rootConfigFolder, descriptionsFileName), defaultTree);
}
private ConfigurationCache createConfigurationCache(Configuration configProvider) {
return new ConfigurationCache(configProvider, setupFileLogger(new File(configProvider.getString("logging.filename"))));
}
public static File getGlobalConfigFile(String rootFolder) {
File globalConfig = new File(rootFolder, configFileName);
return globalConfig;
}
public static Map<String, File> getWorldSpecificConfigFiles(String rootConfigFolder) {
HashMap<String, File> files = new HashMap<String, File>();
File rootFolder = new File(rootConfigFolder);
if(rootFolder.isDirectory()) {
for(File f : rootFolder.listFiles()) {
if(f.isFile()) {
String filename = f.getName();
if(filename.matches(".+_" + configFileName + "$")) {
// Get the first part = world name
String worldname = filename.substring(0, filename.length() - (configFileName.length() + 1));
files.put(worldname, f);
}
}
}
}
return files;
}
/**
* Create a full configuration tree based on a default tree and a
* configuration file
* The resulting tree will have all settings of the defaultTree with entries
* replaced,
* if existing, by data from the configurationFile
*
* @param defaultTree
* @param configurationFile
* @throws IOException
*/
public static ConfigurationTree createFullConfigurationTree(ConfigurationTree defaultTree, File configurationFile) throws IOException {
return yamlToTree(defaultTree, configurationFile, true);
}
/**
* Create a partial configuration tree based on a default tree and a
* configuration file
* The resulting tree will only have settings from the configurationFile,
* but reference
* the defaultTree as its parent.
*
* @param defaultTree
* @param configurationFile
* @throws IOException
*/
public static ConfigurationTree createPartialConfigurationTree(ConfigurationTree defaultTree, File configurationFile) throws IOException {
ConfigurationTree tree = yamlToTree(defaultTree, configurationFile, false);
tree.setParent(defaultTree);
return tree;
}
private static ConfigurationTree yamlToTree(ConfigurationTree defaults, File configurationFile, boolean fullCopy) throws IOException {
FlatConfigParser source = new FlatConfigParser();
source.read(configurationFile);
ConfigurationTree partial = new ConfigurationTree();
for(Option o : defaults.getAllOptions()) {
if(o instanceof ActionListOption) {
ActionListOption o2 = ((ActionListOption) o).clone();
partial.add(o.getParent().getFullIdentifier(), o2);
// Does the new source have a node for this property??
Object prop = source.getProperty(o2.getFullIdentifier());
if(prop instanceof Map<?, ?> && prop != null) {
// Yes, so we rather take the data from that node
@SuppressWarnings("unchecked")
Map<Object, Object> m = (Map<Object, Object>) prop;
o2.clear();
for(Entry<Object, Object> entry : m.entrySet()) {
try {
o2.add(Integer.parseInt((String) entry.getKey()), (String) entry.getValue());
} catch(Exception e) {
System.out.println("NoCheat: PROBLEM OFFICER?!?!");
}
}
}
if(!fullCopy && prop == null) {
o2.setActive(false);
}
} else if(o instanceof ParentOption) {
ParentOption o2 = new ParentOption(o.getIdentifier());
partial.add(o.getParent().getFullIdentifier(), o2);
} else if(o instanceof ChildOption) {
ChildOption o2 = ((ChildOption) o).clone();
partial.add(o.getParent().getFullIdentifier(), o2);
o2.setStringValue(source.getString(o2.getFullIdentifier(), o2.getStringValue()));
if(!fullCopy && source.getProperty(o.getFullIdentifier()) == null) {
o2.setActive(false);
}
}
}
return partial;
}
private Logger setupFileLogger(File logfile) {
FileHandler fh = fileToFileHandlerMap.get(logfile);
if(fh == null) {
try {
fh = new FileHandler(logfile.getCanonicalPath(), true);
// We decide before logging what gets logged there anyway
// because different worlds may use this filehandler and
// therefore may need to log different message levels
fh.setLevel(Level.ALL);
fh.setFormatter(new LogFileFormatter());
fileToFileHandlerMap.put(logfile, fh);
} catch(SecurityException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
}
// this logger will be used ONLY for logging to a single log-file and
// only
// in this plugin, therefore it doesn't need any namespace
Logger l = Logger.getAnonymousLogger();
l.setLevel(Level.INFO);
// Ignore parent's settings
l.setUseParentHandlers(false);
l.addHandler(fh);
return l;
}
/**
* Reset the loggers and flush and close the fileHandlers
* to be able to use them next time without problems
*/
public void cleanup() {
// Remove handlers from the logger
for(ConfigurationCache c : worldnameToConfigCacheMap.values()) {
for(Handler h : c.logging.filelogger.getHandlers()) {
c.logging.filelogger.removeHandler(h);
}
}
// Close all file handlers
for(FileHandler fh : fileToFileHandlerMap.values()) {
fh.flush();
fh.close();
}
}
/**
* Write configuration to specific file
*
* @param f
*/
public static void writeConfigFile(File f, ConfigurationTree configuration) {
try {
if(f.getParentFile() != null)
f.getParentFile().mkdirs();
f.createNewFile();
BufferedWriter w = new BufferedWriter(new FileWriter(f));
w.write(FlatConfigGenerator.treeToFlatFile(configuration));
w.flush();
w.close();
} catch(IOException e) {
e.printStackTrace();
}
}
/**
* Write a file with the descriptions of all options of a specific
* configuration tree
*
* @param f
*/
public static void writeDescriptionFile(File f, ConfigurationTree configuration) {
try {
if(f.getParentFile() != null)
f.getParentFile().mkdirs();
f.createNewFile();
BufferedWriter w = new BufferedWriter(new FileWriter(f));
w.write(DescriptionGenerator.treeToDescription(configuration));
w.flush();
w.close();
} catch(IOException e) {
e.printStackTrace();
}
}
/**
* Get the cache of the specified world, or the default cache,
* if no cache exists for that world.
*
* @param worldname
* @return
*/
public ConfigurationCache getConfigurationCacheForWorld(String worldname) {
ConfigurationCache cache = worldnameToConfigCacheMap.get(worldname);
if(cache != null) {
return cache;
} else {
// Enter a reference to the cache under the new name
// to be faster in looking it up later
cache = worldnameToConfigCacheMap.get(null);
worldnameToConfigCacheMap.put(worldname, cache);
return cache;
}
}
public static File getDescriptionFile(String rootConfigFolder) {
return new File(rootConfigFolder, descriptionsFileName);
}
public static File getDefaultActionFile(String rootConfigFolder) {
return new File(rootConfigFolder, defaultActionFileName);
}
public static File getActionFile(String rootConfigFolder) {
return new File(rootConfigFolder, actionFileName);
}
}

View File

@ -1,79 +0,0 @@
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;
}
}

View File

@ -1,78 +0,0 @@
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 final String description;
private final 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();
}
}

View File

@ -1,13 +0,0 @@
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);
}
}

View File

@ -1,13 +0,0 @@
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);
}
}

View File

@ -1,445 +0,0 @@
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.LogFileFormatter;
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";
public final static String descriptionsFile = "plugins/NoCheat/descriptions.txt";
private ParentOption root;
private final Map<String, Action> actionMap = new HashMap<String, Action>();
private Map<String, Object> yamlContent = new HashMap<String, Object>();
// 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, File descriptionsFile) {
// Setup the configuration tree
config(configurationFile, descriptionsFile);
}
/**
* Read the configuration file and assign either standard values or whatever
* is declared in the file
*
* @param configurationFile
*/
public void config(File configurationFile, File descriptionsFile) {
try {
yamlContent = (Map<String, Object>) SimpleYaml.read(configurationFile);
} catch(Exception e) {
System.out.println("Couldn't use existing nocheat.yml, creating a new file.");
yamlContent = new HashMap<String, Object>();
}
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)));
}
root.add(new BooleanOption("newpermsystem", SimpleYaml.getBoolean("newpermsystem", false, yamlContent)));
root.add(new BooleanOption("showinfomessages", SimpleYaml.getBoolean("showinfomessages", true, 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("bogusitems", SimpleYaml.getBoolean("active.bogusitems", false, yamlContent)));
activeNode.add(new BooleanOption("nuke", SimpleYaml.getBoolean("active.nuke", false, yamlContent)));
activeNode.add(new BooleanOption("infinitedurability", SimpleYaml.getBoolean("active.infinitedurability", true, yamlContent)));
}
/*** SPEEDHACK section ***/
{
ParentOption speedhackNode = new ParentOption("speedhack", false);
root.add(speedhackNode);
speedhackNode.add(new LongStringOption("logmessage", SimpleYaml.getString("speedhack.logmessage", "[player] sent [events] move events, but only [limit] were allowed. Speedhack?", yamlContent)));
speedhackNode.add(new BooleanOption("checkops", SimpleYaml.getBoolean("speedhack.checkops", false, yamlContent)));
/*** SPEEDHACK LIMITS section ***/
{
ParentOption speedhackLimitsNode = new ParentOption("limits", false);
speedhackNode.add(speedhackLimitsNode);
speedhackLimitsNode.add(new IntegerOption("low", SimpleYaml.getInt("speedhack.limits.low", 22, yamlContent)));
speedhackLimitsNode.add(new IntegerOption("med", SimpleYaml.getInt("speedhack.limits.med", 33, yamlContent)));
speedhackLimitsNode.add(new IntegerOption("high", SimpleYaml.getInt("speedhack.limits.high", 44, 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: [player] from [world] [from] to [to] distance [distance]", yamlContent)));
movingNode.add(new LongStringOption("summarymessage", SimpleYaml.getString("moving.summarymessage", "Moving summary of last ~[timeframe] seconds: [player] total Violations: [violations]", yamlContent)));
movingNode.add(new IntegerOption("summaryafter", SimpleYaml.getInt("moving.summaryafter", 15, yamlContent)));
movingNode.add(new BooleanOption("allowflying", SimpleYaml.getBoolean("moving.allowflying", false, yamlContent)));
movingNode.add(new BooleanOption("allowfakesneak", SimpleYaml.getBoolean("moving.allowfakesneak", true, yamlContent)));
movingNode.add(new BooleanOption("allowfastswim", SimpleYaml.getBoolean("moving.allowfastswim", false, yamlContent)));
movingNode.add(new BooleanOption("waterelevators", SimpleYaml.getBoolean("moving.waterelevators", false, yamlContent)));
movingNode.add(new BooleanOption("checkops", SimpleYaml.getBoolean("moving.checkops", false, yamlContent)));
movingNode.add(new BooleanOption("enforceteleport", SimpleYaml.getBoolean("moving.enforceteleport", true, yamlContent)));
/*** MOVING LIMITS section ***/
{
ParentOption movingLimitsNode = new ParentOption("limits", false);
movingNode.add(movingLimitsNode);
movingLimitsNode.add(new IntegerOption("walking", SimpleYaml.getInt("moving.limits.walking", 22, yamlContent)));
movingLimitsNode.add(new IntegerOption("sneaking", SimpleYaml.getInt("moving.limits.sneaking", 14, yamlContent)));
movingLimitsNode.add(new IntegerOption("swimming", SimpleYaml.getInt("moving.limits.swimming", 18, 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);
airbuildNode.add(new BooleanOption("checkops", SimpleYaml.getBoolean("airbuild.checkops", false, yamlContent)));
/*** 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)));
}
}
/*** BOGUSITEMS section ***/
{
ParentOption bogusitemsNode = new ParentOption("bogusitems", false);
root.add(bogusitemsNode);
bogusitemsNode.add(new BooleanOption("checkops", SimpleYaml.getBoolean("bogusitems.checkops", false, yamlContent)));
}
/*** NUKE section ***/
{
ParentOption nukeNode = new ParentOption("nuke", false);
root.add(nukeNode);
nukeNode.add(new BooleanOption("checkops", SimpleYaml.getBoolean("nuke.checkops", false, yamlContent)));
nukeNode.add(new LongStringOption("logmessage", SimpleYaml.getString("nuke.logmessage", "Nuke: [player] tried to nuke the world", yamlContent)));
nukeNode.add(new LongStringOption("kickmessage", SimpleYaml.getString("nuke.kickmessage", "No nuking allowed", yamlContent)));
nukeNode.add(new BooleanOption("limitreach", SimpleYaml.getBoolean("nuke.limitreach", true, yamlContent)));
}
/*** INFINITE_DURABILITY section ***/
{
ParentOption nukeNode = new ParentOption("infinitedurability", false);
root.add(nukeNode);
nukeNode.add(new BooleanOption("checkops", SimpleYaml.getBoolean("infinitedurability.checkops", false, yamlContent)));
nukeNode.add(new LongStringOption("logmessage", SimpleYaml.getString("infinitedurability.logmessage", "InfDur: [player] tries to use an infinite durability hack", yamlContent)));
nukeNode.add(new LongStringOption("kickmessage", SimpleYaml.getString("infinitedurability.kickmessage", "No infinite durability hacks allowed", yamlContent)));
nukeNode.add(new BooleanOption("log", SimpleYaml.getBoolean("infinitedurability.log", true, yamlContent)));
nukeNode.add(new BooleanOption("kick", SimpleYaml.getBoolean("infinitedurability.kick", true, yamlContent)));
nukeNode.add(new BooleanOption("cancel", SimpleYaml.getBoolean("infinitedurability.cancel", true, yamlContent)));
}
/*** CUSTOMACTIONS section ***/
{
ParentOption customActionsNode = new ParentOption("customactions", true);
root.add(customActionsNode);
Set<String> 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());
}
}
writeConfigFile(configurationFile, this);
writeDescriptionFile(descriptionsFile, 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(new LogFileFormatter());
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();
}
}
}
private Action[] stringToActions(String string) {
List<Action> as = new LinkedList<Action>();
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();
}
}
/**
* Write a file with the descriptions of all options
*
* @param f
*/
private static void writeDescriptionFile(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().toDescriptionString(""));
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();
}
private 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();
}
private 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();
}
private 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();
}
private 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<String> l = new LinkedList<String>();
for(String s : optionName.split("\\.")) {
l.addLast(s);
}
return getOption(root, l);
}
private Option getOption(Option parent, LinkedList<String> 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;
}
}

View File

@ -1,78 +0,0 @@
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 final LinkedList<Option> children = new LinkedList<Option>();
private final boolean editable;
public ParentOption(String identifier, boolean editable) {
super(identifier);
this.editable = editable;
}
public final Collection<Option> getChildOptions() {
return Collections.unmodifiableCollection(children);
}
public final void add(Option option) {
children.addLast(option);
option.setParent(this);
}
public final void remove(Option option) {
if(editable)
children.remove(option);
}
public boolean isEditable() {
return editable;
}
@Override
public String toYAMLString(String prefix) {
String s = "";
if(getIdentifier().length() > 0) {
s += prefix + getIdentifier() + ":\r\n";
for(Option o : getChildOptions()) {
s += o.toYAMLString(prefix + " ");
}
} else {
for(Option o : getChildOptions()) {
s += o.toYAMLString(prefix);
}
}
return s;
}
@Override
public String toDescriptionString(String prefix) {
String s = "";
if(getIdentifier().length() > 0) {
s += prefix + getIdentifier() + ":\r\n";
for(Option o : getChildOptions()) {
s += o.toDescriptionString(prefix + " ");
}
} else {
for(Option o : getChildOptions()) {
s += o.toDescriptionString(prefix);
}
}
return s;
}
}

View File

@ -1,13 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.config;
public class ShortStringOption extends TextFieldOption {
/**
*
*/
private static final long serialVersionUID = 2258827414736580449L;
public ShortStringOption(String name, String initialValue) {
super(name, initialValue, 10);
}
}

View File

@ -0,0 +1,32 @@
package cc.co.evenprime.bukkit.nocheat.config.cache;
import cc.co.evenprime.bukkit.nocheat.actions.ActionList;
import cc.co.evenprime.bukkit.nocheat.config.Configuration;
/**
* Configurations specific for the "BlockBreak" checks
* Every world gets one of these assigned to it.
*
* @author Evenprime
*
*/
public class CCBlockBreak {
public final boolean check;
public final boolean reachCheck;
public final double reachDistance;
public final ActionList reachActions;
public final boolean directionCheck;
public final ActionList directionActions;
public CCBlockBreak(Configuration data) {
check = data.getBoolean("blockbreak.check");
reachCheck = data.getBoolean("blockbreak.reach.check");
reachDistance = ((double) data.getInteger("blockbreak.reach.reachlimit")) / 100D;
reachActions = data.getActionList("blockbreak.reach.actions");
directionCheck = data.getBoolean("blockbreak.direction.check");
directionActions = data.getActionList("blockbreak.direction.actions");
}
}

View File

@ -0,0 +1,31 @@
package cc.co.evenprime.bukkit.nocheat.config.cache;
import java.util.logging.Logger;
import cc.co.evenprime.bukkit.nocheat.config.Configuration;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
/**
* Configurations specific for logging. Every world gets one of these.
*
* @author Evenprime
*
*/
public class CCLogging {
public final LogLevel fileLevel;
public final LogLevel consoleLevel;
public final LogLevel chatLevel;
public final Logger filelogger;
public final boolean active;
public CCLogging(Configuration data, Logger worldSpecificFileLogger) {
active = data.getBoolean("logging.active");
fileLevel = data.getLogLevel("logging.filelevel");
consoleLevel = data.getLogLevel("logging.consolelevel");
chatLevel = data.getLogLevel("logging.chatlevel");
filelogger = worldSpecificFileLogger;
}
}

View File

@ -0,0 +1,63 @@
package cc.co.evenprime.bukkit.nocheat.config.cache;
import cc.co.evenprime.bukkit.nocheat.actions.ActionList;
import cc.co.evenprime.bukkit.nocheat.config.Configuration;
/**
* Configurations specific for the Move Checks. Every world gets one of these
* assigned to it.
*
* @author Evenprime
*
*/
public class CCMoving {
public final boolean check;
public final boolean flyingCheck;
public final double flyingSpeedLimitVertical;
public final double flyingSpeedLimitHorizontal;
public final ActionList flyingActions;
public final boolean runningCheck;
public final double runningSpeedLimit;
public final ActionList runningActions;
public final boolean swimmingCheck;
public final double swimmingSpeedLimit;
public final boolean sneakingCheck;
public final double sneakingSpeedLimit;
public final boolean noclipCheck;
public final ActionList noclipActions;
public final boolean morePacketsCheck;
public final ActionList morePacketsActions;
public CCMoving(Configuration data) {
check = data.getBoolean("moving.check");
flyingCheck = data.getBoolean("moving.flying.check");
flyingSpeedLimitVertical = ((double) data.getInteger("moving.flying.speedlimitvertical")) / 100D;
flyingSpeedLimitHorizontal = ((double) data.getInteger("moving.flying.speedlimithorizontal")) / 100D;
flyingActions = data.getActionList("moving.flying.actions");
runningCheck = data.getBoolean("moving.running.check");
runningSpeedLimit = ((double) data.getInteger("moving.running.speedlimit")) / 100D;
runningActions = data.getActionList("moving.running.actions");
swimmingCheck = data.getBoolean("moving.running.swimming.check");
swimmingSpeedLimit = ((double) data.getInteger("moving.running.swimming.speedlimit")) / 100D;
sneakingCheck = data.getBoolean("moving.running.sneaking.check");
sneakingSpeedLimit = ((double) data.getInteger("moving.running.sneaking.speedlimit")) / 100D;
noclipCheck = data.getBoolean("moving.noclip.check");
noclipActions = data.getActionList("moving.noclip.actions");
morePacketsCheck = data.getBoolean("moving.morepackets.check");
morePacketsActions = data.getActionList("moving.morepackets.actions");
}
}

View File

@ -0,0 +1,32 @@
package cc.co.evenprime.bukkit.nocheat.config.cache;
import java.util.logging.Logger;
import cc.co.evenprime.bukkit.nocheat.config.Configuration;
/**
* A class to keep all configurables of the plugin associated with
* a world, everything unmodifiable.
*
* @author Evenprime
*
*/
public class ConfigurationCache {
public final CCMoving moving;
public final CCLogging logging;
public final CCBlockBreak blockbreak;
/**
* Instantiate a config cache and populate it with the data of a
* Config tree (and its parent tree)
*
* @param data
*/
public ConfigurationCache(Configuration data, Logger worldSpecificFileLogger) {
moving = new CCMoving(data);
blockbreak = new CCBlockBreak(data);
logging = new CCLogging(data, worldSpecificFileLogger);
}
}

View File

@ -0,0 +1,50 @@
package cc.co.evenprime.bukkit.nocheat.config.tree;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* A special node of the configuration tree
*
* @author Evenprime
*
*/
public class ActionListOption extends ChildOption {
private final LinkedList<ActionOption> actionOptions = new LinkedList<ActionOption>();
public ActionListOption(String identifier) {
super(identifier);
}
public void add(Integer treshold, String actions) {
actionOptions.add(new ActionOption(treshold, actions));
Collections.sort(actionOptions);
}
public List<ActionOption> getChildOptions() {
return actionOptions;
}
public void remove(ActionOption actionOption) {
this.actionOptions.remove(actionOption);
}
@Override
public ActionListOption clone() {
ActionListOption o = new ActionListOption(this.getIdentifier());
for(ActionOption ao : getChildOptions()) {
o.add(ao.getTreshold(), ao.getStringValue());
}
return o;
}
public void clear() {
actionOptions.clear();
}
}

View File

@ -0,0 +1,73 @@
package cc.co.evenprime.bukkit.nocheat.config.tree;
/**
* A special node of the configuration tree
*
* @author Evenprime
*
*/
public class ActionOption extends ChildOption implements Comparable<ActionOption> {
private int treshold;
private String value;
public ActionOption(Integer treshold, String value) {
super(treshold.toString());
this.treshold = treshold;
this.value = value;
}
@Override
public String getStringValue() {
return value;
}
@Override
public boolean setStringValue(String value) {
this.value = value;
return true;
}
/**
* It is recommended to take further action if the treshold
* gets changed: If successful, "clone()" this object and
* replace the original with it.
*
* @param treshold
* @return
*/
public boolean setTreshold(String treshold) {
try {
this.treshold = Integer.parseInt(treshold);
return true;
} catch(NumberFormatException e) {
return false;
}
}
public int getTreshold() {
return treshold;
}
@Override
public ActionOption clone() {
return new ActionOption(treshold, value);
}
@Override
public int compareTo(ActionOption o) {
if(treshold < o.treshold) {
return -1;
} else if(treshold == o.treshold) {
return 0;
} else
return 1;
}
public String toString() {
return "ActionOption " + getFullIdentifier() + " " + getStringValue();
}
}

View File

@ -0,0 +1,65 @@
package cc.co.evenprime.bukkit.nocheat.config.tree;
/**
* A node of the configuration tree
*
* @author Evenprime
*
*/
public class BooleanOption extends ChildOption {
/**
*
*/
private static final long serialVersionUID = 2258827414736580449L;
private boolean value;
private boolean isMaster = false;
public BooleanOption(String name, boolean initialValue, boolean isMaster) {
super(name);
this.value = initialValue;
this.isMaster = isMaster;
}
public void setBooleanValue(boolean value) {
this.value = value;
}
@Override
public String getStringValue() {
return Boolean.toString(value);
}
@Override
public boolean setStringValue(String value) {
try {
this.value = Boolean.parseBoolean(value);
return true;
} catch(Exception e) {
return false;
}
}
public boolean getBooleanValue() {
return value;
}
@Override
public BooleanOption clone() {
return new BooleanOption(this.getIdentifier(), value, isMaster);
}
public boolean isMaster() {
return isMaster;
}
public void setMaster(boolean master) {
this.isMaster = master;
}
public String toString() {
return "BooleanOption " + this.getFullIdentifier() + " " + getStringValue() + (isMaster ? " master" : "");
}
}

View File

@ -0,0 +1,32 @@
package cc.co.evenprime.bukkit.nocheat.config.tree;
/**
* A leaf of the configuration tree
*
* @author Evenprime
*
*/
public abstract class ChildOption extends Option implements Cloneable {
/**
*
*/
private static final long serialVersionUID = -4648294833934457776L;
private String value;
public ChildOption(String identifier) {
super(identifier);
}
public String getStringValue() {
return value;
}
public boolean setStringValue(String string) {
this.value = string;
return true;
}
public abstract ChildOption clone();
}

View File

@ -0,0 +1,239 @@
package cc.co.evenprime.bukkit.nocheat.config.tree;
import java.util.ArrayList;
import java.util.List;
import cc.co.evenprime.bukkit.nocheat.actions.ActionList;
import cc.co.evenprime.bukkit.nocheat.config.Configuration;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
/**
* Only used during parsing of the configuration files and for the GUI wizard
*
* @author Evenprime
*
*/
public class ConfigurationTree implements Configuration {
// Each tree has a root option that does nothing
private final ParentOption root = new ParentOption("");
// Each tree can have a "parent" tree
private ConfigurationTree parent = null;
/**
* Start a new tree
*
* @param parent
*/
public ConfigurationTree() {}
public void setParent(ConfigurationTree parent) {
this.parent = parent;
}
public ConfigurationTree getParent() {
return parent;
}
/**
* Get a specific option from this tree or its parent(s), if this
* tree doesn't contain this option
*
* @param fullIdentifier
* @return
*/
private Option getOptionRecursive(String fullIdentifier) {
// Find out the partial identifiers
String[] identifiers = fullIdentifier.split("\\.");
// Start at the root
Option o = root;
// Go through all partial identifiers
for(int i = 0; i < identifiers.length; i++) {
if(o instanceof ParentOption) {
for(Option o2 : ((ParentOption) o).getChildOptions()) {
if(o2.getIdentifier().equals(identifiers[i])) {
o = o2;
break;
}
}
} else
break;
}
// Does the node we last met match our searched node and is it enabled?
if(o.getFullIdentifier().equals(fullIdentifier) && o.isActive()) {
return o;
}
// No, then ask our parent (if possible)
else if(parent != null) {
return parent.getOptionRecursive(fullIdentifier);
} else {
return null;
}
}
/**
* Get a specific option from this tree
*
* @param fullIdentifier
* @return
*/
public Option getOption(String fullIdentifier) {
// Find out the partial identifiers
String[] identifiers = fullIdentifier.split("\\.");
// Start at the root
Option o = root;
// Go through all partial identifiers
for(int i = 0; i < identifiers.length; i++) {
if(o instanceof ParentOption) {
for(Option o2 : ((ParentOption) o).getChildOptions()) {
if(o2.getIdentifier().equals(identifiers[i])) {
o = o2;
break;
}
}
} else
break;
}
// Does the node we last met match our searched node?
if(o.getFullIdentifier().equals(fullIdentifier)) {
return o;
} else {
return null;
}
}
/**
* Add a option to this tree, at the specified parent
*
* @param parent
* @param option
*/
public void add(String parent, Option option) {
try {
if(parent == null || parent == "") {
add(option);
} else {
ParentOption po = (ParentOption) getOption(parent);
po.add(option);
}
} catch(Exception e) {
e.printStackTrace();
}
}
/**
* Add a option at the root
*
* @param option
*/
public void add(Option option) {
root.add(option);
}
/**
*
* @return
*/
public List<Option> getAllOptions() {
List<Option> options = new ArrayList<Option>();
ParentOption o = root;
for(Option o2 : o.getChildOptions()) {
if(o2.isActive()) {
options.addAll(getAllOptions(o2));
}
}
return options;
}
private List<Option> getAllOptions(Option subtree) {
List<Option> options = new ArrayList<Option>();
options.add(subtree);
if(subtree instanceof ParentOption) {
for(Option child : ((ParentOption) subtree).getChildOptions()) {
options.addAll(getAllOptions(child));
}
}
return options;
}
/*
* (non-Javadoc)
*
* @see
* cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationProvider#getBoolean
* (java.lang.String)
*/
@Override
public boolean getBoolean(String string) {
return ((BooleanOption) this.getOptionRecursive(string)).getBooleanValue();
}
/*
* (non-Javadoc)
*
* @see cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationProvider#
* getActionList(java.lang.String)
*/
@Override
public ActionList getActionList(String string) {
ActionList actionList = new ActionList();
ActionListOption option = (ActionListOption) this.getOptionRecursive(string);
for(ActionOption ao : option.getChildOptions()) {
actionList.addEntry(ao.getTreshold(), ao.getStringValue().split(" "));
}
return actionList;
}
/*
* (non-Javadoc)
*
* @see
* cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationProvider#getInteger
* (java.lang.String)
*/
@Override
public int getInteger(String string) {
return ((IntegerOption) this.getOptionRecursive(string)).getIntegerValue();
}
/*
* (non-Javadoc)
*
* @see
* cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationProvider#getString
* (java.lang.String)
*/
@Override
public String getString(String string) {
return ((ChildOption) this.getOptionRecursive(string)).getStringValue();
}
/*
* (non-Javadoc)
*
* @see
* cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationProvider#getLogLevel
* (java.lang.String)
*/
@Override
public LogLevel getLogLevel(String string) {
return ((LogLevelOption) this.getOptionRecursive(string)).getLogLevelValue();
}
}

View File

@ -1,6 +1,12 @@
package cc.co.evenprime.bukkit.nocheat.config;
package cc.co.evenprime.bukkit.nocheat.config.tree;
public class IntegerOption extends TextFieldOption {
/**
* A node for the configuration tree
*
* @author Evenprime
*
*/
public class IntegerOption extends StringOption {
/**
*
@ -27,6 +33,10 @@ public class IntegerOption extends TextFieldOption {
}
public int getIntegerValue() {
return Integer.parseInt(this.getValue());
return Integer.parseInt(this.getStringValue());
}
public IntegerOption clone() {
return new IntegerOption(this.getIdentifier(), this.getIntegerValue());
}
}

View File

@ -0,0 +1,47 @@
package cc.co.evenprime.bukkit.nocheat.config.tree;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
/**
* A node for the configuration tree
*
* @author Evenprime
*
*/
public class LogLevelOption extends ChildOption {
/**
*
*/
private static final long serialVersionUID = -1609308017422576285L;
private LogLevel option;
public LogLevelOption(String identifier, LogLevel initialValue) {
super(identifier);
this.option = initialValue;
}
@Override
public String getStringValue() {
return option.name;
}
public boolean setStringValue(String value) {
option = LogLevel.getLogLevelFromString(value);
return true;
}
public void setLogLevelValue(LogLevel value) {
this.option = value;
}
public LogLevel getLogLevelValue() {
return this.option;
}
public LogLevelOption clone() {
return new LogLevelOption(this.getIdentifier(), this.option);
}
}

View File

@ -0,0 +1,23 @@
package cc.co.evenprime.bukkit.nocheat.config.tree;
/**
* A node for the configuration tree
*
* @author Evenprime
*
*/
public class MediumStringOption extends StringOption {
/**
*
*/
private static final long serialVersionUID = 2258827414736580449L;
public MediumStringOption(String name, String initialValue) {
super(name, initialValue, 30);
}
public MediumStringOption clone() {
return new MediumStringOption(this.getIdentifier(), this.getStringValue());
}
}

View File

@ -1,10 +1,18 @@
package cc.co.evenprime.bukkit.nocheat.config;
package cc.co.evenprime.bukkit.nocheat.config.tree;
/**
* A node for the configuration tree
*
* @author Evenprime
*
*/
public abstract class Option {
private final String identifier;
private Option parent;
private boolean active = true;
public Option(String identifier) {
this.identifier = identifier;
}
@ -17,11 +25,19 @@ public abstract class Option {
this.parent = parent;
}
public final Option getParent() {
return parent;
}
public final String getFullIdentifier() {
return (parent == null || parent.getFullIdentifier() == "") ? identifier : parent.getFullIdentifier() + "." + identifier;
}
public abstract String toYAMLString(String prefix);
public void setActive(boolean b) {
active = b;
}
public abstract String toDescriptionString(String prefix);
public boolean isActive() {
return active;
}
}

View File

@ -0,0 +1,45 @@
package cc.co.evenprime.bukkit.nocheat.config.tree;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
/**
* A node for the configuration tree
*
* @author Evenprime
*
*/
public class ParentOption extends Option {
/**
*
*/
private static final long serialVersionUID = 3162246550749560727L;
private final LinkedList<Option> children = new LinkedList<Option>();
public ParentOption(String identifier) {
super(identifier);
}
public final Collection<Option> getChildOptions() {
return Collections.unmodifiableCollection(children);
}
public final void add(Option option) {
children.addLast(option);
option.setParent(this);
}
public Option getChild(String identifier) {
for(Option o : children) {
if(o.getIdentifier().equals(identifier)) {
return o;
}
}
return null;
}
}

View File

@ -1,6 +1,12 @@
package cc.co.evenprime.bukkit.nocheat.config;
package cc.co.evenprime.bukkit.nocheat.config.tree;
public abstract class TextFieldOption extends ChildOption {
/**
* A node for the configuration tree
*
* @author Evenprime
*
*/
public abstract class StringOption extends ChildOption {
/**
*
@ -10,7 +16,7 @@ public abstract class TextFieldOption extends ChildOption {
private String value;
private final int length;
public TextFieldOption(String name, String initialValue, int preferredLength) {
protected StringOption(String name, String initialValue, int preferredLength) {
super(name);
this.value = initialValue;
@ -18,11 +24,11 @@ public abstract class TextFieldOption extends ChildOption {
}
@Override
public String getValue() {
public String getStringValue() {
return this.value;
}
public boolean setValue(String value) {
public boolean setStringValue(String value) {
if(isValid(value)) {
this.value = value;
return true;

View File

@ -1,8 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.data;
public class AirbuildData {
public int perFiveSeconds = 0;
public int summaryTask = -1;
}

View File

@ -0,0 +1,18 @@
package cc.co.evenprime.bukkit.nocheat.data;
import org.bukkit.Location;
/**
* Playerspecific data for the blockbreak check group
*
* @author Evenprime
*
*/
public class BlockBreakData {
public double reachViolationLevel = 0.0D;
public double directionViolationLevel = 0.0D;
public Location instaBrokeBlockLocation = null;
}

View File

@ -0,0 +1,56 @@
package cc.co.evenprime.bukkit.nocheat.data;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.entity.Player;
/**
* Provide secure access to player-specific data objects for various checks or
* check groups
*
* @author Evenprime
*
*/
public class DataManager {
// Store data between Events
private final Map<Player, MovingData> movingData = new HashMap<Player, MovingData>();
private final Map<Player, BlockBreakData> blockbreakData = new HashMap<Player, BlockBreakData>();
public DataManager() {
}
public MovingData getMovingData(Player player) {
MovingData data;
// intentionally not thread-safe, because bukkit events are handled
// in sequence anyway, so zero chance of two move events of the same
// player being handled at the same time
data = movingData.get(player);
if(data == null) {
data = new MovingData();
movingData.put(player, data);
}
return data;
}
public BlockBreakData getBlockBreakData(Player player) {
BlockBreakData data;
// intentionally not thread-safe, because bukkit events are handled
// in sequence anyway, so zero chance of two move events of the same
// player being handled at the same time
data = blockbreakData.get(player);
if(data == null) {
data = new BlockBreakData();
blockbreakData.put(player, data);
}
return data;
}
}

View File

@ -1,7 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.data;
public class InfinitedurabilityData {
public long lastLog = 0;
}

View File

@ -1,67 +1,40 @@
package cc.co.evenprime.bukkit.nocheat.data;
import java.util.logging.Level;
import net.minecraft.server.Block;
import org.bukkit.Location;
import org.bukkit.Material;
/**
* Playerspecific data for the moving check group
*
* @author Evenprime
*
*/
public class MovingData {
public int jumpPhase = 0;
public final int violationsInARow[] = {0, 0, 0};
public double horizFreedom = 0.0D;
public double vertFreedom = 0.0D;
public int vertFreedomCounter = 0;
public int jumpPhase = 0;
// setbackpoint is a recommendation - try to teleport to first solid block
// below it
// for better effect
public Location setBackPoint = null;
public Location movingsetBackPoint = null;
public int summaryTask = -1;
public Level highestLogLevel = null;
public double maxYVelocity = 0.0D;
public double violationLevel = 0.0D;
public double movingViolationLevel = 0.0D;
public Location teleportInitializedByMe = null;
public double horizontalBuffer = 0.1D;
public double vertFreedom = 0.0D;
public double vertVelocity = 0.0D;
public int vertVelocityCounter = 0;
public double horizFreedom = 0.0D;
public int horizVelocityCounter = 0;
// Block types that may need to be treated specially
public static final int NONSOLID = 0; // 0x00000000
public static final int SOLID = 1; // 0x00000001
public static final int LIQUID = 2; // 0x00000010
public static final int LADDER = 4; // 0x00000100
public static final int FENCE = 8; // 0x00001000
public int noclipX;
public int noclipY;
public int noclipZ;
// Until I can think of a better way to determine if a block is solid or
// not, this is what I'll do
public static final int types[] = new int[256];
public double horizontalBuffer;
static {
public int morePacketsCounter;
public long morePacketsLastTime;
// Find and define properties of all blocks
for(int i = 0; i < types.length; i++) {
public double morePacketsOverLimit = -50;
// Everything is considered solid at first
types[i] = SOLID;
public Location morePacketsSetbackPoint;
if(Block.byId[i] != null) {
if(Block.byId[i].material.isSolid()) {
// solid blocks like STONE, CAKE, TRAPDOORS
types[i] = SOLID;
} else if(Block.byId[i].material.isLiquid()) {
// WATER, LAVA
types[i] = LIQUID;
} else {
types[i] = NONSOLID;
}
}
}
public Location teleportTo;
// Special types just for me
types[Material.LADDER.getId()] = LADDER | SOLID;
types[Material.FENCE.getId()] = FENCE | SOLID;
}
}

View File

@ -1,25 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.data;
/**
* per player storage for data persistence between events
*
* @author Evenprime
*
*/
public class NoCheatData {
/**
* Don't rely on any of these yet, they are likely going to change their
* name/functionality
*/
public MovingData moving;
public SpeedhackData speedhack;
public AirbuildData airbuild;
public PermissionData permission;
public NukeData nuke;
public InfinitedurabilityData infinite;
public NoCheatData() {}
}

View File

@ -1,7 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.data;
public class NukeData {
public int counter = 0;
}

View File

@ -1,38 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.data;
public class PermissionData {
private static final int size = 12;
public final long lastUpdate[] = new long[size];
public final boolean cache[] = new boolean[size];
public static final String[] permissionNames = new String[size];
public static final int PERMISSION_MOVING = 0;
public static final int PERMISSION_FLYING = 1;
public static final int PERMISSION_SPEEDHACK = 2;
public static final int PERMISSION_AIRBUILD = 3;
public static final int PERMISSION_BEDTELEPORT = 4; // unused
public static final int PERMISSION_BOGUSITEMS = 5;
public static final int PERMISSION_NOTIFY = 6;
public static final int PERMISSION_ITEMDUPE = 7; // unused
public static final int PERMISSION_FAKESNEAK = 8;
public static final int PERMISSION_FASTSWIM = 9;
public static final int PERMISSION_NUKE = 10;
public static final int PERMISSION_INFINITEDURABILITY = 11;
static {
permissionNames[PERMISSION_AIRBUILD] = "nocheat.airbuild";
permissionNames[PERMISSION_BEDTELEPORT] = "nocheat.bedteleport";
permissionNames[PERMISSION_FLYING] = "nocheat.flying";
permissionNames[PERMISSION_MOVING] = "nocheat.moving";
permissionNames[PERMISSION_BOGUSITEMS] = "nocheat.bogusitems";
permissionNames[PERMISSION_SPEEDHACK] = "nocheat.speedhack";
permissionNames[PERMISSION_NOTIFY] = "nocheat.notify";
permissionNames[PERMISSION_ITEMDUPE] = "nocheat.itemdupe";
permissionNames[PERMISSION_FAKESNEAK] = "nocheat.fakesneak";
permissionNames[PERMISSION_FASTSWIM] = "nocheat.fastswim";
permissionNames[PERMISSION_NUKE] = "nocheat.nuke";
permissionNames[PERMISSION_INFINITEDURABILITY] = "nocheat.infinitedurability";
}
}

View File

@ -1,15 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.data;
import org.bukkit.Location;
public class SpeedhackData {
public int lastCheckTicks = 0; // timestamp of last
// check for speedhacks
public Location setBackPoint = null;
public int eventsSinceLastCheck = 0; // used to identify
// speedhacks
public final int violationsInARow[] = {0, 0, 0};
public int violationsInARowTotal = 0;
}

View File

@ -0,0 +1,87 @@
package cc.co.evenprime.bukkit.nocheat.events;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.block.BlockListener;
import org.bukkit.plugin.PluginManager;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.Permissions;
import cc.co.evenprime.bukkit.nocheat.checks.blockbreak.BlockBreakCheck;
import cc.co.evenprime.bukkit.nocheat.config.ConfigurationManager;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.DataManager;
import cc.co.evenprime.bukkit.nocheat.data.BlockBreakData;
/**
* Central location to listen to player-interact events and dispatch them to
* relevant checks
*
* @author Evenprime
*
*/
public class BlockBreakEventManager extends BlockListener {
private final BlockBreakCheck blockBreakCheck;
private final DataManager data;
private final ConfigurationManager config;
public BlockBreakEventManager(NoCheat plugin) {
this.data = plugin.getDataManager();
this.config = plugin.getConfigurationManager();
this.blockBreakCheck = new BlockBreakCheck(plugin);
PluginManager pm = Bukkit.getServer().getPluginManager();
pm.registerEvent(Event.Type.BLOCK_BREAK, this, Priority.Lowest, plugin);
pm.registerEvent(Event.Type.BLOCK_DAMAGE, this, Priority.Monitor, plugin);
}
@Override
public void onBlockBreak(BlockBreakEvent event) {
if(event.isCancelled()) {
return;
}
final Player player = event.getPlayer();
final ConfigurationCache cc = config.getConfigurationCacheForWorld(player.getWorld().getName());
// Find out if checks need to be done for that player
if(cc.blockbreak.check && !player.hasPermission(Permissions.BLOCKBREAK)) {
boolean cancel = false;
// Get the player-specific stored data that applies here
final BlockBreakData data = this.data.getBlockBreakData(player);
cancel = blockBreakCheck.check(player, event.getBlock(), data, cc);
if(cancel) {
event.setCancelled(true);
}
}
}
@Override
public void onBlockDamage(BlockDamageEvent event) {
// Only interested in insta-break events
if(!event.isCancelled() && !event.getInstaBreak()) {
return;
}
final Player player = event.getPlayer();
// Get the player-specific stored data that applies here
final BlockBreakData data = this.data.getBlockBreakData(player);
// Remember this location. We ignore block breaks in the block-break direction check that are insta-breaks
data.instaBrokeBlockLocation = event.getBlock().getLocation();
}
}

View File

@ -0,0 +1,51 @@
package cc.co.evenprime.bukkit.nocheat.events;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.block.BlockListener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.plugin.PluginManager;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.checks.moving.MovingCheck;
import cc.co.evenprime.bukkit.nocheat.data.DataManager;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* Central location to listen to Block-related events and dispatching them to
* checks
*
* @author Evenprime
*
*/
public class BlockPlaceEventManager extends BlockListener {
private final MovingCheck movingCheck;
private final DataManager data;
public BlockPlaceEventManager(NoCheat plugin) {
this.data = plugin.getDataManager();
this.movingCheck = new MovingCheck(plugin);
PluginManager pm = Bukkit.getServer().getPluginManager();
pm.registerEvent(Event.Type.BLOCK_PLACE, this, Priority.Monitor, plugin);
}
@Override
public void onBlockPlace(BlockPlaceEvent event) {
if(!event.isCancelled()) {
final Player player = event.getPlayer();
// Get the player-specific stored data that applies here
final MovingData data = this.data.getMovingData(player);
movingCheck.blockPlaced(player, data, event.getBlockPlaced());
}
}
}

View File

@ -0,0 +1,122 @@
package cc.co.evenprime.bukkit.nocheat.events;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerVelocityEvent;
import org.bukkit.plugin.PluginManager;
import org.bukkit.util.Vector;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.Permissions;
import cc.co.evenprime.bukkit.nocheat.checks.moving.MovingCheck;
import cc.co.evenprime.bukkit.nocheat.config.ConfigurationManager;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.DataManager;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
import cc.co.evenprime.bukkit.nocheat.log.LogManager;
/**
* The only place that listens to and modifies player_move events if necessary
*
* Get the event, decide which checks should work on it and in what order,
* evaluate the check results and decide what to
*
* @author Evenprime
*
*/
public class PlayerMoveEventManager extends PlayerListener {
private final MovingCheck movingCheck;
private final ConfigurationManager config;
private final LogManager log;
private final DataManager data;
public PlayerMoveEventManager(NoCheat plugin) {
this.config = plugin.getConfigurationManager();
this.log = plugin.getLogManager();
this.data = plugin.getDataManager();
this.movingCheck = new MovingCheck(plugin);
PluginManager pm = Bukkit.getServer().getPluginManager();
pm.registerEvent(Event.Type.PLAYER_MOVE, this, Priority.Lowest, plugin);
pm.registerEvent(Event.Type.PLAYER_VELOCITY, this, Priority.Monitor, plugin);
}
@Override
public void onPlayerMove(PlayerMoveEvent event) {
// Cancelled events are ignored
if(event.isCancelled())
return;
// Get the world-specific configuration that applies here
final Player player = event.getPlayer();
final ConfigurationCache cc = config.getConfigurationCacheForWorld(player.getWorld().getName());
// Find out if checks need to be done for that player
if(cc.moving.check && !player.hasPermission(Permissions.MOVE)) {
// Get the player-specific stored data that applies here
final MovingData data = this.data.getMovingData(player);
// Get some data that's needed from this event, to avoid passing the
// event itself on to the checks (and risk to
// accidentally modifying the event there)
final Location from = event.getFrom();
final Location to = event.getTo();
// This variable will have the modified data of the event (new
// "to"-location)
Location newTo = null;
// Currently only one check here.
newTo = movingCheck.check(player, from, to, data, cc);
// Did the check(s) decide we need a new "to"-location?
if(newTo != null) {
// Compose a new location based on coordinates of "newTo" and
// viewing direction of "event.getTo()"
Location l = new Location(newTo.getWorld(), newTo.getX(), newTo.getY(), newTo.getZ(), to.getYaw(), to.getPitch());
event.setTo(l);
data.teleportTo = l;
}
}
// Log some performance data
// log.logToConsole(LogLevel.LOW, "Time: " + (System.nanoTime() -
// nanoTime));
}
@Override
public void onPlayerVelocity(PlayerVelocityEvent event) {
if(!event.isCancelled()) {
Player player = event.getPlayer();
MovingData mdata = data.getMovingData(player);
Vector v = event.getVelocity();
double newVal = v.getY();
if(newVal > 0.0D) {
mdata.vertVelocity += newVal;
mdata.vertFreedom += mdata.vertVelocity;
mdata.vertVelocityCounter = 50;
}
newVal = Math.sqrt(Math.pow(v.getX(), 2) + Math.pow(v.getZ(), 2));
if(newVal > 0.0D) {
mdata.horizFreedom += newVal;
mdata.horizVelocityCounter = 30;
}
}
}
}

View File

@ -0,0 +1,90 @@
package cc.co.evenprime.bukkit.nocheat.events;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.plugin.PluginManager;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.data.DataManager;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
import cc.co.evenprime.bukkit.nocheat.log.LogManager;
/**
* Only place that listens to Player-teleport related events and dispatches them
* to relevant checks
*
* @author Evenprime
*
*/
public class PlayerTeleportEventManager extends PlayerListener {
private final LogManager log;
private final DataManager data;
public PlayerTeleportEventManager(NoCheat plugin) {
this.log = plugin.getLogManager();
this.data = plugin.getDataManager();
PluginManager pm = Bukkit.getServer().getPluginManager();
pm.registerEvent(Event.Type.PLAYER_TELEPORT, this, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_PORTAL, this, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_RESPAWN, this, Priority.Monitor, plugin);
// This belongs to the move-check
// Override decision to cancel teleports initialized by NoCheat by
// uncancelling them
pm.registerEvent(Event.Type.PLAYER_TELEPORT, new PlayerListener() {
@Override
public void onPlayerTeleport(PlayerTeleportEvent event) {
final MovingData data2 = data.getMovingData(event.getPlayer());
if(event.isCancelled()) {
if(data2.teleportTo != null && data2.teleportTo.equals(event.getTo())) {
event.setCancelled(false);
}
}
}
}, Priority.Highest, plugin);
}
@Override
public void onPlayerTeleport(PlayerTeleportEvent event) {
if(!event.isCancelled())
handleTeleportation(event.getPlayer(), event.getTo());
}
public void onPlayerPortal(PlayerPortalEvent event) {
if(!event.isCancelled())
handleTeleportation(event.getPlayer(), event.getTo());
}
public void onPlayerRespawn(PlayerRespawnEvent event) {
handleTeleportation(event.getPlayer(), event.getRespawnLocation());
}
public void handleTeleportation(Player player, Location newLocation) {
/********* Moving check ************/
final MovingData data = this.data.getMovingData(player);
data.movingsetBackPoint = null;
data.morePacketsCounter = 0;
data.morePacketsSetbackPoint = null;
data.jumpPhase = 0;
data.noclipX = newLocation.getBlockX();
data.noclipY = Location.locToBlock(newLocation.getY()+1.1D);
data.noclipZ = newLocation.getBlockZ();
}
}

View File

@ -0,0 +1,47 @@
package cc.co.evenprime.bukkit.nocheat.file;
import cc.co.evenprime.bukkit.nocheat.Explainations;
import cc.co.evenprime.bukkit.nocheat.config.tree.ChildOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationTree;
import cc.co.evenprime.bukkit.nocheat.config.tree.Option;
import cc.co.evenprime.bukkit.nocheat.config.tree.ParentOption;
/**
* Create a description file based on a configuration tree (to know what should
* be in the description file) and data from "Explainations.java".
*
* @author Evenprime
*
*/
public class DescriptionGenerator {
public static String treeToDescription(ConfigurationTree tree) {
ParentOption o = (ParentOption) tree.getOption("");
String s = "";
for(Option option : o.getChildOptions()) {
s += optionToDescriptionString(option);
}
return s;
}
private static String optionToDescriptionString(Option option) {
String s = "";
if(option instanceof ParentOption) {
for(Option o : ((ParentOption) option).getChildOptions()) {
s += optionToDescriptionString(o) + "\r\n";
}
} else if(option instanceof ChildOption && option.isActive()) {
String padding = " ";
s += option.getFullIdentifier() + "\r\n" + padding + Explainations.get(option.getFullIdentifier()).replace("\n", "\r\n" + padding) + "\r\n";
}
return s;
}
}

View File

@ -0,0 +1,90 @@
package cc.co.evenprime.bukkit.nocheat.file;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import cc.co.evenprime.bukkit.nocheat.actions.ActionManager;
/**
* Parses a action config file that was written in a flat style, one action per
* line
*
* @author Evenprime
*
*/
public class FlatActionParser {
public void read(ActionManager manager, File file) {
List<String[]> actionLines = readActionLinesFromFile(file, manager.getKnownTypes());
for(String[] actionLine : actionLines) {
manager.createActionFromStrings(actionLine[0], actionLine[1], actionLine[2], actionLine[3], actionLine.length > 4 ? actionLine[4] : null);
}
}
private List<String[]> readActionLinesFromFile(File file, String[] knownTypes) {
List<String[]> lines = new LinkedList<String[]>();
if(!file.exists()) {
createActionFile(file);
return lines;
}
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader(file));
String line = null;
while((line = reader.readLine()) != null) {
for(String s : knownTypes) {
if(line.startsWith(s)) {
// Split at whitespace characters
String parts[] = line.split("\\s+", 5);
if(parts.length < 4) {
System.out.println("NoCheat: Incomplete action definition found. Ignoring it: " + line);
} else {
lines.add(parts);
}
}
}
}
reader.close();
} catch(FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
return lines;
}
public void createActionFile(File file) {
if(!file.exists()) {
try {
file.createNewFile();
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
writer.write("# Use this file to define your own actions.");
writer.newLine();
writer.write("# Look at \"default_actions.txt\" for inspiration.");
writer.newLine();
writer.flush();
writer.close();
} catch(Exception e) {
e.printStackTrace();
};
}
}
}

View File

@ -0,0 +1,51 @@
package cc.co.evenprime.bukkit.nocheat.file;
import cc.co.evenprime.bukkit.nocheat.config.tree.ActionListOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ActionOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ChildOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationTree;
import cc.co.evenprime.bukkit.nocheat.config.tree.Option;
import cc.co.evenprime.bukkit.nocheat.config.tree.ParentOption;
/**
* Create a flat config file based on a ConfigurationTree
*
* @author Evenprime
*
*/
public class FlatConfigGenerator {
public static String treeToFlatFile(ConfigurationTree tree) {
ParentOption o = (ParentOption) tree.getOption("");
String s = "";
for(Option option : o.getChildOptions()) {
s += optionToFlatString(option);
}
return s;
}
private static String optionToFlatString(Option option) {
String s = "";
if(option instanceof ParentOption) {
for(Option o : ((ParentOption) option).getChildOptions()) {
s += optionToFlatString(o);
}
} else if(option instanceof ActionListOption && option.isActive()) {
for(ActionOption o : ((ActionListOption) option).getChildOptions()) {
s += option.getFullIdentifier() + "." + o.getIdentifier() + " = \"" + o.getStringValue() + "\"\r\n";
}
} else if(option instanceof ChildOption && option.isActive()) {
s += option.getFullIdentifier() + " = \"" + ((ChildOption) option).getStringValue() + "\"\r\n";
}
return s;
}
}

View File

@ -0,0 +1,127 @@
package cc.co.evenprime.bukkit.nocheat.file;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
/**
* An extremely simple flat config file parser
*
* @author Evenprime
*
*/
public class FlatConfigParser {
private final Map<String, Object> root;
public FlatConfigParser() {
root = new HashMap<String, Object>();
}
public void read(File file) throws IOException {
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
LinkedList<String> lines = new LinkedList<String>();
String line = null;
while((line = r.readLine()) != null) {
lines.add(line);
}
r.close();
parse(root, lines, "");
}
private void parse(Map<String, Object> root, LinkedList<String> lines, String prefix) throws IOException {
String line = null;
while(!lines.isEmpty()) {
line = lines.getFirst();
if(line.trim().startsWith("#")) {
lines.removeFirst();
} else if(line.trim().isEmpty()) {
lines.removeFirst();
} else {
lines.removeFirst();
if(line.contains("=")) {
String pair[] = line.split("=", 2);
putString(pair[0].trim(), root, removeQuotationMarks(pair[1].trim()));
}
}
}
}
private static String removeQuotationMarks(String s) {
if(s.startsWith("\"") && s.endsWith("\"")) {
return s.substring(1, s.length() - 1);
} else if(s.startsWith("\'") && s.endsWith("\'")) {
return s.substring(1, s.length() - 1);
}
return s;
}
/* Convenience methods for retrieving values start here */
public Object getProperty(String path) {
return getProperty(path, root);
}
@SuppressWarnings("unchecked")
private static Object getProperty(String path, Map<String, Object> node) {
if(node == null) {
return null;
}
if(!path.contains(".")) {
return node.get(path);
} else {
String[] parts = path.split("\\.", 2);
return getProperty(parts[1], (Map<String, Object>) node.get(parts[0]));
}
}
public String getString(String path, String defaultValue) {
return getString(path, defaultValue, root);
}
@SuppressWarnings("unchecked")
private static void putString(String path, Map<String, Object> node, String property) {
String[] pathParts = path.split("\\.");
for(int i = 0; i < pathParts.length; i++) {
if(i == pathParts.length - 1) { // last in the chain
node.put(pathParts[i], property);
} else if(node.containsKey(pathParts[i]) && node.get(pathParts[i]) instanceof Map) {
node = (Map<String, Object>) node.get(pathParts[i]);
} else {
HashMap<String, Object> newMap = new HashMap<String, Object>();
node.put(pathParts[i], newMap);
node = newMap;
}
}
}
private static String getString(String path, String defaultValue, Map<String, Object> node) {
try {
String result = (String) getProperty(path, node);
if(result == null)
return defaultValue;
return result;
} catch(Exception e) {
return defaultValue;
}
}
}

View File

@ -0,0 +1,58 @@
package cc.co.evenprime.bukkit.nocheat.file;
import cc.co.evenprime.bukkit.nocheat.config.tree.ActionListOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ActionOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ChildOption;
import cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationTree;
import cc.co.evenprime.bukkit.nocheat.config.tree.Option;
import cc.co.evenprime.bukkit.nocheat.config.tree.ParentOption;
/**
* An extremely simple YAML configuration generator
*
* @author Evenprime
*
*/
public class YamlConfigGenerator {
private final static String spaces = " ";
public static String treeToYaml(ConfigurationTree tree) {
ParentOption o = (ParentOption) tree.getOption("");
String s = "";
for(Option option : o.getChildOptions()) {
s += optionToYamlString(option, "");
}
return s;
}
private static String optionToYamlString(Option option, String prefix) {
String s = "";
if(option instanceof ParentOption) {
s += prefix + option.getIdentifier() + ":\r\n";
prefix += spaces;
for(Option o : ((ParentOption) option).getChildOptions()) {
s += optionToYamlString(o, prefix);
}
} else if(option instanceof ActionListOption && option.isActive()) {
s += prefix + option.getIdentifier() + ":\r\n";
for(ActionOption o : ((ActionListOption) option).getChildOptions()) {
s += prefix + spaces + o.getIdentifier() + ": \"" + o.getStringValue() + "\"\r\n";
}
} else if(option instanceof ChildOption && option.isActive()) {
s += prefix + option.getIdentifier() + ": \"" + ((ChildOption) option).getStringValue() + "\"\r\n";
}
return s;
}
}

View File

@ -1,4 +1,4 @@
package cc.co.evenprime.bukkit.nocheat.yaml;
package cc.co.evenprime.bukkit.nocheat.file;
import java.io.BufferedReader;
import java.io.File;
@ -6,26 +6,27 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
/**
* An extremely simple YAML parser, not feature complete, but good enough for me
* An extremely simple YAML config parser
*
* @author Evenprime
*
*/
public class SimpleYaml {
public class YamlConfigParser {
private static final String prefix = " ";
private final String prefix = " ";
private SimpleYaml() {}
private final Map<String, Object> root;
public static Map<String, Object> read(File file) throws IOException {
public YamlConfigParser() {
Map<String, Object> root = new HashMap<String, Object>();
root = new HashMap<String, Object>();
}
public void read(File file) throws IOException {
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
@ -39,11 +40,11 @@ public class SimpleYaml {
r.close();
return parse(root, lines, "");
parse(root, lines, "");
}
private static Map<String, Object> parse(Map<String, Object> root, LinkedList<String> lines, String prefix) throws IOException {
private void parse(Map<String, Object> root, LinkedList<String> lines, String prefix) throws IOException {
String line = null;
@ -59,7 +60,8 @@ public class SimpleYaml {
String pair[] = line.split(":", 2);
if(pair[1].trim().isEmpty()) {
Map<String, Object> m = new HashMap<String, Object>();
root.put(pair[0].trim(), parse(m, lines, prefix + SimpleYaml.prefix));
parse(m, lines, prefix + this.prefix);
root.put(pair[0].trim(), m);
} else {
root.put(pair[0].trim(), removeQuotationMarks(pair[1].trim()));
}
@ -67,8 +69,6 @@ public class SimpleYaml {
} else
break;
}
return root;
}
private static String removeQuotationMarks(String s) {
@ -84,8 +84,17 @@ public class SimpleYaml {
/* Convenience methods for retrieving values start here */
public Object getProperty(String path) {
return getProperty(path, root);
}
@SuppressWarnings("unchecked")
private final static Object getProperty(String path, Map<String, Object> node) {
private static Object getProperty(String path, Map<String, Object> node) {
if(node == null) {
return null;
}
if(!path.contains(".")) {
return node.get(path);
} else {
@ -94,41 +103,11 @@ public class SimpleYaml {
}
}
@SuppressWarnings("unchecked")
public static Set<String> getKeys(String path, Map<String, Object> node) {
try {
return ((Map<String, Object>) getProperty(path, node)).keySet();
} catch(Exception e) {
// e.printStackTrace();
return new HashSet<String>();
}
public String getString(String path, String defaultValue) {
return getString(path, defaultValue, root);
}
public static int getInt(String path, int defaultValue, Map<String, Object> node) {
try {
return Integer.parseInt((String) getProperty(path, node));
} catch(Exception e) {
// e.printStackTrace();
return defaultValue;
}
}
public static boolean getBoolean(String path, boolean defaultValue, Map<String, Object> node) {
try {
if(((String) getProperty(path, node)).equals("true")) {
return true;
} else if(((String) getProperty(path, node)).equals("false")) {
return false;
} else {
return defaultValue;
}
} catch(Exception e) {
// e.printStackTrace();
return defaultValue;
}
}
public static String getString(String path, String defaultValue, Map<String, Object> node) {
private static String getString(String path, String defaultValue, Map<String, Object> node) {
try {
String result = (String) getProperty(path, node);
if(result == null)

View File

@ -1,28 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.event.block.BlockListener;
import org.bukkit.event.block.BlockPlaceEvent;
import cc.co.evenprime.bukkit.nocheat.checks.AirbuildCheck;
/**
* Handle events for all Block related events
*
* @author Evenprime
*
*/
public class AirbuildBlockListener extends BlockListener {
private final AirbuildCheck check;
public AirbuildBlockListener(AirbuildCheck check) {
this.check = check;
}
@Override
public void onBlockPlace(BlockPlaceEvent event) {
if(!event.isCancelled())
check.check(event);
}
}

View File

@ -1,38 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerPickupItemEvent;
import cc.co.evenprime.bukkit.nocheat.checks.BogusitemsCheck;
public class BogusitemsPlayerListener extends PlayerListener {
private final BogusitemsCheck check;
public BogusitemsPlayerListener(BogusitemsCheck bogusitemsCheck) {
check = bogusitemsCheck;
}
@Override
public void onPlayerPickupItem(PlayerPickupItemEvent event) {
if(!event.isCancelled())
check.check(event);
}
@Override
public void onPlayerDropItem(PlayerDropItemEvent event) {
check.check(event);
}
@Override
public void onPlayerInteract(PlayerInteractEvent event) {
if(!event.isCancelled())
check.check(event);
}
}

View File

@ -1,27 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerListener;
import cc.co.evenprime.bukkit.nocheat.checks.InfinitedurabilityCheck;
public class InfinitedurabilityListener extends PlayerListener {
private final InfinitedurabilityCheck check;
public InfinitedurabilityListener(InfinitedurabilityCheck check) {
this.check = check;
}
@Override
public void onItemHeldChange(PlayerItemHeldEvent event) {
check.check(event);
}
@Override
public void onPlayerInteract(PlayerInteractEvent event) {
check.check(event);
}
}

View File

@ -1,28 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.event.block.BlockListener;
import org.bukkit.event.block.BlockPlaceEvent;
import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck;
/**
* Handle events for all Block related events
*
* @author Evenprime
*
*/
public class MovingBlockMonitor extends BlockListener {
private final MovingCheck check;
public MovingBlockMonitor(MovingCheck check) {
this.check = check;
}
@Override
public void onBlockPlace(BlockPlaceEvent event) {
if(!event.isCancelled())
check.blockPlaced(event);
}
}

View File

@ -1,57 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerMoveEvent;
import cc.co.evenprime.bukkit.nocheat.DataManager;
import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* Handle events for Player related events
*
* @author Evenprime
*/
public class MovingPlayerListener extends PlayerListener {
private final MovingCheck movingCheck;
private final DataManager dataManager;
public MovingPlayerListener(DataManager dataManager, MovingCheck check) {
this.dataManager = dataManager;
this.movingCheck = check;
}
@Override
public void onPlayerMove(PlayerMoveEvent event) {
if(event.isCancelled())
return;
final Player player = event.getPlayer();
// Is there something to do at all?
if(!movingCheck.skipCheck(player)) {
final MovingData data = dataManager.getMovingData(player);
final Location from = event.getFrom();
final Location to = event.getTo();
Location newTo = null;
if(!player.isInsideVehicle()) {
// Check it
newTo = movingCheck.check(player, from, to, data);
}
// Did the checks decide we need a new To-Location?
if(newTo != null) {
event.setTo(new Location(newTo.getWorld(), newTo.getX(), newTo.getY(), newTo.getZ(), event.getTo().getYaw(), event.getTo().getPitch()));
data.setBackPoint = null;
}
}
}
}

View File

@ -1,62 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerVelocityEvent;
import cc.co.evenprime.bukkit.nocheat.DataManager;
import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
*
* @author Evenprime
*
*/
public class MovingPlayerMonitor extends PlayerListener {
private final MovingCheck check;
private final DataManager dataManager;
public MovingPlayerMonitor(DataManager dataManager, MovingCheck check) {
this.dataManager = dataManager;
this.check = check;
}
@Override
public void onPlayerRespawn(PlayerRespawnEvent event) {
MovingData data = dataManager.getMovingData(event.getPlayer());
data.setBackPoint = null;
}
@Override
public void onPlayerPortal(PlayerPortalEvent event) {
check.teleported(event);
}
@Override
public void onPlayerTeleport(PlayerTeleportEvent event) {
check.teleported(event);
}
@Override
public void onPlayerVelocity(PlayerVelocityEvent event) {
check.updateVelocity(event.getVelocity(), dataManager.getMovingData(event.getPlayer()));
}
@Override
public void onPlayerMove(PlayerMoveEvent event) {
if(event.getPlayer().isInsideVehicle()) {
MovingData data = dataManager.getMovingData(event.getPlayer());
data.setBackPoint = null;
}
if(event.isCancelled()) {
MovingData data = dataManager.getMovingData(event.getPlayer());
data.setBackPoint = event.getPlayer().getLocation();
}
}
}

View File

@ -1,22 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockListener;
import cc.co.evenprime.bukkit.nocheat.checks.NukeCheck;
public class NukeBlockListener extends BlockListener {
private final NukeCheck check;
public NukeBlockListener(NukeCheck check) {
this.check = check;
}
@Override
public void onBlockBreak(BlockBreakEvent event) {
check.check(event);
}
}

View File

@ -1,35 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import cc.co.evenprime.bukkit.nocheat.checks.SpeedhackCheck;
/**
*
* @author Evenprime
*
*/
public class SpeedhackPlayerListener extends PlayerListener {
private final SpeedhackCheck check;
public SpeedhackPlayerListener(SpeedhackCheck check) {
this.check = check;
}
@Override
public void onPlayerMove(PlayerMoveEvent event) {
if(event.isCancelled())
return;
check.check(event);
}
@Override
public void onPlayerTeleport(PlayerTeleportEvent event) {
check.teleported(event);
}
}

View File

@ -1,22 +0,0 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerMoveEvent;
import cc.co.evenprime.bukkit.nocheat.checks.SpeedhackCheck;
public class SpeedhackPlayerMonitor extends PlayerListener {
private final SpeedhackCheck check;
public SpeedhackPlayerMonitor(SpeedhackCheck check) {
this.check = check;
}
@Override
public void onPlayerMove(PlayerMoveEvent event) {
if(event.isCancelled()) {
check.teleported(event.getPlayer());
}
}
}

View File

@ -0,0 +1,56 @@
package cc.co.evenprime.bukkit.nocheat.log;
import java.util.logging.Level;
/**
* Define the available log levels (low, med, high, off)
*
* @author Evenprime
*
*/
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);
public final String name;
private final String description;
public final Level level;
private LogLevel(String name, String description, Level level) {
this.name = name;
this.description = description;
this.level = level;
}
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;
}
/**
* Is this level smaller or equal to "level"
*
* @param level
*/
public boolean matches(LogLevel level) {
if(this == OFF || level == OFF) {
return false;
} else {
return this.level.intValue() <= level.level.intValue();
}
}
}

View File

@ -0,0 +1,87 @@
package cc.co.evenprime.bukkit.nocheat.log;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.Permissions;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
/**
* Manage logging throughout NoCheat. Messages may be logged directly to a
* specific place or go through configuration/permissions to decide if and where
* the message will be visible
*
* @author Evenprime
*
*/
public class LogManager {
private final NoCheat plugin;
public LogManager(NoCheat plugin) {
this.plugin = plugin;
}
/**
* Check if and where the message should be logged to and then do it
*
* @param level
* @param message
* @param cc
*/
public void log(LogLevel level, String message, ConfigurationCache cc) {
if(!cc.logging.active)
return;
if(cc.logging.fileLevel.matches(level)) {
logToFile(level, message, cc.logging.filelogger);
}
if(cc.logging.consoleLevel.matches(level)) {
logToConsole(level, message);
}
if(cc.logging.chatLevel.matches(level)) {
logToChat(level, message);
}
}
/**
* Directly log to the server console, no checks
*
* @param level
* @param message
*/
public void logToConsole(LogLevel level, String message) {
Logger.getLogger("Minecraft").log(level.level, message);
}
/**
* Directly log to the chat, no checks
*
* @param level
* @param message
*/
public void logToChat(LogLevel level, String message) {
for(Player player : Bukkit.getServer().getOnlinePlayers()) {
if(player.hasPermission(Permissions.ADMIN_CHATLOG)) {
player.sendMessage(message);
}
}
}
/**
* Directly log to the file, no checks
*
* @param level
* @param message
* @param fileLogger
*/
public void logToFile(LogLevel level, String message, Logger fileLogger) {
fileLogger.log(level.level, message);
}
}

View File

@ -1,8 +1,12 @@
package cc.co.evenprime.bukkit.nocheat.wizard;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.swing.BoxLayout;
import javax.swing.JButton;
@ -10,58 +14,168 @@ import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration;
import cc.co.evenprime.bukkit.nocheat.wizard.gui.ParentOptionGui;
import cc.co.evenprime.bukkit.nocheat.DefaultConfiguration;
import cc.co.evenprime.bukkit.nocheat.config.ConfigurationManager;
import cc.co.evenprime.bukkit.nocheat.config.tree.ConfigurationTree;
import cc.co.evenprime.bukkit.nocheat.wizard.gui.ConfigurationTreeGui;
/**
* The actual GUI for the configuration tool
*
* @author Evenprime
*
*/
public class Wizard extends JFrame {
/**
*
*/
private static final long serialVersionUID = 8798111079958779207L;
public static void main(String[] args) {
Wizard w = new Wizard();
w.setVisible(true);
}
private static final long serialVersionUID = 8798111079958773207L;
public static final Color disabled = Color.GRAY;
public static final Color enabled = Color.BLACK;
private class Wizard_JPanel extends JPanel {
private static final long serialVersionUID = 5748088661296418403L;
private final JPanel inside;
private ConfigurationTree tree;
/**
* Create a complete configuration screen based on a specific
* configuration tree
*
* @param tree
*/
private Wizard_JPanel(ConfigurationTree tree) {
JScrollPane scrollPane = new JScrollPane();
inside = new JPanel();
this.tree = tree;
scrollPane.setViewportView(inside);
this.setLayout(new BorderLayout());
inside.setLayout(new BoxLayout(inside, BoxLayout.Y_AXIS));
// Recursively walk through "defaults" tree and move stuff to our
// new real config tree, if it is not defined
// in our real tree already
final ConfigurationTree modelRoot = tree;
final ConfigurationTreeGui guiRoot = new ConfigurationTreeGui(modelRoot);
inside.add(guiRoot);
this.add(scrollPane, BorderLayout.CENTER);
}
/**
* Recreate the whole tree (e.g. in case the underlying model tree
* changed
*/
private void refresh() {
this.inside.removeAll();
this.inside.add(new ConfigurationTreeGui(tree));
}
}
private final JTabbedPane tabs;
private final Map<String, File> worldFiles;
private final Map<String, ConfigurationTree> worldTrees;
public Wizard() {
JScrollPane scrollable = new JScrollPane();
tabs = new JTabbedPane();
worldFiles = ConfigurationManager.getWorldSpecificConfigFiles("NoCheat");
worldTrees = new HashMap<String, ConfigurationTree>();
final File globalConfig = ConfigurationManager.getGlobalConfigFile("NoCheat");
ConfigurationTree globalTree;
try {
globalTree = ConfigurationManager.createFullConfigurationTree(DefaultConfiguration.buildDefaultConfigurationTree(), globalConfig);
} catch(Exception e) {
System.out.println("NoCheat: Couldn't use existing global config file " + globalConfig + ", creating a new file.");
globalTree = DefaultConfiguration.buildDefaultConfigurationTree();
}
worldTrees.put(null, globalTree);
for(String worldName : worldFiles.keySet()) {
ConfigurationTree worldTree;
try {
worldTree = ConfigurationManager.createPartialConfigurationTree(globalTree, worldFiles.get(worldName));
worldTrees.put(worldName, worldTree);
} catch(Exception e) {
System.out.println("NoCheat: Couldn't read existing world-specific config file for world " + worldName);
worldFiles.remove(worldName);
}
}
worldFiles.put(null, globalConfig);
setup();
}
private void setup() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setContentPane(scrollable);
this.setLayout(new BorderLayout());
JPanel inside = new JPanel();
scrollable.setViewportView(inside);
JButton saveAllButton = new JButton("Save All");
inside.setLayout(new BoxLayout(inside, BoxLayout.Y_AXIS));
tabs.addChangeListener(new ChangeListener() {
final NoCheatConfiguration config = new NoCheatConfiguration(new File("NoCheat/nocheat.yml"), new File("NoCheat/descriptions.txt"));
@Override
public void stateChanged(ChangeEvent arg0) {
((Wizard_JPanel) tabs.getSelectedComponent()).refresh();
}
});
ParentOptionGui root2 = new ParentOptionGui(config.getRoot());
Wizard_JPanel global = new Wizard_JPanel(worldTrees.get(null));
tabs.addTab("Global Settings", null, global, "The settings valid for all worlds, unless a specific setting overrides them.");
inside.add(root2);
for(String name : worldTrees.keySet()) {
if(name != null) {
Wizard_JPanel world = new Wizard_JPanel(worldTrees.get(name));
tabs.addTab(name + " Settings", null, world, "Some world-specific settings.");
}
}
JButton b = new JButton("Save");
b.addActionListener(new ActionListener() {
saveAllButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
NoCheatConfiguration.writeConfigFile(new File("NoCheat/nocheat.yml"), config);
for(String worldName : worldTrees.keySet()) {
ConfigurationManager.writeConfigFile(worldFiles.get(worldName), worldTrees.get(worldName));
}
JOptionPane.showMessageDialog(null, "Saved");
ConfigurationManager.writeDescriptionFile(ConfigurationManager.getDescriptionFile("NoCheat"), worldTrees.get(null));
DefaultConfiguration.writeDefaultActionFile(ConfigurationManager.getDefaultActionFile("NoCheat"));
DefaultConfiguration.writeActionFile(ConfigurationManager.getActionFile("NoCheat"));
JOptionPane.showMessageDialog(null, "Saved All");
}
});
b.setAlignmentY(0.0F);
inside.add(b);
this.doLayout();
saveAllButton.setAlignmentY(0.0F);
this.add(saveAllButton, BorderLayout.SOUTH);
this.pack();
this.setSize(900, 700);
this.setSize(1000, 700);
this.setTitle("NoCheat configuration utility");
this.add(tabs, BorderLayout.CENTER);
}
}

Some files were not shown because too many files have changed in this diff Show More