"InstantHeal" check to identify artificially accelerated life

regeneration.
This commit is contained in:
Evenprime 2012-03-04 17:33:50 +01:00
parent 10d76d1a22
commit abf9d97e3c
11 changed files with 171 additions and 5 deletions

View File

@ -248,6 +248,10 @@
Don't prevent the player from keeping the temporary invulnerability that he
gets when taking damage
- nocheat.checks.fight.instantheal
Don't prevent the player from accellerating their health generation by
food saturation
--------------------------------------------------------------------------------
----------------------- Permissions for ADMINISTRATION -------------------------
@ -881,6 +885,23 @@
amount of ticks (but at most 15 per failed check), and everytime the
player didn't avoid taking damage it gets reduced slowly.
6) INSTANTHEAL:
Players may trick Bukkit into regenerating their health faster when they
are satiated (full food bar) than normally possible. This will try to
identify and correct that behaviour.
active:
Should players be checked for this behavior.
actions:
What should happen if the player fails this check. Default is to not
allow the health regeneration ("cancel" the regeneration) and log a
message. The Violation LEvel (VL) for this check is the number of
seconds that the player tried to skip while regenerating health. It
gets reduced whenever the player regenerates health while obeying the
normal regeneration times.
--------------------------------------------------------------------------------
------------------------------- STRINGS Section --------------------------------

View File

@ -84,6 +84,8 @@ permissions:
description: Allow a player to attack faster than usual
nocheat.checks.fight.godmode:
description: Allow a player to not take damage by exploiting a design flaw in Minecraft
nocheat.checks.fight.instantheal:
description: Allow a player to artificially speed up his health regeneration
nocheat.checks.inventory:
description: Allow the player to bypass all inventory checks
children:

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>cc.co.evenprime.bukkit</groupId>
<artifactId>NoCheat</artifactId>
<version>3.4.5</version>
<version>3.5.0</version>
<packaging>jar</packaging>
<name>NoCheat</name>
<properties>

View File

