[BLEEDING] Add AutoSign check (first sketch).

This commit is contained in:
asofold 2013-04-22 04:38:14 +02:00
parent f4b88b3309
commit 3b4352c044
11 changed files with 203 additions and 15 deletions

View File

@ -57,6 +57,7 @@ public enum CheckType {
BLOCKPLACE(BlockPlaceConfig.factory, BlockPlaceData.factory, Permissions.BLOCKPLACE),
BLOCKPLACE_AGAINST(BLOCKPLACE, Permissions.BLOCKPLACE_AGAINST),
BLOCKPLACE_AUTOSIGN(BLOCKPLACE, Permissions.BLOCKPLACE_AUTOSIGN),
BLOCKPLACE_DIRECTION(BLOCKPLACE, Permissions.BLOCKPLACE_DIRECTION),
BLOCKPLACE_FASTPLACE(BLOCKPLACE, Permissions.BLOCKPLACE_FASTPLACE),
BLOCKPLACE_NOSWING(BLOCKPLACE, Permissions.BLOCKPLACE_NOSWING),

View File

@ -0,0 +1,110 @@
package fr.neatmonster.nocheatplus.checks.blockplace;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.utilities.StringUtil;
import fr.neatmonster.nocheatplus.utilities.TickTask;
public class AutoSign extends Check {
/** Reference time that is needed to edit the most complicated sign :). */
private static long maxEditTime = 1500;
/** Fastest time "possible" estimate for an empty sign. */
private static long minEditTime = 150;
/** Minimum time needed to add one extra line (not the first). */
private static long minLineTime = 50;
/** Minimum time needed to type a character. */
private static long minCharTime = 50;
private final List<String> tags = new ArrayList<String>();
final Set<Character> chars = new HashSet<Character>(15 * 4);
public AutoSign() {
super(CheckType.BLOCKPLACE_AUTOSIGN);
}
public boolean check(final Player player, final Block block, final String[] lines) {
// TODO: Might want to reset time + hash ?
final long time = System.currentTimeMillis();
tags.clear();
final BlockPlaceData data = BlockPlaceData.getData(player);
Material mat = block.getType();
if (mat == Material.WALL_SIGN){
// Use one thing for signs.
mat = Material.SIGN_POST;
}
if (data.autoSignPlacedHash != BlockPlaceListener.getBlockPlaceHash(block, mat)){
tags.add("block_mismatch");
return handleViolation(player, maxEditTime, data);
}
if (time < data.autoSignPlacedTime){
data.autoSignPlacedTime = 0;
return false;
}
// check time, mind lag.
final long editTime = time - data.autoSignPlacedTime;
long expected = getExpectedEditTime(lines);
expected = (long) (expected / TickTask.getLag(expected));
if (expected > editTime){
tags.add("edit_time");
return handleViolation(player, expected - editTime, data);
}
return false;
}
private long getExpectedEditTime(final String[] lines) {
long expected = minEditTime;
int n = 0;
for (String line : lines){
if (line != null){
line = line.trim().toLowerCase();
if (!line.isEmpty()){
chars.clear();
n += 1;
for (final char c : line.toCharArray()){
chars.add(c);
}
expected += minCharTime * chars.size();
}
}
}
if (n > 1){
expected += minLineTime * n;
}
return expected;
}
/**
*
* @param player
* @param violationTime Amount of too fast editing.
* @param data
* @return
*/
private boolean handleViolation(final Player player, final long violationTime, final BlockPlaceData data) {
final double addedVL = 10.0 * Math.min(maxEditTime, violationTime) / maxEditTime;
data.autoSignVL += addedVL;
final ViolationData vd = new ViolationData(this, player, data.autoSignVL, addedVL, BlockPlaceConfig.getConfig(player).autoSignActions);
if (vd.needsParameters()){
vd.setParameter(ParameterName.TAGS, StringUtil.join(tags, "+"));
}
return executeActions(vd);
}
}

View File

@ -71,6 +71,9 @@ public class BlockPlaceConfig extends ACheckConfig {
return worldsMap.get(player.getWorld().getName());
}
public final boolean autoSignCheck;
public final ActionList autoSignActions;
public final boolean directionCheck;
public final ActionList directionActions;
@ -98,6 +101,11 @@ public class BlockPlaceConfig extends ACheckConfig {
*/
public BlockPlaceConfig(final ConfigFile data) {
super(data, ConfPaths.BLOCKPLACE);
autoSignCheck = data.getBoolean(ConfPaths.BLOCKPLACE_AUTOSIGN_CHECK);
autoSignActions = data.getOptimizedActionList(ConfPaths.BLOCKPLACE_AUTOSIGN_ACTIONS, Permissions.BLOCKPLACE_AUTOSIGN);
directionCheck = data.getBoolean(ConfPaths.BLOCKPLACE_DIRECTION_CHECK);
directionActions = data.getOptimizedActionList(ConfPaths.BLOCKPLACE_DIRECTION_ACTIONS, Permissions.BLOCKPLACE_DIRECTION);
@ -136,6 +144,8 @@ public class BlockPlaceConfig extends ACheckConfig {
return speedCheck;
case BLOCKPLACE_AGAINST:
return true;
case BLOCKPLACE_AUTOSIGN:
return autoSignCheck;
default:
return true;
}

View File

@ -75,11 +75,16 @@ public class BlockPlaceData extends ACheckData {
}
// Violation levels.
public double directionVL;
public double fastPlaceVL;
public double noSwingVL;
public double reachVL;
public double speedVL;
public double autoSignVL = 0;
public double directionVL = 0;
public double fastPlaceVL = 0;
public double noSwingVL = 0;
public double reachVL = 0;
public double speedVL = 0;
// AutoSign.
public long autoSignPlacedTime = 0;
public long autoSignPlacedHash = 0;
// Data of the fast place check.
public final ActionFrequency fastPlaceBuckets = new ActionFrequency(2, 1000);

View File

@ -9,6 +9,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.event.player.PlayerAnimationEvent;
import org.bukkit.event.player.PlayerInteractEvent;
@ -46,6 +47,30 @@ import fr.neatmonster.nocheatplus.utilities.BlockProperties;
*/
public class BlockPlaceListener extends CheckListener {
private static final int p1 = 73856093;
private static final int p2 = 19349663;
private static final int p3 = 83492791;
private static final int getHash(final int x, final int y, final int z) {
return p1 * x ^ p2 * y ^ p3 * z;
}
public static int getCoordHash(final Block block){
return getHash(block.getX(), block.getY(), block.getZ());
}
public static int getBlockPlaceHash(final Block block, final Material mat){
int hash = getCoordHash(block);
if (mat != null){
hash |= mat.name().hashCode();
}
hash |= block.getWorld().getName().hashCode();
return hash;
}
/** AutoSign. */
private final AutoSign autoSign = addCheck(new AutoSign());
/** The direction check. */
private final Direction direction = addCheck(new Direction());
@ -104,6 +129,14 @@ public class BlockPlaceListener extends CheckListener {
if (!player.hasPermission(Permissions.BLOCKPLACE_AGAINST_AIR) && !NCPExemptionManager.isExempted(player, CheckType.BLOCKPLACE_AGAINST)) cancelled = true;
}
final BlockPlaceData data = BlockPlaceData.getData(player);
if (mat == Material.SIGN_POST || mat == Material.WALL_SIGN){
data.autoSignPlacedTime = System.currentTimeMillis();
// Always hash as sign post for improved compatibility with Lockette etc.
data.autoSignPlacedHash = getBlockPlaceHash(block, Material.SIGN_POST);
}
// First, the fast place check.
if (fastPlace.isEnabled(player)){
if (fastPlace.check(player, block))
@ -116,15 +149,15 @@ public class BlockPlaceListener extends CheckListener {
// Second, the no swing check (player doesn't swing his arm when placing a lily pad).
if (!cancelled && mat != Material.WATER_LILY && noSwing.isEnabled(player)
&& noSwing.check(player))
&& noSwing.check(player, data))
cancelled = true;
// Third, the reach check.
if (!cancelled && reach.isEnabled(player) && reach.check(player, block))
if (!cancelled && reach.isEnabled(player) && reach.check(player, block, data))
cancelled = true;
// Fourth, the direction check.
if (!cancelled && direction.isEnabled(player) && direction.check(player, block, blockAgainst))
if (!cancelled && direction.isEnabled(player) && direction.check(player, block, blockAgainst, data))
cancelled = true;
// If one of the checks requested to cancel the event, do so.
@ -132,6 +165,25 @@ public class BlockPlaceListener extends CheckListener {
event.setCancelled(cancelled);
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onSignChange(final SignChangeEvent event){
if (event.getClass() != SignChangeEvent.class){
// Built in plugin compatibility.
// TODO: Don't understand why two consecutive events editing the same block are a problem.
return;
}
final Player player = event.getPlayer();
final Block block = event.getBlock();
final String[] lines = event.getLines();
if (block == null || lines == null || player == null){
// Somewhat defensive.
return;
}
if (autoSign.isEnabled(player) && autoSign.check(player, block, lines)){
event.setCancelled(true);
}
}
/**
* We listen to PlayerAnimation events because it is (currently) equivalent to "player swings arm" and we want to
* check if he did that between block breaks.

View File

@ -35,12 +35,12 @@ public class Direction extends Check {
*
* @param player
* the player
* @param data
* @param location
* the location
* @return true, if successful
*/
public boolean check(final Player player, final Block placed, final Block against) {
final BlockPlaceData data = BlockPlaceData.getData(player);
public boolean check(final Player player, final Block placed, final Block against, final BlockPlaceData data) {
boolean cancel = false;

View File

@ -32,10 +32,10 @@ public class NoSwing extends Check {
*
* @param player
* the player
* @param data
* @return true, if successful
*/
public boolean check(final Player player) {
final BlockPlaceData data = BlockPlaceData.getData(player);
public boolean check(final Player player, final BlockPlaceData data) {
boolean cancel = false;

View File

@ -44,12 +44,12 @@ public class Reach extends Check {
*
* @param player
* the player
* @param data2
* @param location
* the location
* @return true, if successful
*/
public boolean check(final Player player, final Block block) {
final BlockPlaceData data = BlockPlaceData.getData(player);
public boolean check(final Player player, final Block block, final BlockPlaceData data) {
boolean cancel = false;

View File

@ -178,6 +178,10 @@ public abstract class ConfPaths {
*/
public static final String BLOCKPLACE = CHECKS + "blockplace.";
private static final String BLOCKPLACE_AUTOSIGN = BLOCKPLACE + "autosign.";
public static final String BLOCKPLACE_AUTOSIGN_CHECK = BLOCKPLACE_AUTOSIGN + "active";
public static final String BLOCKPLACE_AUTOSIGN_ACTIONS = BLOCKPLACE_AUTOSIGN + "actions";
private static final String BLOCKPLACE_DIRECTION = BLOCKPLACE + "direction.";
public static final String BLOCKPLACE_DIRECTION_CHECK = BLOCKPLACE_DIRECTION + "active";
public static final String BLOCKPLACE_DIRECTION_ACTIONS = BLOCKPLACE_DIRECTION + "actions";

View File

@ -148,6 +148,10 @@ public class DefaultConfig extends ConfigFile {
* 888 88b, 888 Y888 888P Y888 , 888 b 888 888 ,ee 888 Y888 , 888 ,
* 888 88P' 888 "88 88" "88,e8' 888 8b 888 888 "88 888 "88,e8' "YeeP"
*/
set(ConfPaths.BLOCKPLACE_AUTOSIGN_CHECK, true);
set(ConfPaths.BLOCKPLACE_AUTOSIGN_ACTIONS, "cancel vl>10 log:bautosign:0:3:if cancel");
set(ConfPaths.BLOCKPLACE_DIRECTION_CHECK, true);
set(ConfPaths.BLOCKPLACE_DIRECTION_ACTIONS, "cancel vl>10 log:bdirection:0:3:if cancel");
@ -458,6 +462,7 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.STRINGS + ".angle", start + "tried to hit multiple entities at the same time" + end);
set(ConfPaths.STRINGS + ".ban", "ban [player]");
set(ConfPaths.STRINGS + ".ban-ip", "ban-ip [ip]");
set(ConfPaths.STRINGS + ".bautosign", start + "failed autosign with [tags]" + end);
set(ConfPaths.STRINGS + ".bbfrequency", start + "tried to break too many blocks within time frame" + end);
set(ConfPaths.STRINGS + ".bdirection", start + "tried to interact with a block out of his line of sight" + end);
set(ConfPaths.STRINGS + ".bedleave", start + "sends bed leave packets (was not in bed)" + end);

View File

@ -95,6 +95,7 @@ public class Permissions {
*/
public static final String BLOCKPLACE = CHECKS + ".blockplace";
public static final String BLOCKPLACE_AGAINST = BLOCKPLACE + ".against";
public static final String BLOCKPLACE_AUTOSIGN = BLOCKPLACE + ".autosign";
public static final String BLOCKPLACE_AGAINST_AIR = BLOCKPLACE_AGAINST + ".air";
public static final String BLOCKPLACE_AGAINST_LIQUIDS = BLOCKPLACE_AGAINST + ".liquids";
public static final String BLOCKPLACE_BOATSANYWHERE = BLOCKPLACE + ".boatsanywhere";