diff options
Diffstat (limited to 'EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data')
6 files changed, 472 insertions, 0 deletions
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/DataStore.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/DataStore.java new file mode 100644 index 000000000..1f5b6ea71 --- /dev/null +++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/DataStore.java @@ -0,0 +1,38 @@ +package com.earth2me.essentials.anticheat.data; + +import com.earth2me.essentials.anticheat.DataItem; +import java.util.HashMap; +import java.util.Map; + + +public class DataStore +{ + private final Map<String, DataItem> dataMap = new HashMap<String, DataItem>(); + private final Statistics statistics = new Statistics(); + private final long timestamp = System.currentTimeMillis(); + + @SuppressWarnings("unchecked") + public <T extends DataItem> T get(String id) + { + return (T)dataMap.get(id); + } + + public void set(String id, DataItem data) + { + dataMap.put(id, data); + } + + public Map<String, Object> collectData() + { + Map<String, Object> map = statistics.get(); + map.put("nocheat.starttime", timestamp); + map.put("nocheat.endtime", System.currentTimeMillis()); + + return map; + } + + public Statistics getStatistics() + { + return statistics; + } +} diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/ExecutionHistory.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/ExecutionHistory.java new file mode 100644 index 000000000..da57c3c50 --- /dev/null +++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/ExecutionHistory.java @@ -0,0 +1,145 @@ +package com.earth2me.essentials.anticheat.data; + +import com.earth2me.essentials.anticheat.actions.Action; +import java.util.HashMap; +import java.util.Map; + + +/** + * Store amount of action executions for last 60 seconds for various actions + * + */ +public class ExecutionHistory +{ + private static class ExecutionHistoryEntry + { + private final int executionTimes[]; + private long lastExecution = 0; + private int totalEntries = 0; + private long lastClearedTime = 0; + + private ExecutionHistoryEntry(int monitoredTimeFrame) + { + this.executionTimes = new int[monitoredTimeFrame]; + } + + /** + * Remember an execution at the specific time + */ + private void addCounter(long time) + { + // clear out now outdated values from the array + if (time - lastClearedTime > 0) + { + // Clear the next few fields of the array + clearTimes(lastClearedTime + 1, time - lastClearedTime); + lastClearedTime = time + 1; + } + + executionTimes[(int)(time % executionTimes.length)]++; + totalEntries++; + } + + /** + * Clean parts of the array + * + * @param start + * @param length + */ + private void clearTimes(long start, long length) + { + + if (length <= 0) + { + return; // nothing to do (yet) + } + if (length > executionTimes.length) + { + length = executionTimes.length; + } + + int j = (int)start % executionTimes.length; + + for (int i = 0; i < length; i++) + { + if (j == executionTimes.length) + { + j = 0; + } + + totalEntries -= executionTimes[j]; + executionTimes[j] = 0; + + j++; + } + } + + public int getCounter() + { + return totalEntries; + } + + public long getLastExecution() + { + return lastExecution; + } + + public void setLastExecution(long time) + { + this.lastExecution = time; + } + } + // Store data between Events + // time + action + action-counter + private final Map<String, Map<Action, ExecutionHistoryEntry>> executionHistories; + + public ExecutionHistory() + { + executionHistories = new HashMap<String, Map<Action, ExecutionHistoryEntry>>(); + } + + /** + * 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 and remember the result + * + * @param check + * @param action + * @param time a time IN SECONDS + * @return + */ + public boolean executeAction(String check, Action action, long time) + { + + Map<Action, ExecutionHistoryEntry> executionHistory = executionHistories.get(check); + + if (executionHistory == null) + { + executionHistory = new HashMap<Action, ExecutionHistoryEntry>(); + executionHistories.put(check, executionHistory); + } + + ExecutionHistoryEntry entry = executionHistory.get(action); + + if (entry == null) + { + entry = new ExecutionHistoryEntry(60); + executionHistory.put(action, entry); + } + + // update entry + entry.addCounter(time); + + if (entry.getCounter() > action.delay) + { + // Execute action? + if (entry.getLastExecution() <= time - action.repeat) + { + // Execute action! + entry.setLastExecution(time); + return true; + } + } + + return false; + } +} diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/PlayerManager.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/PlayerManager.java new file mode 100644 index 000000000..7a13628c6 --- /dev/null +++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/PlayerManager.java @@ -0,0 +1,80 @@ +package com.earth2me.essentials.anticheat.data; + +import com.earth2me.essentials.anticheat.NoCheat; +import com.earth2me.essentials.anticheat.NoCheatPlayer; +import com.earth2me.essentials.anticheat.player.NoCheatPlayerImpl; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.bukkit.entity.Player; + + +/** + * Provide secure access to player-specific data objects for various checks or check groups. + */ +public class PlayerManager +{ + // Store data between Events + private final Map<String, NoCheatPlayerImpl> players; + private final NoCheat plugin; + + public PlayerManager(NoCheat plugin) + { + this.players = new HashMap<String, NoCheatPlayerImpl>(); + this.plugin = plugin; + } + + /** + * Get a data object of the specified class. If none is stored yet, create one. + */ + public NoCheatPlayer getPlayer(Player player) + { + + NoCheatPlayerImpl p = this.players.get(player.getName().toLowerCase()); + + if (p == null) + { + p = new NoCheatPlayerImpl(player, plugin); + this.players.put(player.getName().toLowerCase(), p); + } + + p.setLastUsedTime(System.currentTimeMillis()); + p.refresh(player); + + return p; + } + + public void cleanDataMap() + { + long time = System.currentTimeMillis(); + List<String> removals = new ArrayList<String>(5); + + for (Entry<String, NoCheatPlayerImpl> e : this.players.entrySet()) + { + if (e.getValue().shouldBeRemoved(time)) + { + removals.add(e.getKey()); + } + } + + for (String key : removals) + { + this.players.remove(key); + } + } + + public Map<String, Object> getPlayerData(String playerName) + { + + NoCheatPlayer player = this.players.get(playerName.toLowerCase()); + + if (player != null) + { + return player.getDataStore().collectData(); + } + + return new HashMap<String, Object>(); + } +} diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/PreciseLocation.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/PreciseLocation.java new file mode 100644 index 000000000..5cf828c96 --- /dev/null +++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/PreciseLocation.java @@ -0,0 +1,51 @@ +package com.earth2me.essentials.anticheat.data; + +import org.bukkit.Location; + + +/** + * A class to store x,y,z triple data, instead of using bukkits Location objects, which can't be easily recycled + * + */ +public final class PreciseLocation +{ + public double x; + public double y; + public double z; + + public PreciseLocation() + { + reset(); + } + + public final void set(Location location) + { + x = location.getX(); + y = location.getY(); + z = location.getZ(); + } + + public final void set(PreciseLocation location) + { + x = location.x; + y = location.y; + z = location.z; + } + + public final boolean isSet() + { + return x != Double.MAX_VALUE; + } + + public final void reset() + { + x = Double.MAX_VALUE; + y = Double.MAX_VALUE; + z = Double.MAX_VALUE; + } + + public final boolean equals(Location location) + { + return location.getX() == x && location.getY() == y && location.getZ() == z; + } +} diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/SimpleLocation.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/SimpleLocation.java new file mode 100644 index 000000000..34923051e --- /dev/null +++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/SimpleLocation.java @@ -0,0 +1,76 @@ +package com.earth2me.essentials.anticheat.data; + +import org.bukkit.Location; +import org.bukkit.block.Block; + + +/** + * To avoid constantly creating and referencing "Location" objects, which in turn reference a whole lot of other + * unnecessary stuff, rather use our own "Location" object which is easily reusable. + * + */ +public final class SimpleLocation +{ + public int x; + public int y; + public int z; + + public SimpleLocation() + { + reset(); + } + + @Override + public final boolean equals(Object object) + { + if (!(object instanceof SimpleLocation)) + { + return false; + } + + SimpleLocation simpleLocation = (SimpleLocation)object; + + if (!isSet() && !simpleLocation.isSet()) + { + return true; + } + else if (!isSet() || !simpleLocation.isSet()) + { + return false; + } + + return simpleLocation.x == x && simpleLocation.y == y && simpleLocation.z == z; + } + + @Override + public final int hashCode() + { + return x * 1000000 + y * 1000 + z; + } + + public final void set(Block block) + { + x = block.getX(); + y = block.getY(); + z = block.getZ(); + } + + public final void setLocation(Location location) + { + x = location.getBlockX(); + y = location.getBlockY(); + z = location.getBlockZ(); + } + + public final boolean isSet() + { + return x != Integer.MAX_VALUE; + } + + public final void reset() + { + x = Integer.MAX_VALUE; + y = Integer.MAX_VALUE; + z = Integer.MAX_VALUE; + } +} diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/Statistics.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/Statistics.java new file mode 100644 index 000000000..9c83e97d5 --- /dev/null +++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/Statistics.java @@ -0,0 +1,82 @@ +package com.earth2me.essentials.anticheat.data; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + + +public class Statistics +{ + public enum Id + { + BB_DIRECTION("blockbreak.direction"), BB_NOSWING("blockbreak.noswing"), + BB_REACH("blockbreak.reach"), BP_DIRECTION("blockplace.direction"), + BP_REACH("blockplace.reach"), CHAT_COLOR("chat.color"), + CHAT_SPAM("chat.spam"), FI_DIRECTION("fight.direction"), + FI_NOSWING("fight.noswing"), FI_REACH("fight.reach"), + FI_SPEED("fight.speed"), INV_DROP("inventory.drop"), + INV_BOW("inventory.instantbow"), INV_EAT("inventory.instanteat"), + MOV_RUNNING("moving.running"), MOV_FLYING("moving.flying"), + MOV_MOREPACKETS("moving.morepackets"), MOV_NOFALL("moving.nofall"), + MOV_SNEAKING("moving.sneaking"), MOV_SWIMMING("moving.swimming"), + FI_GODMODE("fight.godmode"), FI_INSTANTHEAL("fight.instantheal"); + private final String name; + + private Id(String name) + { + this.name = name; + } + + public String toString() + { + return this.name; + } + } + private final Map<Id, Double> statisticVLs = new HashMap<Id, Double>(Id.values().length); + private final Map<Id, Integer> statisticFails = new HashMap<Id, Integer>(Id.values().length); + + public Statistics() + { + // Initialize statistic values + for (Id id : Id.values()) + { + statisticVLs.put(id, 0D); + statisticFails.put(id, 0); + } + } + + public void increment(Id id, double vl) + { + Double stored = statisticVLs.get(id); + if (stored == null) + { + stored = 0D; + } + statisticVLs.put(id, stored + vl); + + Integer failed = statisticFails.get(id); + if (failed == null) + { + failed = 0; + } + statisticFails.put(id, failed + 1); + } + + public Map<String, Object> get() + { + Map<String, Object> map = new TreeMap<String, Object>(); + + for (Entry<Id, Double> entry : statisticVLs.entrySet()) + { + map.put(entry.getKey().toString() + ".vl", entry.getValue().intValue()); + } + + for (Entry<Id, Integer> entry : statisticFails.entrySet()) + { + map.put(entry.getKey().toString() + ".failed", entry.getValue()); + } + + return map; + } +} |