Prevent the creation of new tasks while disabling the plugin

This commit is contained in:
Evenprime 2011-07-17 07:45:38 +02:00
parent c5ec73b1f4
commit ee1ae892eb
17 changed files with 225 additions and 195 deletions

View File

@ -3,7 +3,7 @@ name: NoCheat
author: Evenprime
main: cc.co.evenprime.bukkit.nocheat.NoCheat
version: 1.09e
version: 1.09f
softdepend: [ Permissions, CraftIRC ]

View File

@ -0,0 +1,163 @@
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.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())
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
*/
public NoCheatData getPlayerData(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();
data.moving.teleportedTo = p.getLocation();
}
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;
}
/**
* 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()) {
Map.Entry<Player, NoCheatData> pairs = (Map.Entry<Player, NoCheatData>)it.next();
AirbuildData d = pairs.getValue().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 = pairs.getValue().moving;
if(d2 != null) {
int id = d2.summaryTask;
if(id != -1) {
Bukkit.getServer().getScheduler().cancelTask(id);
}
else {
// To prevent accidentially creating a new one while cleaning up
d2.summaryTask = 1;
}
}
}
}
}
}

View File

@ -70,9 +70,11 @@ public class NoCheat extends JavaPlugin implements CommandSender {
private Level ircLevel;
private Level consoleLevel;
private String ircTag;
private NukeCheck instantmineCheck;
private NukeCheck nukeCheck;
private DataManager dataManager;
public NoCheat() {
}
@ -125,7 +127,7 @@ public class NoCheat extends JavaPlugin implements CommandSender {
teardownCleanupTask();
teardownServerLagMeasureTask();
NoCheatData.cancelPlayerDataTasks();
dataManager.cancelPlayerDataTasks();
}
catch(Exception e) { /* Can't do much in case of error here... */ }
Logger.getLogger("Minecraft").info( "[NoCheat] version [" + pdfFile.getVersion() + "] is disabled.");
@ -133,6 +135,7 @@ public class NoCheat extends JavaPlugin implements CommandSender {
public void onEnable() {
dataManager = new DataManager();
// parse the nocheat.yml config file
setupConfig();
@ -140,10 +143,10 @@ public class NoCheat extends JavaPlugin implements CommandSender {
speedhackCheck = new SpeedhackCheck(this, config);
airbuildCheck = new AirbuildCheck(this, config);
bogusitemsCheck = new BogusitemsCheck(this, config);
instantmineCheck = new NukeCheck(this, config);
nukeCheck = new NukeCheck(this, config);
// just for convenience
checks = new Check[] { movingCheck, speedhackCheck, airbuildCheck, bogusitemsCheck, instantmineCheck };
checks = new Check[] { movingCheck, speedhackCheck, airbuildCheck, bogusitemsCheck, nukeCheck };
if(!allowFlightSet && 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\"");
@ -162,6 +165,10 @@ public class NoCheat extends JavaPlugin implements CommandSender {
setupServerLagMeasureTask();
}
public DataManager getDataManager() {
return dataManager;
}
private void setupCleanupTask() {
if(cleanUpTaskId != -1) return;
@ -171,7 +178,7 @@ public class NoCheat extends JavaPlugin implements CommandSender {
@Override
public void run() {
NoCheatData.cleanPlayerDataCollection();
dataManager.cleanPlayerDataCollection();
}
}, 5000, 5000);
}
@ -296,7 +303,7 @@ public class NoCheat extends JavaPlugin implements CommandSender {
}
}
else {
PermissionData data = PermissionData.get(player);
PermissionData data = dataManager.getPermissionData(player);
long time = System.currentTimeMillis();
if(data.lastUpdate[permission] + 10000 < time) {
data.lastUpdate[permission] = time;

View File

@ -1,101 +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.NukeData;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
import cc.co.evenprime.bukkit.nocheat.data.PermissionData;
import cc.co.evenprime.bukkit.nocheat.data.SpeedhackData;
/**
* 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;
// Store data between Events
private static final Map<Player, NoCheatData> playerData = new HashMap<Player, NoCheatData>();
/**
* 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 = playerData.get(p);
if(data == null) {
// If we have no data for the player, create some
data = new NoCheatData();
playerData.put(p, data);
}
return data;
}
/**
* 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 static 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())
it.remove();
}
}
}
/**
* 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 static void cancelPlayerDataTasks() {
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();
int id;
id = pairs.getValue().airbuild != null ? pairs.getValue().airbuild.summaryTask : -1;
if(id != -1) {
Bukkit.getServer().getScheduler().cancelTask(id);
}
id = pairs.getValue().moving != null ? pairs.getValue().moving.summaryTask : -1;
if(id != -1)
Bukkit.getServer().getScheduler().cancelTask(id);
}
}
}
}

View File

@ -45,7 +45,7 @@ public class AirbuildCheck extends Check {
// Are all 6 sides "air-blocks" -> cancel the event
if( event.getBlockAgainst().getType() == Material.AIR && event.getBlockPlaced().getType() != Material.AIR ) {
final AirbuildData data = AirbuildData.get(event.getPlayer());
final AirbuildData data = plugin.getDataManager().getAirbuildData(event.getPlayer());
final Player p = event.getPlayer();
if(data.summaryTask == -1) {

View File

@ -245,7 +245,7 @@ public class MovingCheck extends Check {
*/
public void teleported(PlayerTeleportEvent event) {
MovingData data = MovingData.get(event.getPlayer());
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...
@ -531,17 +531,15 @@ public class MovingCheck extends Check {
protected void registerListeners() {
PluginManager pm = Bukkit.getServer().getPluginManager();
Listener movingPlayerMonitor = new MovingPlayerMonitor(this);
Listener movingPlayerMonitor = new MovingPlayerMonitor(plugin.getDataManager(), this);
// Register listeners for moving check
pm.registerEvent(Event.Type.PLAYER_MOVE, new MovingPlayerListener(this), Priority.Lowest, plugin);
pm.registerEvent(Event.Type.PLAYER_MOVE, new MovingPlayerListener(plugin.getDataManager(), this), Priority.Lowest, plugin);
pm.registerEvent(Event.Type.PLAYER_INTERACT, movingPlayerMonitor, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_MOVE, movingPlayerMonitor, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.ENTITY_DAMAGE, new MovingEntityListener(this), Priority.Monitor, plugin);
pm.registerEvent(Event.Type.ENTITY_DAMAGE, new MovingEntityListener(plugin.getDataManager(), this), 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);
}
}

View File

@ -59,7 +59,7 @@ public class NukeCheck extends Check {
return;
}
NukeData data = NukeData.get(event.getPlayer());
NukeData data = plugin.getDataManager().getNukeData(event.getPlayer());
Block block = event.getBlock();

View File

@ -61,7 +61,7 @@ public class SpeedhackCheck extends Check {
}
// Get the player-specific data
SpeedhackData data = SpeedhackData.get(player);
SpeedhackData data = plugin.getDataManager().getSpeedhackData(player);
// Count the event (twice, to interpolate from 0.5 seconds to 1 second
data.eventsSinceLastCheck += 2;
@ -195,7 +195,7 @@ public class SpeedhackCheck extends Check {
}
public void teleported(PlayerTeleportEvent event) {
SpeedhackData data = SpeedhackData.get(event.getPlayer());
SpeedhackData data = plugin.getDataManager().getSpeedhackData(event.getPlayer());
resetData(data, event.getTo());
}
}

View File

@ -1,21 +1,9 @@
package cc.co.evenprime.bukkit.nocheat.data;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheatData;
public class AirbuildData {
public int perFiveSeconds = 0;
public int summaryTask = -1;
public static AirbuildData get(Player p) {
NoCheatData data = NoCheatData.getPlayerData(p);
if(data.airbuild == null) {
data.airbuild = new AirbuildData();
}
return data.airbuild;
}
}

View File

@ -6,9 +6,7 @@ import net.minecraft.server.Block;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheatData;
public class MovingData {
public int jumpPhase = 0;
@ -67,16 +65,4 @@ public class MovingData {
types[Material.LADDER.getId()]= LADDER | SOLID;
types[Material.FENCE.getId()]= FENCE | SOLID;
}
public static MovingData get(final Player p) {
final NoCheatData data = NoCheatData.getPlayerData(p);
if(data.moving == null) {
data.moving = new MovingData();
data.moving.teleportedTo = p.getLocation();
}
return data.moving;
}
}

View File

@ -0,0 +1,23 @@
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 NoCheatData() { }
}

View File

@ -1,21 +1,8 @@
package cc.co.evenprime.bukkit.nocheat.data;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheatData;
public class NukeData {
public int counter = 0;
public static NukeData get(Player p) {
NoCheatData data = NoCheatData.getPlayerData(p);
if(data.nuke == null) {
data.nuke = new NukeData();
}
return data.nuke;
}
}

View File

@ -1,9 +1,5 @@
package cc.co.evenprime.bukkit.nocheat.data;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheatData;
public class PermissionData {
public final long lastUpdate[] = new long[11];
@ -36,16 +32,4 @@ public class PermissionData {
permissionNames[PERMISSION_FASTSWIM] = "nocheat.fastswim";
permissionNames[PERMISSION_NUKE] = "nocheat.nuke";
}
public static PermissionData get(Player p) {
NoCheatData data = NoCheatData.getPlayerData(p);
if(data.permission == null) {
data.permission = new PermissionData();
}
return data.permission;
}
}

View File

@ -1,9 +1,6 @@
package cc.co.evenprime.bukkit.nocheat.data;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheatData;
public class SpeedhackData {
@ -13,14 +10,4 @@ public class SpeedhackData {
public final int violationsInARow[] = { 0, 0, 0 };
public int violationsInARowTotal = 0;
public static SpeedhackData get(Player p) {
NoCheatData data = NoCheatData.getPlayerData(p);
if(data.speedhack == null) {
data.speedhack = new SpeedhackData();
}
return data.speedhack;
}
}

View File

@ -4,21 +4,23 @@ import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityListener;
import cc.co.evenprime.bukkit.nocheat.DataManager;
import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
public class MovingEntityListener extends EntityListener {
private final MovingCheck check;
private final DataManager dataManager;
public MovingEntityListener(MovingCheck check) {
public MovingEntityListener(DataManager dataManager, MovingCheck check) {
this.dataManager = dataManager;
this.check = check;
}
@Override
public void onEntityDamage(EntityDamageEvent event) {
if(event.getEntity() instanceof Player) {
check.updateVelocity(event.getEntity().getVelocity(), MovingData.get((Player)event.getEntity()));
check.updateVelocity(event.getEntity().getVelocity(), dataManager.getMovingData((Player)event.getEntity()));
}
}
}

View File

@ -6,6 +6,7 @@ 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;
@ -18,8 +19,10 @@ import cc.co.evenprime.bukkit.nocheat.data.MovingData;
public class MovingPlayerListener extends PlayerListener {
private final MovingCheck check;
private final DataManager dataManager;
public MovingPlayerListener(MovingCheck check) {
public MovingPlayerListener(DataManager dataManager, MovingCheck check) {
this.dataManager = dataManager;
this.check = check;
}
@ -33,7 +36,7 @@ public class MovingPlayerListener extends PlayerListener {
// Is there something to do at all?
if(!check.skipCheck(player)) {
final MovingData data = MovingData.get(player);
final MovingData data = dataManager.getMovingData(player);
final Location from = event.getFrom();
final Location to = event.getTo();

View File

@ -7,6 +7,7 @@ import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import cc.co.evenprime.bukkit.nocheat.DataManager;
import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
@ -18,14 +19,16 @@ import cc.co.evenprime.bukkit.nocheat.data.MovingData;
public class MovingPlayerMonitor extends PlayerListener {
private final MovingCheck check;
private final DataManager dataManager;
public MovingPlayerMonitor(MovingCheck check) {
public MovingPlayerMonitor(DataManager dataManager, MovingCheck check) {
this.dataManager = dataManager;
this.check = check;
}
@Override
public void onPlayerRespawn(PlayerRespawnEvent event) {
MovingData data = MovingData.get(event.getPlayer());
MovingData data = dataManager.getMovingData(event.getPlayer());
data.wasTeleported = true;
data.setBackPoint = null;
data.jumpPhase = 0;
@ -44,12 +47,12 @@ public class MovingPlayerMonitor extends PlayerListener {
@Override
public void onPlayerInteract(PlayerInteractEvent event) {
check.updateVelocity(event.getPlayer().getVelocity(), MovingData.get(event.getPlayer()));
check.updateVelocity(event.getPlayer().getVelocity(), dataManager.getMovingData(event.getPlayer()));
}
@Override
public void onPlayerMove(PlayerMoveEvent event) {
MovingData data = MovingData.get(event.getPlayer());
MovingData data = dataManager.getMovingData(event.getPlayer());
check.updateVelocity(event.getPlayer().getVelocity(), data);