Code cleanup

This commit is contained in:
Evenprime 2011-03-04 20:38:54 +01:00
parent a2d443cb75
commit 45b4f11452
12 changed files with 548 additions and 547 deletions

View File

@ -3,5 +3,5 @@ name: NoCheatPlugin
author: Evenprime
main: cc.co.evenprime.bukkit.nocheat.NoCheatPlugin
version: 0.6.3
version: 0.6.3a

View File

@ -18,129 +18,129 @@ import org.bukkit.util.config.Configuration;
*
*/
public class NoCheatConfiguration {
// Our personal logger
public static final String loggerName = "cc.co.evenprime.bukkit.nocheat";
public static final Logger logger = Logger.getLogger(loggerName);
// Which checks are active
public static boolean speedhackCheckActive;
public static boolean movingCheckActive;
public static boolean airbuildCheckActive;
public static boolean dupebydeathCheckActive;
public static boolean bedteleportCheckActive;
// Limits for the speedhack check
public static int speedhackLimitLow;
public static int speedhackLimitMed;
public static int speedhackLimitHigh;
// How should speedhack violations be treated?
public static String speedhackActionMinor = "";
public static String speedhackActionNormal = "";
public static String speedhackActionHeavy = "";
public static int movingFreeMoves = 10;
// How should moving violations be treated?
public static String movingActionMinor = "";
public static String movingActionNormal = "";
public static String movingActionHeavy = "";
// How should airbuild violations be treated?
public static String airbuildAction = "";
// The log level above which players with the permission nocheat.notify will get informed about violations
public static Level notifyLevel = Level.OFF;
// Our two log outputs, the console and a file
private static ConsoleHandler ch = null;
private static FileHandler fh = null;
private NoCheatConfiguration() {}
/**
* Read the configuration file and assign either standard values or whatever is declared in the file
* @param configurationFile
*/
public static void config(File configurationFile) {
if(!configurationFile.exists()) {
createStandardConfigFile(configurationFile);
}
Configuration c = new Configuration(configurationFile);
c.load();
logger.setLevel(Level.INFO);
logger.setUseParentHandlers(false);
if(ch == null) {
ch = new ConsoleHandler();
ch.setLevel(stringToLevel(c.getString("logging.logtoconsole")));
ch.setFormatter(Logger.getLogger("Minecraft").getHandlers()[0].getFormatter());
logger.addHandler(ch);
}
if(fh == null) {
try {
fh = new FileHandler(c.getString("logging.filename"), true);
fh.setLevel(stringToLevel(c.getString("logging.logtofile")));
fh.setFormatter(Logger.getLogger("Minecraft").getHandlers()[0].getFormatter());
logger.addHandler(fh);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
notifyLevel = stringToLevel(c.getString("logging.logtonotify"));
speedhackCheckActive = c.getBoolean("active.speedhack", true);
movingCheckActive = c.getBoolean("active.moving", true);
airbuildCheckActive = c.getBoolean("active.airbuild", false);
dupebydeathCheckActive = c.getBoolean("active.dupebydeath", true);
bedteleportCheckActive = c.getBoolean("active.bedteleport", true);
speedhackLimitLow = c.getInt("speedhack.limits.low", 30);
speedhackLimitMed = c.getInt("speedhack.limits.med", 45);
speedhackLimitHigh = c.getInt("speedhack.limits.high", 60);
movingFreeMoves = c.getInt("moving.freemoves", 10);
movingActionMinor = c.getString("moving.action.low", "loglow reset");
movingActionNormal = c.getString("moving.action.med", "logmed reset");
movingActionHeavy = c.getString("moving.action.high", "loghigh reset");
speedhackActionMinor = c.getString("speedhack.action.low", "loglow");
speedhackActionNormal = c.getString("speedhack.action.med", "logmed");
speedhackActionHeavy = c.getString("speedhack.action.high", "loghigh");
airbuildAction = c.getString("airbuild.action", "logmed deny");
if(movingFreeMoves < 10) movingFreeMoves = 10;
}
/**
* Convert a string into a log level
* @param string
* @return
*/
private static Level stringToLevel(String string) {
if(string == null) {
return Level.OFF;
}
if(string.trim().equals("info") || string.trim().equals("low")) return Level.INFO;
if(string.trim().equals("warn") || string.trim().equals("med")) return Level.WARNING;
if(string.trim().equals("severe")|| string.trim().equals("high")) return Level.SEVERE;
return Level.OFF;
}
/**
* Standard configuration file for people who haven't got one yet
* @param f
@ -150,7 +150,7 @@ public class NoCheatConfiguration {
f.getParentFile().mkdirs();
f.createNewFile();
BufferedWriter w = new BufferedWriter(new FileWriter(f));
w.write("# Logging: potential log levels are low (info), med (warn), high (severe), off"); w.newLine();
w.write("logging:"); w.newLine();
w.write(" filename: plugins/NoCheat/nocheat.log"); w.newLine();

View File

@ -9,23 +9,21 @@ import org.bukkit.Location;
*
*/
public class NoCheatData {
/**
* Don't rely on any of these yet, they are likely going to change their name/functionality
*/
public int movingJumpPhase = 0; // current jumpingPhase
public int movingMinorViolationsInARow = 0;
public int movingNormalViolationsInARow = 0;
public int movingHeavyViolationsInARow = 0;
public Location movingSetBackPoint = null;
public int movingIgnoreNextXEvents = 0;
public long speedhackLastCheck = System.currentTimeMillis(); // timestamp of last check for speedhacks
public Location speedhackSetBackPoint = null;
public int speedhackEventsSinceLastCheck = 0; // used to identify speedhacks
public int speedhackViolationsInARow = 0;
NoCheatData() { }
}

View File

@ -22,46 +22,46 @@ import com.nijiko.permissions.PermissionHandler;
import org.bukkit.plugin.Plugin;
/**
*
* NoCheatPlugin
*
* Check various player events for their plausibilty and log/deny them based on configuration
*
* @author Evenprime
*/
*
* NoCheatPlugin
*
* Check various player events for their plausibilty and log/deny them based on configuration
*
* @author Evenprime
*/
public class NoCheatPlugin extends JavaPlugin {
// Various listeners needed for different Checks
private NoCheatPlayerListener playerListener;
private NoCheatBlockListener blockListener;
private NoCheatEntityListener entityListener;
// My main logger
private static Logger log;
private static NoCheatPlugin p;
// Permissions 2.0, if available
public static PermissionHandler Permissions = null;
// Store data between Events
public static Map<Player, NoCheatData> playerData = new HashMap<Player, NoCheatData>();
public NoCheatPlugin() {
p = this;
}
/**
* 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
*/
public static NoCheatData getPlayerData(Player p) {
NoCheatData data = null;
// Various listeners needed for different Checks
private NoCheatPlayerListener playerListener;
private NoCheatBlockListener blockListener;
private NoCheatEntityListener entityListener;
// My main logger
private static Logger log;
private static NoCheatPlugin p;
// Permissions 2.0, if available
public static PermissionHandler Permissions = null;
// Store data between Events
public static Map<Player, NoCheatData> playerData = new HashMap<Player, NoCheatData>();
public NoCheatPlugin() {
p = this;
}
/**
* 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
*/
public static NoCheatData getPlayerData(Player p) {
NoCheatData data = null;
if((data = playerData.get(p)) == null ) {
synchronized(playerData) {
data = playerData.get(p);
@ -72,98 +72,98 @@ public class NoCheatPlugin extends JavaPlugin {
}
}
}
return data;
}
}
public void onDisable() {
PluginDescriptionFile pdfFile = this.getDescription();
Logger.getLogger("Minecraft").info( "[NoCheatPlugin] version [" + pdfFile.getVersion() + "] is disabled.");
}
public void onDisable() {
PluginDescriptionFile pdfFile = this.getDescription();
Logger.getLogger("Minecraft").info( "[NoCheatPlugin] version [" + pdfFile.getVersion() + "] is disabled.");
}
public void onEnable() {
// Create our listeners and feed them with neccessary information
playerListener = new NoCheatPlayerListener();
blockListener = new NoCheatBlockListener();
entityListener = new NoCheatEntityListener();
public void onEnable() {
// Create our listeners and feed them with neccessary information
playerListener = new NoCheatPlayerListener();
blockListener = new NoCheatBlockListener();
entityListener = new NoCheatEntityListener();
log = NoCheatConfiguration.logger;
PluginManager pm = getServer().getPluginManager();
pm.registerEvent(Event.Type.PLAYER_MOVE, playerListener, Priority.Lowest, this); // needed for speedhack and moving checks
pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener, Priority.Monitor, this); // used to delete old data of users
pm.registerEvent(Event.Type.BLOCK_PLACED, blockListener, Priority.Low, this); // used for airbuild check
pm.registerEvent(Event.Type.ENTITY_DEATH, entityListener, Priority.Highest, this); // used for dupebydeath check
pm.registerEvent(Event.Type.PLAYER_TELEPORT, playerListener, Priority.Lowest, this); // used for teleportfrombed check
log = NoCheatConfiguration.logger;
PluginDescriptionFile pdfFile = this.getDescription();
// Get, if available, the Permissions plugin
setupPermissions();
// parse the nocheat.yml config file
setupConfig();
String checks = (NoCheatConfiguration.movingCheckActive ? "moving ": "") +
(NoCheatConfiguration.speedhackCheckActive ? "speedhack " : "") +
(NoCheatConfiguration.airbuildCheckActive ? "airbuild " : "") +
(NoCheatConfiguration.dupebydeathCheckActive ? "dupebydeath " : "") +
(NoCheatConfiguration.bedteleportCheckActive ? "bedteleport " : "");
Logger.getLogger("Minecraft").info( "[NoCheatPlugin] version [" + pdfFile.getVersion() + "] is enabled with the following checks: "+checks);
}
PluginManager pm = getServer().getPluginManager();
pm.registerEvent(Event.Type.PLAYER_MOVE, playerListener, Priority.Lowest, this); // needed for speedhack and moving checks
pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener, Priority.Monitor, this); // used to delete old data of users
pm.registerEvent(Event.Type.BLOCK_PLACED, blockListener, Priority.Low, this); // used for airbuild check
pm.registerEvent(Event.Type.ENTITY_DEATH, entityListener, Priority.Highest, this); // used for dupebydeath check
pm.registerEvent(Event.Type.PLAYER_TELEPORT, playerListener, Priority.Lowest, this); // used for teleportfrombed check
/**
* Get, if available, a reference to the Permissions-plugin
*/
public void setupPermissions() {
Permissions = null;
Plugin test = this.getServer().getPluginManager().getPlugin("Permissions");
PluginDescriptionFile pdfFile = this.getDescription();
if(test != null) {
Permissions = ((Permissions)test).getHandler();
if(Permissions == null) {
this.getServer().getPluginManager().enablePlugin(test);
}
Permissions = ((Permissions)test).getHandler();
}
if(Permissions == null) {
log.info("Nocheat couldn't find Permissions plugin. Fallback to 'isOp()' equals 'all allowed'.");
}
}
/**
* Log a violation message to all locations declared in the config file
* @param message
*/
private static void log(Level l, String message) {
if(l != null) {
logToChat(l, message);
log.log(l, message);
}
}
// Get, if available, the Permissions plugin
setupPermissions();
// parse the nocheat.yml config file
setupConfig();
String checks = (NoCheatConfiguration.movingCheckActive ? "moving ": "") +
(NoCheatConfiguration.speedhackCheckActive ? "speedhack " : "") +
(NoCheatConfiguration.airbuildCheckActive ? "airbuild " : "") +
(NoCheatConfiguration.dupebydeathCheckActive ? "dupebydeath " : "") +
(NoCheatConfiguration.bedteleportCheckActive ? "bedteleport " : "");
Logger.getLogger("Minecraft").info( "[NoCheatPlugin] version [" + pdfFile.getVersion() + "] is enabled with the following checks: "+checks);
}
/**
* Get, if available, a reference to the Permissions-plugin
*/
public void setupPermissions() {
Permissions = null;
Plugin test = this.getServer().getPluginManager().getPlugin("Permissions");
if(test != null) {
Permissions = ((Permissions)test).getHandler();
if(Permissions == null) {
this.getServer().getPluginManager().enablePlugin(test);
}
Permissions = ((Permissions)test).getHandler();
}
if(Permissions == null) {
log.info("Nocheat couldn't find Permissions plugin. Fallback to 'isOp()' equals 'all allowed'.");
}
}
/**
* Log a violation message to all locations declared in the config file
* @param message
*/
private static void log(Level l, String message) {
if(l != null) {
logToChat(l, message);
log.log(l, message);
}
}
private static void logToChat(Level l, String message) {
if(NoCheatConfiguration.notifyLevel.intValue() <= l.intValue()) {
for(Player player : p.getServer().getOnlinePlayers()) {
if((Permissions != null && Permissions.has(player, "nocheat.notify")) ||
(Permissions == null && player.isOp())) {
player.sendMessage("["+l.getName()+"] " + message);
}
}
}
}
public static void logAction(String actions, String message) {
if(actions == null) return;
private static void logToChat(Level l, String message) {
if(NoCheatConfiguration.notifyLevel.intValue() <= l.intValue()) {
for(Player player : p.getServer().getOnlinePlayers()) {
if((Permissions != null && Permissions.has(player, "nocheat.notify")) ||
(Permissions == null && player.isOp())) {
player.sendMessage("["+l.getName()+"] " + message);
}
}
}
}
public static void logAction(String actions, String message) {
if(actions == null) return;
// LOGGING IF NEEDED AND WHERE NEEDED
Level logLevel = null;
if(actions.contains("loglow")) {
logLevel = Level.INFO;
}
@ -173,15 +173,15 @@ public class NoCheatPlugin extends JavaPlugin {
if(actions.contains("loghigh")) {
logLevel = Level.SEVERE;
}
if(logLevel != null) {
NoCheatPlugin.log(logLevel, "NC: "+message);
}
}
/**
* Read the config file
*/
public void setupConfig() {
NoCheatConfiguration.config(new File("plugins/NoCheat/nocheat.yml"));
}
}
/**
* Read the config file
*/
public void setupConfig() {
NoCheatConfiguration.config(new File("plugins/NoCheat/nocheat.yml"));
}
}

View File

@ -40,17 +40,17 @@ public class AirbuildCheck {
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY(), l.getBlockZ()-1) == airId &&
w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY(), l.getBlockZ()+1) == airId)
action(NoCheatConfiguration.airbuildAction, event);
}
private static void action(String action, BlockPlaceEvent event) {
// LOG IF NEEDED
if(action.contains("log")) {
Location l = event.getBlockPlaced().getLocation();
NoCheatPlugin.logAction(action, "NoCheatPlugin: Airbuild violation: "+event.getPlayer().getName()+" tried to place block " + event.getBlockPlaced().getType() + " in the air at " + l.getBlockX() + "," + l.getBlockY() +"," + l.getBlockZ());
}
// DENY IF NEEDED
if(action.contains("deny")) {
event.setCancelled(true);

View File

@ -5,24 +5,29 @@ import org.bukkit.event.player.PlayerMoveEvent;
import cc.co.evenprime.bukkit.nocheat.NoCheatPlugin;
/**
*
* @author Evenprime
*
*/
public class BedteleportCheck {
public static void check(PlayerMoveEvent event) {
// Should we check at all
if(NoCheatPlugin.Permissions != null && NoCheatPlugin.Permissions.has(event.getPlayer(), "nocheat.bedteleport")) {
if(NoCheatPlugin.Permissions != null && NoCheatPlugin.Permissions.has(event.getPlayer(), "nocheat.bedteleport")) {
return;
}
else if(NoCheatPlugin.Permissions == null && event.getPlayer().isOp() ) {
return;
}
if(event.getFrom().getWorld().getBlockTypeIdAt(event.getFrom()) == Material.BED_BLOCK.getId()) {
double yRest = Math.floor(event.getFrom().getY()) - event.getFrom().getY();
if(yRest > 0.099 && yRest < 0.101)
// Don't allow the teleport
event.setCancelled(true);
}
if(event.getFrom().getWorld().getBlockTypeIdAt(event.getFrom()) == Material.BED_BLOCK.getId()) {
double yRest = Math.floor(event.getFrom().getY()) - event.getFrom().getY();
if(yRest > 0.099 && yRest < 0.101)
// Don't allow the teleport
event.setCancelled(true);
}
}
}

View File

@ -9,6 +9,11 @@ import org.bukkit.inventory.PlayerInventory;
import cc.co.evenprime.bukkit.nocheat.NoCheatPlugin;
/**
*
* @author Evenprime
*
*/
public class DupebydeathCheck {
/**
@ -16,7 +21,7 @@ public class DupebydeathCheck {
* @param event
*/
public static void playerDeath(EntityDeathEvent event) {
if(event.getEntity() instanceof Player) {
Player p = (Player)event.getEntity();
@ -28,7 +33,7 @@ public class DupebydeathCheck {
else if(NoCheatPlugin.Permissions == null && p.isOp() ) {
return;
}
PlayerInventory playerInventory = p.getInventory();
List<ItemStack> drops = event.getDrops();

View File

@ -21,304 +21,304 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatPlugin;
public class MovingCheck {
// previously-calculated upper bound values for jumps. Minecraft is very deterministic when it comes to jumps
// Each entry represents the maximum gain in height per move event.
private static double jumpingPhases[] = new double[]{ 0.501D, 0.34D, 0.26D, 0.17D, 0.09D, 0.02D, 0.00D, -0.07D, -0.15D, -0.22D, -0.29D, -0.36D, -0.43D, -0.49D };
// Each entry represents the maximum gain in height per move event.
private static double jumpingPhases[] = new double[]{ 0.501D, 0.34D, 0.26D, 0.17D, 0.09D, 0.02D, 0.00D, -0.07D, -0.15D, -0.22D, -0.29D, -0.36D, -0.43D, -0.49D };
// Limits for the moving check
public static double movingDistanceLow = 0.1D;
public static double movingDistanceMed = 2.0D;
public static double movingDistanceHigh = 5.0D;
// Block types that may be treated specially
private enum BlockType {
// Block types that may be treated specially
private enum BlockType {
SOLID, NONSOLID, LADDER, LIQUID, UNKNOWN;
}
// Until I can think of a better way to determine if a block is solid or not, this is what I'll do
private static BlockType types[] = new BlockType[256];
static {
for(int i = 0; i < types.length; i++) {
types[i] = BlockType.UNKNOWN;
}
types[Material.AIR.getId()] = BlockType.NONSOLID;
types[Material.STONE.getId()] = BlockType.SOLID;
types[Material.GRASS.getId()] = BlockType.SOLID;
types[Material.DIRT.getId()] = BlockType.SOLID;
types[Material.COBBLESTONE.getId()] = BlockType.SOLID;
types[Material.WOOD.getId()] = BlockType.SOLID;
types[Material.SAPLING.getId()] = BlockType.NONSOLID;
types[Material.BEDROCK.getId()] = BlockType.SOLID;
types[Material.WATER.getId()] = BlockType.LIQUID;
types[Material.STATIONARY_WATER.getId()] = BlockType.LIQUID;
types[Material.LAVA.getId()] = BlockType.LIQUID;
types[Material.STATIONARY_LAVA.getId()] = BlockType.LIQUID;
types[Material.SAND.getId()] = BlockType.SOLID;
types[Material.GRAVEL.getId()] = BlockType.SOLID;
types[Material.GOLD_ORE.getId()] = BlockType.SOLID;
types[Material.IRON_ORE.getId()] = BlockType.SOLID;
types[Material.COAL_ORE.getId()] = BlockType.SOLID;
types[Material.LOG.getId()] = BlockType.SOLID;
types[Material.LEAVES.getId()] = BlockType.SOLID;
types[Material.SPONGE.getId()] = BlockType.SOLID;
types[Material.GLASS.getId()] = BlockType.SOLID;
types[Material.LAPIS_ORE.getId()] = BlockType.SOLID;
types[Material.LAPIS_BLOCK.getId()] = BlockType.SOLID;
types[Material.DISPENSER.getId()] = BlockType.SOLID;
types[Material.SANDSTONE.getId()] = BlockType.SOLID;
types[Material.NOTE_BLOCK.getId()]= BlockType.SOLID;
types[Material.WOOL.getId()]= BlockType.SOLID;
types[Material.YELLOW_FLOWER.getId()]= BlockType.NONSOLID;
types[Material.RED_ROSE.getId()]= BlockType.NONSOLID;
types[Material.BROWN_MUSHROOM.getId()]= BlockType.NONSOLID;
types[Material.RED_MUSHROOM.getId()]= BlockType.NONSOLID;
types[Material.GOLD_BLOCK.getId()]= BlockType.SOLID;
types[Material.IRON_BLOCK.getId()]= BlockType.SOLID;
types[Material.DOUBLE_STEP.getId()]= BlockType.UNKNOWN;
types[Material.STEP.getId()]= BlockType.UNKNOWN;
types[Material.BRICK.getId()]= BlockType.SOLID;
types[Material.TNT.getId()]= BlockType.SOLID;
types[Material.BOOKSHELF.getId()]= BlockType.SOLID;
types[Material.MOSSY_COBBLESTONE.getId()] = BlockType.SOLID;
types[Material.OBSIDIAN.getId()]= BlockType.SOLID;
types[Material.TORCH.getId()]= BlockType.NONSOLID;
types[Material.FIRE.getId()]= BlockType.NONSOLID;
types[Material.MOB_SPAWNER.getId()]= BlockType.SOLID;
types[Material.WOOD_STAIRS.getId()]= BlockType.UNKNOWN;
types[Material.CHEST.getId()]= BlockType.SOLID;
types[Material.REDSTONE_WIRE.getId()]= BlockType.NONSOLID;
types[Material.DIAMOND_ORE.getId()]= BlockType.SOLID;
types[Material.DIAMOND_BLOCK.getId()]= BlockType.SOLID;
types[Material.WORKBENCH.getId()]= BlockType.SOLID;
types[Material.CROPS.getId()]= BlockType.NONSOLID;
types[Material.SOIL.getId()]= BlockType.SOLID;
types[Material.FURNACE.getId()]= BlockType.SOLID;
types[Material.BURNING_FURNACE.getId()]= BlockType.SOLID;
types[Material.SIGN_POST.getId()]= BlockType.NONSOLID;
types[Material.WOODEN_DOOR.getId()]= BlockType.NONSOLID;
types[Material.LADDER.getId()]= BlockType.LADDER;
types[Material.RAILS.getId()]= BlockType.NONSOLID;
types[Material.COBBLESTONE_STAIRS.getId()]= BlockType.UNKNOWN;
types[Material.WALL_SIGN.getId()]= BlockType.NONSOLID;
types[Material.LEVER.getId()]= BlockType.NONSOLID;
types[Material.STONE_PLATE.getId()]= BlockType.UNKNOWN;
types[Material.IRON_DOOR_BLOCK.getId()]= BlockType.NONSOLID;
types[Material.WOOD_PLATE.getId()]= BlockType.NONSOLID;
types[Material.REDSTONE_ORE.getId()]= BlockType.SOLID;
types[Material.GLOWING_REDSTONE_ORE.getId()]= BlockType.SOLID;
types[Material.REDSTONE_TORCH_OFF.getId()]= BlockType.NONSOLID;
types[Material.REDSTONE_TORCH_ON.getId()]= BlockType.NONSOLID;
types[Material.STONE_BUTTON.getId()]= BlockType.NONSOLID;
types[Material.SNOW.getId()]= BlockType.UNKNOWN;
types[Material.ICE.getId()]= BlockType.UNKNOWN;
types[Material.SNOW_BLOCK.getId()]= BlockType.SOLID;
types[Material.CACTUS.getId()]= BlockType.SOLID;
types[Material.CLAY.getId()]= BlockType.SOLID;
types[Material.SUGAR_CANE_BLOCK.getId()]= BlockType.NONSOLID;
types[Material.JUKEBOX.getId()]= BlockType.SOLID;
types[Material.FENCE.getId()]= BlockType.UNKNOWN;
types[Material.PUMPKIN.getId()]= BlockType.SOLID;
types[Material.NETHERRACK.getId()]= BlockType.SOLID;
types[Material.SOUL_SAND.getId()]= BlockType.UNKNOWN;
types[Material.GLOWSTONE.getId()]= BlockType.SOLID;
types[Material.PORTAL.getId()]= BlockType.NONSOLID;
types[Material.JACK_O_LANTERN.getId()]= BlockType.SOLID;
types[Material.CAKE_BLOCK.getId()]= BlockType.UNKNOWN;
}
// Until I can think of a better way to determine if a block is solid or not, this is what I'll do
private static BlockType types[] = new BlockType[256];
static {
for(int i = 0; i < types.length; i++) {
types[i] = BlockType.UNKNOWN;
}
types[Material.AIR.getId()] = BlockType.NONSOLID;
types[Material.STONE.getId()] = BlockType.SOLID;
types[Material.GRASS.getId()] = BlockType.SOLID;
types[Material.DIRT.getId()] = BlockType.SOLID;
types[Material.COBBLESTONE.getId()] = BlockType.SOLID;
types[Material.WOOD.getId()] = BlockType.SOLID;
types[Material.SAPLING.getId()] = BlockType.NONSOLID;
types[Material.BEDROCK.getId()] = BlockType.SOLID;
types[Material.WATER.getId()] = BlockType.LIQUID;
types[Material.STATIONARY_WATER.getId()] = BlockType.LIQUID;
types[Material.LAVA.getId()] = BlockType.LIQUID;
types[Material.STATIONARY_LAVA.getId()] = BlockType.LIQUID;
types[Material.SAND.getId()] = BlockType.SOLID;
types[Material.GRAVEL.getId()] = BlockType.SOLID;
types[Material.GOLD_ORE.getId()] = BlockType.SOLID;
types[Material.IRON_ORE.getId()] = BlockType.SOLID;
types[Material.COAL_ORE.getId()] = BlockType.SOLID;
types[Material.LOG.getId()] = BlockType.SOLID;
types[Material.LEAVES.getId()] = BlockType.SOLID;
types[Material.SPONGE.getId()] = BlockType.SOLID;
types[Material.GLASS.getId()] = BlockType.SOLID;
types[Material.LAPIS_ORE.getId()] = BlockType.SOLID;
types[Material.LAPIS_BLOCK.getId()] = BlockType.SOLID;
types[Material.DISPENSER.getId()] = BlockType.SOLID;
types[Material.SANDSTONE.getId()] = BlockType.SOLID;
types[Material.NOTE_BLOCK.getId()]= BlockType.SOLID;
types[Material.WOOL.getId()]= BlockType.SOLID;
types[Material.YELLOW_FLOWER.getId()]= BlockType.NONSOLID;
types[Material.RED_ROSE.getId()]= BlockType.NONSOLID;
types[Material.BROWN_MUSHROOM.getId()]= BlockType.NONSOLID;
types[Material.RED_MUSHROOM.getId()]= BlockType.NONSOLID;
types[Material.GOLD_BLOCK.getId()]= BlockType.SOLID;
types[Material.IRON_BLOCK.getId()]= BlockType.SOLID;
types[Material.DOUBLE_STEP.getId()]= BlockType.UNKNOWN;
types[Material.STEP.getId()]= BlockType.UNKNOWN;
types[Material.BRICK.getId()]= BlockType.SOLID;
types[Material.TNT.getId()]= BlockType.SOLID;
types[Material.BOOKSHELF.getId()]= BlockType.SOLID;
types[Material.MOSSY_COBBLESTONE.getId()] = BlockType.SOLID;
types[Material.OBSIDIAN.getId()]= BlockType.SOLID;
types[Material.TORCH.getId()]= BlockType.NONSOLID;
types[Material.FIRE.getId()]= BlockType.NONSOLID;
types[Material.MOB_SPAWNER.getId()]= BlockType.SOLID;
types[Material.WOOD_STAIRS.getId()]= BlockType.UNKNOWN;
types[Material.CHEST.getId()]= BlockType.SOLID;
types[Material.REDSTONE_WIRE.getId()]= BlockType.NONSOLID;
types[Material.DIAMOND_ORE.getId()]= BlockType.SOLID;
types[Material.DIAMOND_BLOCK.getId()]= BlockType.SOLID;
types[Material.WORKBENCH.getId()]= BlockType.SOLID;
types[Material.CROPS.getId()]= BlockType.NONSOLID;
types[Material.SOIL.getId()]= BlockType.SOLID;
types[Material.FURNACE.getId()]= BlockType.SOLID;
types[Material.BURNING_FURNACE.getId()]= BlockType.SOLID;
types[Material.SIGN_POST.getId()]= BlockType.NONSOLID;
types[Material.WOODEN_DOOR.getId()]= BlockType.NONSOLID;
types[Material.LADDER.getId()]= BlockType.LADDER;
types[Material.RAILS.getId()]= BlockType.NONSOLID;
types[Material.COBBLESTONE_STAIRS.getId()]= BlockType.UNKNOWN;
types[Material.WALL_SIGN.getId()]= BlockType.NONSOLID;
types[Material.LEVER.getId()]= BlockType.NONSOLID;
types[Material.STONE_PLATE.getId()]= BlockType.UNKNOWN;
types[Material.IRON_DOOR_BLOCK.getId()]= BlockType.NONSOLID;
types[Material.WOOD_PLATE.getId()]= BlockType.NONSOLID;
types[Material.REDSTONE_ORE.getId()]= BlockType.SOLID;
types[Material.GLOWING_REDSTONE_ORE.getId()]= BlockType.SOLID;
types[Material.REDSTONE_TORCH_OFF.getId()]= BlockType.NONSOLID;
types[Material.REDSTONE_TORCH_ON.getId()]= BlockType.NONSOLID;
types[Material.STONE_BUTTON.getId()]= BlockType.NONSOLID;
types[Material.SNOW.getId()]= BlockType.UNKNOWN;
types[Material.ICE.getId()]= BlockType.UNKNOWN;
types[Material.SNOW_BLOCK.getId()]= BlockType.SOLID;
types[Material.CACTUS.getId()]= BlockType.SOLID;
types[Material.CLAY.getId()]= BlockType.SOLID;
types[Material.SUGAR_CANE_BLOCK.getId()]= BlockType.NONSOLID;
types[Material.JUKEBOX.getId()]= BlockType.SOLID;
types[Material.FENCE.getId()]= BlockType.UNKNOWN;
types[Material.PUMPKIN.getId()]= BlockType.SOLID;
types[Material.NETHERRACK.getId()]= BlockType.SOLID;
types[Material.SOUL_SAND.getId()]= BlockType.UNKNOWN;
types[Material.GLOWSTONE.getId()]= BlockType.SOLID;
types[Material.PORTAL.getId()]= BlockType.NONSOLID;
types[Material.JACK_O_LANTERN.getId()]= BlockType.SOLID;
types[Material.CAKE_BLOCK.getId()]= BlockType.UNKNOWN;
}
public static void check(NoCheatData data, PlayerMoveEvent event) {
// Should we check at all
if(NoCheatPlugin.Permissions != null && NoCheatPlugin.Permissions.has(event.getPlayer(), "nocheat.moving")) {
if(NoCheatPlugin.Permissions != null && NoCheatPlugin.Permissions.has(event.getPlayer(), "nocheat.moving")) {
return;
}
else if(NoCheatPlugin.Permissions == null && event.getPlayer().isOp() ) {
return;
}
// Get the two locations of the event
// Get the two locations of the event
Location from = event.getFrom();
Location to = event.getTo();
System.out.println(from.getY() + " " + to.getY());
// First check the distance the player has moved horizontally
// TODO: Make this check much more precise
double xDistance = Math.abs(from.getX() - to.getX());
double zDistance = Math.abs(from.getZ() - to.getZ());
double combined = xDistance * xDistance + zDistance * zDistance;
// First check the distance the player has moved horizontally
// TODO: Make this check much more precise
double xDistance = Math.abs(from.getX() - to.getX());
double zDistance = Math.abs(from.getZ() - to.getZ());
double combined = xDistance * xDistance + zDistance * zDistance;
// If the target is a bed and distance not too big, allow it
if(to.getWorld().getBlockTypeIdAt(to) == Material.BED_BLOCK.getId() && xDistance < 5.0D && zDistance < 5.0D) {
return; // players are allowed to "teleport" into a bed over short distances
}
if(to.getWorld().getBlockTypeIdAt(to) == Material.BED_BLOCK.getId() && xDistance < 5.0D && zDistance < 5.0D) {
return; // players are allowed to "teleport" into a bed over short distances
}
Level vl = null; // The violation level (none, minor, normal, heavy)
// How far are we off?
if(combined > movingDistanceHigh) {
vl = max(vl, Level.SEVERE);
}
else if(combined > movingDistanceMed) {
vl = max(vl, Level.WARNING);
}
else if(combined > movingDistanceLow) {
vl = max(vl, Level.INFO);
}
// pre-calculate boundary values that are needed multiple times in the following checks
// the array each contains [lowerX, higherX, Y, lowerZ, higherZ]
int fromValues[] = {floor_double(from.getX() - 0.3D), (int)Math.floor(from.getX() + 0.3D), from.getBlockY(), floor_double(from.getZ() - 0.3D),(int)Math.floor(from.getZ() + 0.3D) };
int toValues[] = {floor_double(to.getX() - 0.3D), (int)Math.floor(to.getX() + 0.3D), to.getBlockY(), floor_double(to.getZ() - 0.3D), (int)Math.floor(to.getZ() + 0.3D) };
// compare locations to the world to guess if the player is standing on the ground, a half-block or next to a ladder
boolean onGroundFrom = playerIsOnGround(from.getWorld(), fromValues, from);
boolean onGroundTo = playerIsOnGround(from.getWorld(), toValues, to);
// How far are we off?
if(combined > movingDistanceHigh) {
vl = max(vl, Level.SEVERE);
}
else if(combined > movingDistanceMed) {
vl = max(vl, Level.WARNING);
}
else if(combined > movingDistanceLow) {
vl = max(vl, Level.INFO);
}
// Both locations seem to be on solid ground or at a ladder
if(onGroundFrom && onGroundTo)
{
// reset jumping
data.movingJumpPhase = 0;
// pre-calculate boundary values that are needed multiple times in the following checks
// the array each contains [lowerX, higherX, Y, lowerZ, higherZ]
int fromValues[] = {floor_double(from.getX() - 0.3D), (int)Math.floor(from.getX() + 0.3D), from.getBlockY(), floor_double(from.getZ() - 0.3D),(int)Math.floor(from.getZ() + 0.3D) };
int toValues[] = {floor_double(to.getX() - 0.3D), (int)Math.floor(to.getX() + 0.3D), to.getBlockY(), floor_double(to.getZ() - 0.3D), (int)Math.floor(to.getZ() + 0.3D) };
// Check if the player isn't 'walking' up unrealistically far in one step
// Finally found out why this can happen:
// If a player runs into a wall at an angle from above, the game tries to
// place him above the block he bumped into, by placing him 0.5 m above
// the target block
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
// compare locations to the world to guess if the player is standing on the ground, a half-block or next to a ladder
boolean onGroundFrom = playerIsOnGround(from.getWorld(), fromValues, from);
boolean onGroundTo = playerIsOnGround(from.getWorld(), toValues, to);
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
// Both locations seem to be on solid ground or at a ladder
if(onGroundFrom && onGroundTo)
{
// reset jumping
data.movingJumpPhase = 0;
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
}
// player is starting to jump (or starting to fall down somewhere)
else if(onGroundFrom && !onGroundTo)
{
// reset jumping
data.movingJumpPhase = 0;
// Check if the player isn't 'walking' up unrealistically far in one step
// Finally found out why this can happen:
// If a player runs into a wall at an angle from above, the game tries to
// place him above the block he bumped into, by placing him 0.5 m above
// the target block
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
// Check if player isn't jumping too high
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
}
// player is starting to jump (or starting to fall down somewhere)
else if(onGroundFrom && !onGroundTo)
{
// reset jumping
data.movingJumpPhase = 0;
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
else if(to.getY() <= from.getY()) {
// Very special case if running over a cliff and then immediately jumping.
// Some sort of "air jump", MC allows it, so we have to do so too.
}
else data.movingJumpPhase++; // Setup next phase of the jump
}
// player is probably landing somewhere
else if(!onGroundFrom && onGroundTo)
{
// Check if player isn't landing to high (sounds weird, but has its use)
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
// Check if player isn't jumping too high
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
else {
data.movingJumpPhase = 0; // He is on ground now, so reset the jump
}
}
// Player is moving through air (during jumping, falling)
else {
// May also be at the very edge of a platform (I seem to not be able to reliably tell if that's the case)
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
else if(to.getY() <= from.getY()) {
// Very special case if running over a cliff and then immediately jumping.
// Some sort of "air jump", MC allows it, so we have to do so too.
}
else data.movingJumpPhase++; // Setup next phase of the jump
}
// player is probably landing somewhere
else if(!onGroundFrom && onGroundTo)
{
// Check if player isn't landing to high (sounds weird, but has its use)
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
else {
data.movingJumpPhase = 0; // He is on ground now, so reset the jump
}
}
// Player is moving through air (during jumping, falling)
else {
// May also be at the very edge of a platform (I seem to not be able to reliably tell if that's the case)
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
data.movingJumpPhase++; // Enter next phase of the flight
}
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
// do a security check on the jumping phase, such that we don't get
// OutOfArrayBoundsExceptions at long air times (falling off high places)
if(!(data.movingJumpPhase < jumpingPhases.length)) {
data.movingJumpPhase = jumpingPhases.length - 1;
}
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
if(vl == null) {
legitimateMove(data, event);
}
else {
String actions = null;
boolean log = true;
// If it is the first violation, store the "from" location for potential later use
if(data.movingSetBackPoint == null) {
data.movingSetBackPoint = event.getFrom().clone();
}
// Find out with what actions to treat the violation(s)
if(Level.INFO.equals(vl)) {
data.movingMinorViolationsInARow++;
data.movingJumpPhase++; // Enter next phase of the flight
}
actions = NoCheatConfiguration.movingActionMinor;
// do a security check on the jumping phase, such that we don't get
// OutOfArrayBoundsExceptions at long air times (falling off high places)
if(!(data.movingJumpPhase < jumpingPhases.length)) {
data.movingJumpPhase = jumpingPhases.length - 1;
}
// React only after the freebee illegal moves have all been used
if(data.movingMinorViolationsInARow % (NoCheatConfiguration.movingFreeMoves) != 0) {
vl = null;
actions = null;
}
if(data.movingMinorViolationsInARow != NoCheatConfiguration.movingFreeMoves) {
log = false;
}
if(vl == null) {
legitimateMove(data, event);
}
else {
String actions = null;
boolean log = true;
// using up all free moves 4 times in a row counts as one normal violation
if(data.movingMinorViolationsInARow % (NoCheatConfiguration.movingFreeMoves * 4) == 0) {
vl = Level.WARNING;
log = true;
}
}
if(Level.WARNING.equals(vl)) {
if(data.movingNormalViolationsInARow > 0) log = false;
data.movingNormalViolationsInARow++;
actions = NoCheatConfiguration.movingActionNormal;
}
// If it is the first violation, store the "from" location for potential later use
if(data.movingSetBackPoint == null) {
data.movingSetBackPoint = event.getFrom().clone();
}
if(Level.SEVERE.equals(vl)) {
if(data.movingHeavyViolationsInARow > 0) log = false;
data.movingHeavyViolationsInARow++;
actions = NoCheatConfiguration.movingActionHeavy;
}
// Find out with what actions to treat the violation(s)
if(Level.INFO.equals(vl)) {
data.movingMinorViolationsInARow++;
action(event, actions, log);
}
actions = NoCheatConfiguration.movingActionMinor;
// React only after the freebee illegal moves have all been used
if(data.movingMinorViolationsInARow % (NoCheatConfiguration.movingFreeMoves) != 0) {
vl = null;
actions = null;
}
if(data.movingMinorViolationsInARow != NoCheatConfiguration.movingFreeMoves) {
log = false;
}
// using up all free moves 4 times in a row counts as one normal violation
if(data.movingMinorViolationsInARow % (NoCheatConfiguration.movingFreeMoves * 4) == 0) {
vl = Level.WARNING;
log = true;
}
}
if(Level.WARNING.equals(vl)) {
if(data.movingNormalViolationsInARow > 0) log = false;
data.movingNormalViolationsInARow++;
actions = NoCheatConfiguration.movingActionNormal;
}
if(Level.SEVERE.equals(vl)) {
if(data.movingHeavyViolationsInARow > 0) log = false;
data.movingHeavyViolationsInARow++;
actions = NoCheatConfiguration.movingActionHeavy;
}
action(event, actions, log);
}
}
/**
* Perform actions that were specified by the player
* @param event
* @param actions
*/
private static void action(PlayerMoveEvent event, String actions, boolean log) {
if(actions == null) return;
// LOGGING IF NEEDED
if(log && actions.contains("log")) {
NoCheatPlugin.logAction(actions, "Moving violation: "+event.getPlayer().getName()+" from " + String.format("(%.5f, %.5f, %.5f) to (%.5f, %.5f, %.5f)", event.getFrom().getX(), event.getFrom().getY(), event.getFrom().getZ(), event.getTo().getX(), event.getTo().getY(), event.getTo().getZ()));
}
// RESET IF NEEDED
if(actions.contains("reset")) {
resetPlayer(event);
@ -341,12 +341,12 @@ public class MovingCheck {
NoCheatPlugin.logAction(NoCheatConfiguration.movingActionMinor, "Moving violation ended: "+event.getPlayer().getName()+ " total Events: "+ data.movingMinorViolationsInARow);
data.movingMinorViolationsInARow = 0;
}
data.movingMinorViolationsInARow = 0;
data.movingSetBackPoint = null;
}
private static Level max(Level l1, Level l2) {
if(l1 == null) return l2;
if(l2 == null) return l1;
@ -360,9 +360,9 @@ public class MovingCheck {
* @param event
*/
private static void resetPlayer(PlayerMoveEvent event) {
NoCheatData data = NoCheatPlugin.getPlayerData(event.getPlayer());
// Still not a perfect solution. After resetting a player his vertical momentum gets lost
// Therefore we can't expect him to fall big distances in his next move, therefore we have to
// set his flying phase to something he can work with.
@ -372,7 +372,7 @@ public class MovingCheck {
// If we have stored a location for the player, we put him back there
if(data.movingSetBackPoint != null) {
// Lets try it that way. Maybe now people don't "disappear" any longer
event.setFrom(data.movingSetBackPoint);
event.setTo(data.movingSetBackPoint);
@ -386,66 +386,66 @@ public class MovingCheck {
}
}
/**
* Check the four edges of the player's approximated Bounding Box for blocks or ladders,
* at his own height (values[2]) and below his feet (values[2]-1). Also, check at his "head"
* for ladders.
*
* If there is one, the player is considered as standing on it/hanging to it.
*
* Not perfect at all and will produce some false negatives. Probably will be refined
* later.
*
* @param w The world the coordinates belong to
* @param values The coordinates [lowerX, higherX, Y, lowerZ, higherZ]
* @return
*/
private static boolean playerIsOnGround(World w, int values[], Location l) {
// Completely revamped collision detection
// What it does:
// Check the blocks below the player. If they aren't not solid (sic!) and the blocks directly above
// them aren't solid, The player is considered to be standing on the lower block
// Plus the player can hang onto a ladder that is one field above him
// Check the four borders of the players hitbox for something he could be standing on
if(types[w.getBlockTypeIdAt(values[0], values[2]-1, values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2]-1, values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[0], values[2]-1, values[4])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2]-1, values[4])] != BlockType.NONSOLID )
return true;
// Check if he is hanging onto a ladder
else if(types[w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY(), l.getBlockZ())] == BlockType.LADDER ||
types[w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY()+1, l.getBlockZ())] == BlockType.LADDER)
return true;
// check if he is standing "in" an block that's potentially solid (we give him the benefit of a doubt and see that as a legit move)
// If it is not legit, the MC server already has a safeguard against that (You'll get "xy moved wrongly" on the console in that case)
else if(types[w.getBlockTypeIdAt(values[0], values[2], values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2], values[3])] != BlockType.NONSOLID||
types[w.getBlockTypeIdAt(values[0], values[2], values[4])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2], values[4])] != BlockType.NONSOLID)
return true;
// check if his head is "stuck" in an block that's potentially solid (we give him the benefit of a doubt and see that as a legit move)
// If it is not legit, the MC server already has a safeguard against that (You'll get "xy moved wrongly" on the console in that case)
else if(types[w.getBlockTypeIdAt(values[0], values[2]+1, values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2]+1, values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[0], values[2]+1, values[4])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2]+1, values[4])] != BlockType.NONSOLID)
return true;
// Allow using a bug called "water elevator"
else if(types[w.getBlockTypeIdAt(values[0]+1, values[2]-1, values[3]+1)] == BlockType.LIQUID ||
types[w.getBlockTypeIdAt(values[0]+1, values[2], values[3]+1)] == BlockType.LIQUID ||
types[w.getBlockTypeIdAt(values[0]+1, values[2]+1, values[3]+1)] == BlockType.LIQUID)
return true;
else
return false;
}
public static int floor_double(double d)
{
int i = (int)d;
return d > (double)i ? i : i - 1;
}
/**
* Check the four edges of the player's approximated Bounding Box for blocks or ladders,
* at his own height (values[2]) and below his feet (values[2]-1). Also, check at his "head"
* for ladders.
*
* If there is one, the player is considered as standing on it/hanging to it.
*
* Not perfect at all and will produce some false negatives. Probably will be refined
* later.
*
* @param w The world the coordinates belong to
* @param values The coordinates [lowerX, higherX, Y, lowerZ, higherZ]
* @return
*/
private static boolean playerIsOnGround(World w, int values[], Location l) {
// Completely revamped collision detection
// What it does:
// Check the blocks below the player. If they aren't not solid (sic!) and the blocks directly above
// them aren't solid, The player is considered to be standing on the lower block
// Plus the player can hang onto a ladder that is one field above him
// Check the four borders of the players hitbox for something he could be standing on
if(types[w.getBlockTypeIdAt(values[0], values[2]-1, values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2]-1, values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[0], values[2]-1, values[4])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2]-1, values[4])] != BlockType.NONSOLID )
return true;
// Check if he is hanging onto a ladder
else if(types[w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY(), l.getBlockZ())] == BlockType.LADDER ||
types[w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY()+1, l.getBlockZ())] == BlockType.LADDER)
return true;
// check if he is standing "in" an block that's potentially solid (we give him the benefit of a doubt and see that as a legit move)
// If it is not legit, the MC server already has a safeguard against that (You'll get "xy moved wrongly" on the console in that case)
else if(types[w.getBlockTypeIdAt(values[0], values[2], values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2], values[3])] != BlockType.NONSOLID||
types[w.getBlockTypeIdAt(values[0], values[2], values[4])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2], values[4])] != BlockType.NONSOLID)
return true;
// check if his head is "stuck" in an block that's potentially solid (we give him the benefit of a doubt and see that as a legit move)
// If it is not legit, the MC server already has a safeguard against that (You'll get "xy moved wrongly" on the console in that case)
else if(types[w.getBlockTypeIdAt(values[0], values[2]+1, values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2]+1, values[3])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[0], values[2]+1, values[4])] != BlockType.NONSOLID ||
types[w.getBlockTypeIdAt(values[1], values[2]+1, values[4])] != BlockType.NONSOLID)
return true;
// Allow using a bug called "water elevator"
else if(types[w.getBlockTypeIdAt(values[0]+1, values[2]-1, values[3]+1)] == BlockType.LIQUID ||
types[w.getBlockTypeIdAt(values[0]+1, values[2], values[3]+1)] == BlockType.LIQUID ||
types[w.getBlockTypeIdAt(values[0]+1, values[2]+1, values[3]+1)] == BlockType.LIQUID)
return true;
else
return false;
}
public static int floor_double(double d)
{
int i = (int)d;
return d > (double)i ? i : i - 1;
}
}