@ -14,6 +14,8 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.player.PlayerAnimationEvent;
import cc.co.evenprime.bukkit.nocheat.EventManager;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
@ -30,6 +32,7 @@ public class FightCheckListener implements Listener, EventManager {
private final List<FightCheck> checks;
private final GodmodeCheck godmodeCheck;
private final InstanthealCheck instanthealCheck;
private final NoCheat plugin;
public FightCheckListener(NoCheat plugin) {
@ -43,6 +46,7 @@ public class FightCheckListener implements Listener, EventManager {
this.checks.add(new ReachCheck(plugin));
this.godmodeCheck = new GodmodeCheck(plugin);
this.instanthealCheck = new InstanthealCheck(plugin);
this.plugin = plugin;
}
@ -106,6 +110,37 @@ public class FightCheckListener implements Listener, EventManager {
}
}
/**
* We listen to EntityRegainHealth events of type "Satiated"
* for instantheal check
*
* @param event The EntityRegainHealth Event
*/
@EventHandler(priority = EventPriority.LOWEST)
public void satiatedRegen(final EntityRegainHealthEvent event) {
if(!(event.getEntity() instanceof Player) || event.isCancelled() || event.getRegainReason() != RegainReason.SATIATED) {
return;
}
boolean cancelled = false;
NoCheatPlayer player = plugin.getPlayer((Player) event.getEntity());
FightConfig config = FightCheck.getConfig(player);
if(!instanthealCheck.isEnabled(config) || player.hasPermission(instanthealCheck.permission)) {
return;
}
FightData data = FightCheck.getData(player);
cancelled = instanthealCheck.check(player, data, config);
if(cancelled) {
event.setCancelled(true);
}
}
/**
* A player attacked something with DamageCause ENTITY_ATTACK. That's most
* likely what we want to really check.
@ -209,6 +244,8 @@ public class FightCheckListener implements Listener, EventManager {
s.add("fight.speed");
if(f.godmodeCheck)
s.add("fight.godmode");
if(f.instanthealCheck)
s.add("fight.instantHeal");
return s;
}
}

View File

@ -34,6 +34,9 @@ public class FightConfig implements ConfigItem {
public final boolean godmodeCheck;
public final ActionList godmodeActions;
public final boolean instanthealCheck;
public final ActionList instanthealActions;
public FightConfig(NoCheatConfiguration data) {
directionCheck = data.getBoolean(ConfPaths.FIGHT_DIRECTION_CHECK);
@ -52,5 +55,8 @@ public class FightConfig implements ConfigItem {
godmodeCheck = data.getBoolean(ConfPaths.FIGHT_GODMODE_CHECK);
godmodeActions = data.getActionList(ConfPaths.FIGHT_GODMODE_ACTIONS, Permissions.FIGHT_GODMODE);
instanthealCheck = data.getBoolean(ConfPaths.FIGHT_INSTANTHEAL_CHECK);
instanthealActions = data.getActionList(ConfPaths.FIGHT_INSTANTHEAL_ACTIONS, Permissions.FIGHT_INSTANTHEAL);
}
}

View File

@ -15,6 +15,7 @@ public class FightData implements DataItem {
public double reachVL;
public int speedVL;
public double godmodeVL;
public double instanthealVL;
// For checks that have penalty time
public long directionLastViolationTime;
@ -23,16 +24,22 @@ public class FightData implements DataItem {
// godmode check needs to know these
public long godmodeLastDamageTime;
public int godmodeLastAge;
public int godmodeBuffer = 40;
public int godmodeBuffer = 40;
// last time player regenerated health by satiation
public long instanthealLastRegenTime;
// three seconds buffer to smooth out lag
public long instanthealBuffer = 3000;
// While handling an event, use this to keep the attacked entity
public Entity damagee;
// The player swung his arm
public boolean armswung = true;
public boolean armswung = true;
// For some reason the next event should be ignored
public boolean skipNext = false;
public boolean skipNext = false;
// Keep track of time and amount of attacks
public long speedTime;

View File

@ -0,0 +1,80 @@
package cc.co.evenprime.bukkit.nocheat.checks.fight;
import java.util.Locale;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.NoCheatPlayer;
import cc.co.evenprime.bukkit.nocheat.actions.ParameterName;
import cc.co.evenprime.bukkit.nocheat.config.Permissions;
import cc.co.evenprime.bukkit.nocheat.data.Statistics;
/**
* The instantheal Check should find out if a player tried to artificially
* accellerate the health regeneration by food
*
*/
public class InstanthealCheck extends FightCheck {
public InstanthealCheck(NoCheat plugin) {
super(plugin, "fight.instantheal", Permissions.FIGHT_INSTANTHEAL);
}
@Override
public boolean check(NoCheatPlayer player, FightData data, FightConfig cc) {
boolean cancelled = false;
long time = System.currentTimeMillis();
// security check if system time ran backwards
if(data.instanthealLastRegenTime > time) {
data.instanthealLastRegenTime = 0;
return false;
}
long difference = time - (data.instanthealLastRegenTime + 3500L);
data.instanthealBuffer += difference;
if(data.instanthealBuffer < 0) {
// Buffer has been fully consumed
// Increase vl and statistics
double vl = data.instanthealVL -= data.instanthealBuffer / 1000;
incrementStatistics(player, Statistics.Id.FI_INSTANTHEAL, vl);
data.instanthealBuffer = 0;
// Execute whatever actions are associated with this check and the
// violation level and find out if we should cancel the event
cancelled = executeActions(player, cc.instanthealActions, data.instanthealVL);
} else {
// vl gets decreased
data.instanthealVL *= 0.9;
}
// max 2 seconds buffer
if(data.instanthealBuffer > 2000L) {
data.instanthealBuffer = 2000L;
}
if(!cancelled) {
// New reference time
data.instanthealLastRegenTime = time;
}
return cancelled;
}
@Override
public boolean isEnabled(FightConfig cc) {
return cc.instanthealCheck;
}
@Override
public String getParameter(ParameterName wildcard, NoCheatPlayer player) {
if(wildcard == ParameterName.VIOLATIONS)
return String.format(Locale.US, "%d", (int) getData(player).instanthealVL);
else
return super.getParameter(wildcard, player);
}
}

View File

@ -135,6 +135,10 @@ public abstract class ConfPaths {
public static final String FIGHT_GODMODE_CHECK = FIGHT_GODMODE + "active";
public final static String FIGHT_GODMODE_ACTIONS = FIGHT_GODMODE + "actions";
private final static String FIGHT_INSTANTHEAL = FIGHT + "instantheal.";
public static final String FIGHT_INSTANTHEAL_CHECK = FIGHT_INSTANTHEAL + "active";
public final static String FIGHT_INSTANTHEAL_ACTIONS = FIGHT_INSTANTHEAL + "actions";
public final static String STRINGS = "strings";
}

View File

@ -15,6 +15,7 @@ public class DefaultConfiguration extends NoCheatConfiguration {
this.options().header("Main configuration file for NoCheat. Read \"Instructions.txt\"");
/** LOGGING **/
set(ConfPaths.LOGGING_ACTIVE, true);
set(ConfPaths.LOGGING_SHOWACTIVECHECKS, false);
set(ConfPaths.LOGGING_DEBUGMESSAGES, false);
@ -25,6 +26,7 @@ public class DefaultConfiguration extends NoCheatConfiguration {
set(ConfPaths.LOGGING_LOGTOINGAMECHAT, true);
/*** INVENTORY ***/
set(ConfPaths.INVENTORY_DROP_CHECK, true);
set(ConfPaths.INVENTORY_DROP_TIMEFRAME, 20);
set(ConfPaths.INVENTORY_DROP_LIMIT, 100);
@ -37,6 +39,7 @@ public class DefaultConfiguration extends NoCheatConfiguration {
set(ConfPaths.INVENTORY_INSTANTEAT_ACTIONS, "log:ieat:2:5:if cancel");
/*** MOVING ***/
set(ConfPaths.MOVING_RUNFLY_CHECK, true);
set(ConfPaths.MOVING_RUNFLY_ALLOWFASTSNEAKING, false);
set(ConfPaths.MOVING_RUNFLY_ACTIONS, "log:moveshort:3:5:f cancel vl>100 log:moveshort:0:5:if cancel vl>400 log:movelong:0:5:cif cancel");
@ -79,6 +82,7 @@ public class DefaultConfiguration extends NoCheatConfiguration {
set(ConfPaths.BLOCKPLACE_DIRECTION_ACTIONS, "cancel vl>10 log:bpdirection:0:3:if cancel");
/*** CHAT ***/
set(ConfPaths.CHAT_COLOR_CHECK, true);
set(ConfPaths.CHAT_COLOR_ACTIONS, "log:color:0:1:if cancel");
@ -111,6 +115,9 @@ public class DefaultConfiguration extends NoCheatConfiguration {
set(ConfPaths.FIGHT_GODMODE_CHECK, true);
set(ConfPaths.FIGHT_GODMODE_ACTIONS, "log:fgod:2:5:if cancel");
set(ConfPaths.FIGHT_INSTANTHEAL_CHECK, true);
set(ConfPaths.FIGHT_INSTANTHEAL_ACTIONS, "log:fheal:1:1:if cancel");
set(ConfPaths.STRINGS + ".drop", "[player] failed [check]: Tried to drop more items than allowed. VL [violations]");
set(ConfPaths.STRINGS + ".moveshort", "[player] failed [check]. VL [violations]");
set(ConfPaths.STRINGS + ".movelong", "[player] in [world] at [location] moving to [locationto] over distance [movedistance] failed check [check]. Total violation level so far [violations]");
@ -128,6 +135,7 @@ public class DefaultConfiguration extends NoCheatConfiguration {
set(ConfPaths.STRINGS + ".fspeed", "[player] failed [check]: tried to attack more than [limit] times per second. VL [violations]");
set(ConfPaths.STRINGS + ".fnoswing", "[player] failed [check]: Didn't swing arm. VL [violations]");
set(ConfPaths.STRINGS + ".fgod", "[player] failed [check]: Avoided taking damage or lagging. VL [violations]");
set(ConfPaths.STRINGS + ".fheal", "[player] failed [check]: Tried to regenerate health faster than normal. VL [violations]");
set(ConfPaths.STRINGS + ".ibow", "[player] failed [check]: Fires bow to fast. VL [violations]");
set(ConfPaths.STRINGS + ".ieat", "[player] failed [check]: Eats food [food] too fast. VL [violations]");
set(ConfPaths.STRINGS + ".kick", "kick [player]");

View File

@ -37,6 +37,7 @@ public class Permissions {
public static final String FIGHT_REACH = FIGHT + ".reach";
public static final String FIGHT_SPEED = FIGHT + ".speed";
public static final String FIGHT_GODMODE = FIGHT + ".godmode";
public static final String FIGHT_INSTANTHEAL = FIGHT + ".instantheal";
public final static String ADMIN_CHATLOG = ADMIN + ".chatlog";
public static final String ADMIN_COMMANDS = ADMIN + ".commands";

View File

@ -19,7 +19,7 @@ public class Statistics {
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_GODMODE("fight.godmode"), FI_INSTANTHEAL("fight.instantheal");
private final String name;