new check "timed.godmode" with config etc.

This commit is contained in:
Evenprime 2011-10-25 17:32:10 +02:00
parent 67b5505d04
commit d31525ba3a
12 changed files with 244 additions and 8 deletions

View File

@ -31,6 +31,7 @@ import cc.co.evenprime.bukkit.nocheat.events.EventManager;
import cc.co.evenprime.bukkit.nocheat.events.PlayerChatEventManager;
import cc.co.evenprime.bukkit.nocheat.events.PlayerMoveEventManager;
import cc.co.evenprime.bukkit.nocheat.events.PlayerTeleportEventManager;
import cc.co.evenprime.bukkit.nocheat.events.TimedEventManager;
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
import cc.co.evenprime.bukkit.nocheat.log.LogManager;
@ -101,6 +102,7 @@ public class NoCheat extends JavaPlugin {
eventManagers.add(new BlockBreakEventManager(this));
eventManagers.add(new BlockPlaceEventManager(this));
eventManagers.add(new EntityDamageEventManager(this));
eventManagers.add(new TimedEventManager(this));
// Then set up a task to monitor server lag
if(lagMeasureTask == null) {
@ -188,11 +190,12 @@ public class NoCheat extends JavaPlugin {
}
/**
* Call this periodically to walk over the stored data map and remove old/unused entries
* Call this periodically to walk over the stored data map and remove
* old/unused entries
*
*/
public void cleanDataMap() {
data.cleanDataMap();
}
}

View File

@ -0,0 +1,84 @@
package cc.co.evenprime.bukkit.nocheat.checks.timed;
import net.minecraft.server.EntityPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.data.BaseData;
public class TimedCheck {
private final NoCheat plugin;
public TimedCheck(NoCheat plugin) {
this.plugin = plugin;
}
public void check(Player player, int tickTime, ConfigurationCache cc) {
// server lag(ged), skip this
if(plugin.skipCheck())
return;
boolean cancel = false;
BaseData data = plugin.getData(player.getName());
EntityPlayer p = ((CraftPlayer) player).getHandle();
// Compare ingame record of players ticks to our last observed value
int difference = p.ticksLived - data.timed.ticksLived;
// difference should be >= tickTime for perfect synchronization
if(difference > tickTime) {
// player was faster than expected, give him credit for the
// difference
data.timed.ticksBehind -= (difference - tickTime);
// Reduce violation level over time
data.timed.godmodeVL *= 0.90D;
} else if(difference >= tickTime / 2) {
// close enough, let it pass
// Reduce violation level over time
data.timed.godmodeVL *= 0.95D;
} else {
// That's a bit suspicious, why is the player more than half the
// ticktime behind? Keep that in mind
data.timed.ticksBehind += tickTime - difference;
// Is he way too far behind, then correct that
if(data.timed.ticksBehind > cc.timed.godmodeTicksLimit) {
data.timed.godmodeVL += tickTime - difference;
// Enough is enough
data.log.check = "timed.godmode";
data.log.godmodeTicksBehind = data.timed.ticksBehind;
cancel = plugin.execute(player, cc.timed.godmodeActions, (int) data.timed.godmodeVL, data.timed.history, cc);
// Reduce the time the player is behind accordingly
data.timed.ticksBehind -= tickTime;
}
}
if(data.timed.ticksBehind < 0) {
data.timed.ticksBehind = 0;
}
if(cancel) {
// Catch up for at least some of the ticks
for(int i = 0; i < tickTime; i++) {
p.b(true); // Catch up with the server, one tick at a time
}
}
// setup data for next time
data.timed.ticksLived = p.ticksLived;
}
}

View File

@ -107,6 +107,14 @@ public abstract class Configuration {
public static final OptionNode FIGHT_SELFHIT_CHECK = new OptionNode("check", FIGHT_SELFHIT, DataType.BOOLEAN);
public final static OptionNode FIGHT_SELFHIT_ACTIONS = new OptionNode("actions", FIGHT_SELFHIT, DataType.ACTIONLIST);
private static final OptionNode TIMED = new OptionNode("timed", ROOT, DataType.PARENT);
public static final OptionNode TIMED_CHECK = new OptionNode("check", TIMED, DataType.BOOLEAN);
private static final OptionNode TIMED_GODMODE = new OptionNode("godmode", TIMED, DataType.PARENT);
public static final OptionNode TIMED_GODMODE_CHECK = new OptionNode("check", TIMED_GODMODE, DataType.BOOLEAN);
public static final OptionNode TIMED_GODMODE_TICKSLIMIT = new OptionNode("tickslimit", TIMED_GODMODE, DataType.INTEGER);
public static final OptionNode TIMED_GODMODE_ACTIONS = new OptionNode("actions", TIMED_GODMODE, DataType.ACTIONLIST);
private final Map<OptionNode, Object> values;
private final Configuration defaults;

View File

@ -158,12 +158,25 @@ public class DefaultConfiguration extends Configuration {
directionActionList.setActions(20, action.getActions("fightDirectionLog fightCancel".split(" ")));
directionActionList.setActions(50, action.getActions("fightDirectionLogHigh fightCancel".split(" ")));
setValue(FIGHT_DIRECTION_ACTIONS, directionActionList);
setValue(FIGHT_SELFHIT_CHECK, true);
ActionList selfhitActionList = new ActionList();
selfhitActionList.setActions(0, action.getActions("fightSelfhitLog fightCancel".split(" ")));
setValue(FIGHT_SELFHIT_ACTIONS, selfhitActionList);
}
/*** TIMED ***/
{
setValue(TIMED_CHECK, true);
setValue(TIMED_GODMODE_CHECK, true);
setValue(TIMED_GODMODE_TICKSLIMIT, 50);
ActionList directionActionList = new ActionList();
directionActionList.setActions(0, action.getActions("godmodeCancel".split(" ")));
directionActionList.setActions(100, action.getActions("godmodeLog godmodeCancel".split(" ")));
setValue(TIMED_GODMODE_ACTIONS, directionActionList);
}
}
public static void writeActionFile(File file) {
@ -242,6 +255,7 @@ public class DefaultConfiguration extends Configuration {
w(w, "log onliquidLog 2 5 med [player] failed [check]: tried to place a [blocktype] block at [placelocation] against block at [placeagainst]. VL [violations]");
w(w, "log spamLog 0 5 med [player] failed [check]: Last sent message \"[text]\". VL [violations]");
w(w, "log nofallLog 0 5 med [player] failed [check]: tried to avoid fall damage for ~[falldistance] blocks. VL [violations]");
w(w, "log godmodeLog 0 5 med [player] failed [check]: lagging or using godmode. VL [violations]");
w(w, "");
w(w, "");
w(w, "# Some log messages related to fighting, displaying the same text, but with different level (Info, Warning, Severe)");
@ -265,6 +279,7 @@ public class DefaultConfiguration extends Configuration {
w(w, "special spamCancel 0 0");
w(w, "special nofallDamage 0 0");
w(w, "special fightCancel 0 0");
w(w, "special godmodeCancel 0 0");
w(w, "");
w(w, "# CONSOLECOMMAND Actions: They will execute a command as if it were typed into the console.");
w(w, "# - They start with the word 'consolecommand'");

View File

@ -33,6 +33,9 @@ public class Permissions {
public static final String FIGHT_DIRECTION = FIGHT + ".direction";
public static final String FIGHT_SELFHIT = FIGHT + ".selfhit";
public static final String TIMED = CHECKS + ".timed";
public static final String TIMED_GODMODE = TIMED + ".godmode";
public final static String ADMIN_CHATLOG = ADMIN + ".chatlog";
public static final String ADMIN_PERMLIST = ADMIN + ".permlist";
public static final String ADMIN_RELOAD = ADMIN + ".reload";

View File

@ -0,0 +1,20 @@
package cc.co.evenprime.bukkit.nocheat.config.cache;
import cc.co.evenprime.bukkit.nocheat.config.Configuration;
import cc.co.evenprime.bukkit.nocheat.config.util.ActionList;
public class CCTimed {
public final boolean check;
public final boolean godmodeCheck;
public final double godmodeTicksLimit;
public final ActionList godmodeActions;
public CCTimed(Configuration data) {
check = data.getBoolean(Configuration.TIMED_CHECK);
godmodeCheck = data.getBoolean(Configuration.TIMED_GODMODE_CHECK);
godmodeTicksLimit = data.getInteger(Configuration.TIMED_GODMODE_TICKSLIMIT);
godmodeActions = data.getActionList(Configuration.TIMED_GODMODE_ACTIONS);
}
}

View File

@ -9,7 +9,7 @@ import cc.co.evenprime.bukkit.nocheat.config.Configuration;
* a world, everything unmodifiable for security/performance
*
*/
public class ConfigurationCache {
public class ConfigurationCache {
public final CCMoving moving;
public final CCLogging logging;
@ -18,6 +18,7 @@ public class ConfigurationCache {
public final CCChat chat;
public final CCDebug debug;
public final CCFight fight;
public final CCTimed timed;
/**
* Instantiate a config cache and populate it with the data of a
@ -34,6 +35,7 @@ public class ConfigurationCache {
logging = new CCLogging(data, worldSpecificFileLogger);
debug = new CCDebug(data);
fight = new CCFight(data);
timed = new CCTimed(data);
}
}

View File

@ -8,10 +8,11 @@ public class BaseData extends Data {
public final LogData log;
public final MovingData moving;
public final FightData fight;
public final TimedData timed;
private final Data[] data; // for convenience
public long lastUsedTime;
public long lastUsedTime;
public BaseData() {
this.blockbreak = new BlockBreakData();
@ -20,9 +21,10 @@ public class BaseData extends Data {
this.log = new LogData();
this.moving = new MovingData();
this.fight = new FightData();
this.timed = new TimedData();
data = new Data[] {this.blockbreak, this.blockplace, this.chat,
this.log, this.moving, this.fight};
this.log, this.moving, this.fight, this.timed};
}
public void clearCriticalData() {
@ -30,7 +32,7 @@ public class BaseData extends Data {
d.clearCriticalData();
}
}
public boolean shouldBeRemoved(long currentTimeInMilliseconds) {
return lastUsedTime + 60000L < currentTimeInMilliseconds;
}

View File

@ -18,5 +18,6 @@ public class LogData extends Data {
public double reachdistance;
public float falldistance;
public String playerName;
public int godmodeTicksBehind;
}

View File

@ -0,0 +1,17 @@
package cc.co.evenprime.bukkit.nocheat.data;
public class TimedData extends Data {
public int ticksLived;
public int ticksBehind;
public double godmodeVL;
public final ExecutionHistory history = new ExecutionHistory(); ;
public TimedData() {}
@Override
public void clearCriticalData() {
ticksBehind = 0;
ticksLived = 0;
}
}

View File

@ -6,7 +6,7 @@ import java.util.Map;
public class PerformanceManager {
public enum Type {
BLOCKBREAK, BLOCKDAMAGE, BLOCKPLACE, CHAT, MOVING, VELOCITY, FIGHT
BLOCKBREAK, BLOCKDAMAGE, BLOCKPLACE, CHAT, MOVING, VELOCITY, FIGHT, TIMED
}

View File

@ -0,0 +1,81 @@
package cc.co.evenprime.bukkit.nocheat.events;
import java.util.LinkedList;
import java.util.List;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.checks.timed.TimedCheck;
import cc.co.evenprime.bukkit.nocheat.config.Permissions;
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
import cc.co.evenprime.bukkit.nocheat.debug.Performance;
import cc.co.evenprime.bukkit.nocheat.debug.PerformanceManager.Type;
public class TimedEventManager implements EventManager {
private final NoCheat plugin;
private final TimedCheck check;
private final Performance timedPerformance;
public TimedEventManager(final NoCheat plugin) {
this.plugin = plugin;
check = new TimedCheck(plugin);
this.timedPerformance = plugin.getPerformance(Type.TIMED);
// "register a listener" for passed time
plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
private int executions = 0;
private int loopsize = 10;
public void run() {
executions++;
if(executions >= loopsize) {
executions = 0;
}
for(Player p : plugin.getServer().getOnlinePlayers()) {
if((p.hashCode() & 0x7FFFFFFF) % loopsize == executions) {
onTimedEvent(p, loopsize);
}
}
}
}, 0, 1);
}
public void onTimedEvent(Player player, int elapsedTicks) {
// Performance counter setup
long nanoTimeStart = 0;
final boolean performanceCheck = timedPerformance.isEnabled();
if(performanceCheck)
nanoTimeStart = System.nanoTime();
ConfigurationCache cc = plugin.getConfig(player);
if(cc.timed.check && !player.hasPermission(Permissions.TIMED)) {
check.check(player, elapsedTicks, cc);
}
// store performance time
if(performanceCheck)
timedPerformance.addTime(System.nanoTime() - nanoTimeStart);
}
public List<String> getActiveChecks(ConfigurationCache cc) {
LinkedList<String> s = new LinkedList<String>();
if(cc.timed.check && cc.timed.godmodeCheck)
s.add("timed.godmode");
return s;
}
}