View File

@ -14,12 +14,12 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatPlugin;
*/
public class SpeedhackCheck {
private static final long interval = 1000;
private static final int violationsLimit = 3;
private static final long interval = 1000;
private static final int violationsLimit = 3;
public static void check(NoCheatData data, PlayerMoveEvent event) {
// Should we check at all?
if(NoCheatPlugin.Permissions != null && NoCheatPlugin.Permissions.has(event.getPlayer(), "nocheat.speedhack")) {
return;
@ -27,10 +27,10 @@ public class SpeedhackCheck {
else if(NoCheatPlugin.Permissions == null && event.getPlayer().isOp() ) {
return;
}
// Get the time of the server
long time = System.currentTimeMillis();
// Is it time for a speedhack check now?
if(time > interval + data.speedhackLastCheck ) {
// Yes
@ -41,11 +41,11 @@ public class SpeedhackCheck {
int limitMed = (int)((NoCheatConfiguration.speedhackLimitMed * (time - data.speedhackLastCheck)) / interval);
int limitHigh = (int)((NoCheatConfiguration.speedhackLimitHigh * (time - data.speedhackLastCheck)) / interval);
if(data.speedhackEventsSinceLastCheck > limitHigh) action = NoCheatConfiguration.speedhackActionHeavy;
else if(data.speedhackEventsSinceLastCheck > limitMed) action = NoCheatConfiguration.speedhackActionNormal;
else if(data.speedhackEventsSinceLastCheck > limitLow) action = NoCheatConfiguration.speedhackActionMinor;
if(action == null) {
data.speedhackSetBackPoint = event.getFrom().clone();
data.speedhackViolationsInARow = 0;
@ -53,22 +53,22 @@ public class SpeedhackCheck {
else {
data.speedhackViolationsInARow++;
}
if(data.speedhackViolationsInARow >= violationsLimit) {
action(action, event, data);
}
// Reset values for next check
data.speedhackEventsSinceLastCheck = 0;
data.speedhackLastCheck = time;
}
data.speedhackEventsSinceLastCheck++;
}
private static void action(String actions, PlayerMoveEvent event, NoCheatData data) {
if(actions == null) return;
// LOGGING IF NEEDED
if(actions.contains("log")) {
@ -79,12 +79,12 @@ public class SpeedhackCheck {
resetPlayer(event, data);
}
}
private static void resetPlayer(PlayerMoveEvent event, NoCheatData data) {
// If we have stored a location for the player, we put him back there
if(data.speedhackSetBackPoint != null) {
// Lets try it that way. Maybe now people don't "disappear" any longer
event.setFrom(data.speedhackSetBackPoint);
event.setTo(data.speedhackSetBackPoint);

View File

@ -14,11 +14,11 @@ import cc.co.evenprime.bukkit.nocheat.checks.AirbuildCheck;
*/
public class NoCheatBlockListener extends BlockListener {
public NoCheatBlockListener() {
}
@Override
public void onBlockPlace(BlockPlaceEvent event) {

View File

@ -7,11 +7,16 @@ import org.bukkit.event.entity.EntityListener;
import cc.co.evenprime.bukkit.nocheat.NoCheatConfiguration;
import cc.co.evenprime.bukkit.nocheat.checks.DupebydeathCheck;
/**
*
* @author Evenprime
*
*/
public class NoCheatEntityListener extends EntityListener {
@Override
public void onEntityDeath(EntityDeathEvent event) {
if(NoCheatConfiguration.dupebydeathCheckActive) {
DupebydeathCheck.playerDeath(event);
}

View File

@ -1,8 +1,5 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerMoveEvent;
@ -21,42 +18,33 @@ import cc.co.evenprime.bukkit.nocheat.checks.SpeedhackCheck;
*/
public class NoCheatPlayerListener extends PlayerListener {
public NoCheatPlayerListener() { }
@Override
public void onPlayerQuit(PlayerEvent event) {
NoCheatPlugin.playerData.remove(event.getPlayer());
}
public void ingoreNextXEvents(Entity player, int count) {
NoCheatData data = NoCheatPlugin.playerData.get(player);
if(data != null) {
data.movingIgnoreNextXEvents = count;
}
}
@Override
public void onPlayerMove(PlayerMoveEvent event) {
public NoCheatPlayerListener() { }
@Override
public void onPlayerQuit(PlayerEvent event) {
NoCheatPlugin.playerData.remove(event.getPlayer());
}
@Override
public void onPlayerMove(PlayerMoveEvent event) {
// Get the player-specific data
NoCheatData data = NoCheatPlugin.getPlayerData(event.getPlayer());
if(!event.isCancelled() && NoCheatConfiguration.speedhackCheckActive)
SpeedhackCheck.check(data, event);
SpeedhackCheck.check(data, event);
if(!event.isCancelled() && NoCheatConfiguration.movingCheckActive)
MovingCheck.check(data, event);
}
@Override
public void onPlayerTeleport(PlayerMoveEvent event) {
}
@Override
public void onPlayerTeleport(PlayerMoveEvent event) {
if(!event.isCancelled() && NoCheatConfiguration.bedteleportCheckActive) {
BedteleportCheck.check(event);
}
}
}
}