summaryrefslogtreecommitdiffstats
path: root/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data
diff options
context:
space:
mode:
Diffstat (limited to 'EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data')
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/DataStore.java38
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/ExecutionHistory.java145
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/PlayerManager.java80
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/PreciseLocation.java51
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/SimpleLocation.java76
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/data/Statistics.java82
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;
+ }
+}