mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-01-14 19:41:21 +01:00
NoCheat 2.0 initial Commit
This commit is contained in:
parent
6d0da77e7d
commit
92620c4fd4
3
manifest
3
manifest
@ -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
|
||||
|
101
plugin.yml
101
plugin.yml
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
274
src/cc/co/evenprime/bukkit/nocheat/DefaultConfiguration.java
Normal file
274
src/cc/co/evenprime/bukkit/nocheat/DefaultConfiguration.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
70
src/cc/co/evenprime/bukkit/nocheat/Explainations.java
Normal file
70
src/cc/co/evenprime/bukkit/nocheat/Explainations.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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 + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
33
src/cc/co/evenprime/bukkit/nocheat/Permissions.java
Normal file
33
src/cc/co/evenprime/bukkit/nocheat/Permissions.java
Normal 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() {}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
82
src/cc/co/evenprime/bukkit/nocheat/actions/ActionList.java
Normal file
82
src/cc/co/evenprime/bukkit/nocheat/actions/ActionList.java
Normal 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();
|
||||
}
|
||||
}
|
126
src/cc/co/evenprime/bukkit/nocheat/actions/ActionManager.java
Normal file
126
src/cc/co/evenprime/bukkit/nocheat/actions/ActionManager.java
Normal 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());
|
||||
}
|
||||
}
|
@ -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";
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 "";
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
29
src/cc/co/evenprime/bukkit/nocheat/actions/types/Action.java
Normal file
29
src/cc/co/evenprime/bukkit/nocheat/actions/types/Action.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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()]);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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";
|
||||
}
|
||||
}
|
24
src/cc/co/evenprime/bukkit/nocheat/config/Configuration.java
Normal file
24
src/cc/co/evenprime/bukkit/nocheat/config/Configuration.java
Normal 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);
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
32
src/cc/co/evenprime/bukkit/nocheat/config/cache/CCBlockBreak.java
vendored
Normal file
32
src/cc/co/evenprime/bukkit/nocheat/config/cache/CCBlockBreak.java
vendored
Normal 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");
|
||||
}
|
||||
}
|
31
src/cc/co/evenprime/bukkit/nocheat/config/cache/CCLogging.java
vendored
Normal file
31
src/cc/co/evenprime/bukkit/nocheat/config/cache/CCLogging.java
vendored
Normal 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;
|
||||
}
|
||||
}
|
63
src/cc/co/evenprime/bukkit/nocheat/config/cache/CCMoving.java
vendored
Normal file
63
src/cc/co/evenprime/bukkit/nocheat/config/cache/CCMoving.java
vendored
Normal 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");
|
||||
|
||||
}
|
||||
}
|
32
src/cc/co/evenprime/bukkit/nocheat/config/cache/ConfigurationCache.java
vendored
Normal file
32
src/cc/co/evenprime/bukkit/nocheat/config/cache/ConfigurationCache.java
vendored
Normal 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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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" : "");
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
@ -1,8 +0,0 @@
|
||||
package cc.co.evenprime.bukkit.nocheat.data;
|
||||
|
||||
public class AirbuildData {
|
||||
|
||||
public int perFiveSeconds = 0;
|
||||
public int summaryTask = -1;
|
||||
|
||||
}
|
18
src/cc/co/evenprime/bukkit/nocheat/data/BlockBreakData.java
Normal file
18
src/cc/co/evenprime/bukkit/nocheat/data/BlockBreakData.java
Normal 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;
|
||||
}
|
56
src/cc/co/evenprime/bukkit/nocheat/data/DataManager.java
Normal file
56
src/cc/co/evenprime/bukkit/nocheat/data/DataManager.java
Normal 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;
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package cc.co.evenprime.bukkit.nocheat.data;
|
||||
|
||||
|
||||
public class InfinitedurabilityData {
|
||||
|
||||
public long lastLog = 0;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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() {}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package cc.co.evenprime.bukkit.nocheat.data;
|
||||
|
||||
public class NukeData {
|
||||
|
||||
public int counter = 0;
|
||||
|
||||
}
|
@ -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";
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
127
src/cc/co/evenprime/bukkit/nocheat/file/FlatConfigParser.java
Normal file
127
src/cc/co/evenprime/bukkit/nocheat/file/FlatConfigParser.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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)
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
56
src/cc/co/evenprime/bukkit/nocheat/log/LogLevel.java
Normal file
56
src/cc/co/evenprime/bukkit/nocheat/log/LogLevel.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
87
src/cc/co/evenprime/bukkit/nocheat/log/LogManager.java
Normal file
87
src/cc/co/evenprime/bukkit/nocheat/log/LogManager.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user