mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-12-30 20:37:52 +01:00
Safety fuck up commit.
This commit is contained in:
parent
81ec563474
commit
3a1e9fe7d8
@ -21,8 +21,9 @@ package fr.neatmonster.nocheatplus.actions;
|
||||
* Some wildcards that are used in commands and log messages.
|
||||
*/
|
||||
public enum ParameterName {
|
||||
CHECK("check"),
|
||||
BLOCK_ID("blockid"),
|
||||
CHECK("check"),
|
||||
TAGS("tags"),
|
||||
DISTANCE("distance"),
|
||||
FALL_DISTANCE("falldistance"),
|
||||
FOOD("food"),
|
||||
|
@ -1,8 +1,5 @@
|
||||
package fr.neatmonster.nocheatplus.checks;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory;
|
||||
@ -23,7 +20,7 @@ import fr.neatmonster.nocheatplus.checks.inventory.InventoryConfig;
|
||||
import fr.neatmonster.nocheatplus.checks.inventory.InventoryData;
|
||||
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
|
||||
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
|
||||
import fr.neatmonster.nocheatplus.hooks.APIUtils;
|
||||
import fr.neatmonster.nocheatplus.players.DataManager;
|
||||
import fr.neatmonster.nocheatplus.players.Permissions;
|
||||
|
||||
/*
|
||||
@ -40,9 +37,9 @@ import fr.neatmonster.nocheatplus.players.Permissions;
|
||||
* Type of checks (containing configuration and dataFactory classes, name and permission).
|
||||
*/
|
||||
public enum CheckType {
|
||||
ALL,
|
||||
ALL(Permissions.CHECKS),
|
||||
|
||||
BLOCKBREAK(BlockBreakConfig.factory, BlockBreakData.factory),
|
||||
BLOCKBREAK(BlockBreakConfig.factory, BlockBreakData.factory, Permissions.BLOCKBREAK),
|
||||
BLOCKBREAK_DIRECTION(BLOCKBREAK, Permissions.BLOCKBREAK_DIRECTION),
|
||||
BLOCKBREAK_FASTBREAK(BLOCKBREAK, Permissions.BLOCKBREAK_FASTBREAK),
|
||||
BLOCKBREAK_FREQUENCY(BLOCKBREAK, Permissions.BLOCKBREAK_FREQUENCY),
|
||||
@ -50,18 +47,18 @@ public enum CheckType {
|
||||
BLOCKBREAK_REACH(BLOCKBREAK, Permissions.BLOCKBREAK_REACH),
|
||||
BLOCKBREAK_WRONGBLOCK(BLOCKBREAK, Permissions.BLOCKBREAK_WRONGBLOCK),
|
||||
|
||||
BLOCKINTERACT(BlockInteractConfig.factory, BlockInteractData.factory),
|
||||
BLOCKINTERACT(BlockInteractConfig.factory, BlockInteractData.factory, Permissions.BLOCKINTERACT),
|
||||
BLOCKINTERACT_DIRECTION(BLOCKINTERACT, Permissions.BLOCKINTERACT_DIRECTION),
|
||||
BLOCKINTERACT_REACH(BLOCKINTERACT, Permissions.BLOCKINTERACT_REACH),
|
||||
|
||||
BLOCKPLACE(BlockPlaceConfig.factory, BlockPlaceData.factory),
|
||||
BLOCKPLACE(BlockPlaceConfig.factory, BlockPlaceData.factory, Permissions.BLOCKPLACE),
|
||||
BLOCKPLACE_DIRECTION(BLOCKPLACE, Permissions.BLOCKPLACE_DIRECTION),
|
||||
BLOCKPLACE_FASTPLACE(BLOCKPLACE, Permissions.BLOCKPLACE_FASTPLACE),
|
||||
BLOCKPLACE_NOSWING(BLOCKPLACE, Permissions.BLOCKPLACE_NOSWING),
|
||||
BLOCKPLACE_REACH(BLOCKPLACE, Permissions.BLOCKBREAK_REACH),
|
||||
BLOCKPLACE_SPEED(BLOCKPLACE, Permissions.BLOCKPLACE_SPEED),
|
||||
|
||||
CHAT(ChatConfig.factory, ChatData.factory),
|
||||
CHAT(ChatConfig.factory, ChatData.factory, Permissions.CHAT),
|
||||
CHAT_CAPTCHA(CHAT, Permissions.CHAT_CAPTCHA),
|
||||
CHAT_COLOR(CHAT, Permissions.CHAT_COLOR),
|
||||
CHAT_COMMANDS(CHAT, Permissions.CHAT_COMMANDS),
|
||||
@ -70,10 +67,10 @@ public enum CheckType {
|
||||
CHAT_RELOG(CHAT, Permissions.CHAT_RELOG),
|
||||
|
||||
|
||||
COMBINED(CombinedConfig.factory, CombinedData.factory),
|
||||
COMBINED(CombinedConfig.factory, CombinedData.factory, Permissions.COMBINED),
|
||||
COMBINED_IMPROBABLE(COMBINED, Permissions.COMBINED_IMPROBABLE),
|
||||
|
||||
FIGHT(FightConfig.factory, FightData.factory),
|
||||
FIGHT(FightConfig.factory, FightData.factory, Permissions.FIGHT),
|
||||
FIGHT_ANGLE(FIGHT, Permissions.FIGHT_ANGLE),
|
||||
FIGHT_CRITICAL(FIGHT, Permissions.FIGHT_CRITICAL),
|
||||
FIGHT_DIRECTION(FIGHT, Permissions.FIGHT_DIRECTION),
|
||||
@ -84,14 +81,14 @@ public enum CheckType {
|
||||
FIGHT_SELFHIT(FIGHT, Permissions.FIGHT_SELFHIT),
|
||||
FIGHT_SPEED(FIGHT, Permissions.FIGHT_SPEED),
|
||||
|
||||
INVENTORY(InventoryConfig.factory, InventoryData.factory),
|
||||
INVENTORY(InventoryConfig.factory, InventoryData.factory, Permissions.INVENTORY),
|
||||
INVENTORY_DROP(INVENTORY, Permissions.INVENTORY_DROP),
|
||||
INVENTORY_FASTCLICK(INVENTORY, Permissions.INVENTORY_FASTCLICK),
|
||||
INVENTORY_INSTANTBOW(INVENTORY, Permissions.INVENTORY_INSTANTBOW),
|
||||
INVENTORY_INSTANTEAT(INVENTORY, Permissions.INVENTORY_INSTANTEAT),
|
||||
INVENTORY_ITEMS(INVENTORY, Permissions.INVENTORY_ITEMS),
|
||||
|
||||
MOVING(MovingConfig.factory, MovingData.factory),
|
||||
MOVING(MovingConfig.factory, MovingData.factory, Permissions.MOVING),
|
||||
MOVING_CREATIVEFLY(MOVING, Permissions.MOVING_CREATIVEFLY),
|
||||
MOVING_MOREPACKETS(MOVING, Permissions.MOVING_MOREPACKETS),
|
||||
MOVING_MOREPACKETSVEHICLE(MOVING, Permissions.MOVING_MOREPACKETSVEHICLE),
|
||||
@ -101,50 +98,65 @@ public enum CheckType {
|
||||
|
||||
UNKNOWN;
|
||||
|
||||
/** The group. */
|
||||
private CheckType parent = null;
|
||||
/** If not null, this is the check group usually. */
|
||||
private final CheckType parent;
|
||||
|
||||
/** The configFactory. */
|
||||
private CheckConfigFactory configFactory = null;
|
||||
/** The check config factory (access CheckConfig instances by CheckType). */
|
||||
private final CheckConfigFactory configFactory;
|
||||
|
||||
/** The dataFactory. */
|
||||
private CheckDataFactory dataFactory = null;
|
||||
/** The check data factory (access CheckData instances by CheckType). */
|
||||
private final CheckDataFactory dataFactory;
|
||||
|
||||
/** The permission. */
|
||||
private String permission = null;
|
||||
/** The bypass permission. */
|
||||
private final String permission;
|
||||
|
||||
/**
|
||||
* Instantiates a new check type.
|
||||
*/
|
||||
private CheckType() {}
|
||||
/**
|
||||
* Special purpose check types (likely not actual checks).
|
||||
*/
|
||||
private CheckType() {
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new check type.
|
||||
*
|
||||
* @param configFactory
|
||||
* the configFactory
|
||||
* @param dataFactory
|
||||
* the dataFactory
|
||||
*/
|
||||
private CheckType(final CheckConfigFactory configFactory, final CheckDataFactory dataFactory) {
|
||||
this.configFactory = configFactory;
|
||||
this.dataFactory = dataFactory;
|
||||
}
|
||||
/**
|
||||
* Special purpose for grouping (ALL).
|
||||
* @param permission
|
||||
*/
|
||||
private CheckType(final String permission){
|
||||
this(null, null, permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new check type.
|
||||
*
|
||||
* @param parent
|
||||
* the parent
|
||||
* @param permission
|
||||
* the permission
|
||||
*/
|
||||
private CheckType(final CheckType parent, final String permission) {
|
||||
this.parent = parent;
|
||||
configFactory = parent.getConfigFactory();
|
||||
dataFactory = parent.getDataFactory();
|
||||
this.permission = permission;
|
||||
}
|
||||
/**
|
||||
* Constructor for root checks or check groups, that are not grouped under another check type.
|
||||
* @param configFactory
|
||||
* @param dataFactory
|
||||
* @param permission
|
||||
*/
|
||||
private CheckType(final CheckConfigFactory configFactory, final CheckDataFactory dataFactory, final String permission) {
|
||||
this(null, permission, configFactory, dataFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for sub-checks grouped under another check type.
|
||||
* @param parent
|
||||
* @param permission
|
||||
*/
|
||||
private CheckType(final CheckType parent, final String permission) {
|
||||
this(parent, permission, parent.getConfigFactory(), parent.getDataFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Root constructor.
|
||||
* @param parent Super check type (usually the group).
|
||||
* @param permission Bypass permission.
|
||||
* @param configFactory Check config factory.
|
||||
* @param dataFactory Check data factory.
|
||||
*/
|
||||
private CheckType(final CheckType parent, final String permission, final CheckConfigFactory configFactory, final CheckDataFactory dataFactory) {
|
||||
this.parent = parent;
|
||||
this.permission = permission;
|
||||
this.configFactory = configFactory;
|
||||
this.dataFactory = dataFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configFactory.
|
||||
@ -183,7 +195,7 @@ public enum CheckType {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the permission.
|
||||
* Gets the bypass permission for this check type.
|
||||
*
|
||||
* @return the permission
|
||||
*/
|
||||
@ -223,29 +235,12 @@ public enum CheckType {
|
||||
|
||||
/**
|
||||
* Remove the player data for a given player and a given check type. CheckType.ALL and null will be interpreted as removing all data.<br>
|
||||
* @deprecated Will be removed, use DataManager.removeData instead.
|
||||
* @param playerName
|
||||
* @param checkType
|
||||
* @return If any data was present.
|
||||
*/
|
||||
public static boolean removeData(final String playerName, CheckType checkType) {
|
||||
if (checkType == null) checkType = ALL;
|
||||
|
||||
// Attempt for direct removal.
|
||||
CheckDataFactory dataFactory = checkType.getDataFactory();
|
||||
if (dataFactory != null) return dataFactory.removeData(playerName) != null;
|
||||
|
||||
// Remove all for which it seems necessary.
|
||||
final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
|
||||
for (CheckType otherType : CheckType.values()){
|
||||
if (checkType == ALL || APIUtils.isParent(checkType, otherType)){
|
||||
final CheckDataFactory otherFactory = otherType.getDataFactory();
|
||||
if (otherFactory != null) factories.add(otherFactory);
|
||||
}
|
||||
}
|
||||
boolean had = false;
|
||||
for (final CheckDataFactory otherFactory : factories){
|
||||
if (otherFactory.removeData(playerName) != null) had = true;
|
||||
}
|
||||
return had;
|
||||
public static boolean removeData(final String playerName, final CheckType checkType) {
|
||||
return DataManager.removeData(playerName, checkType);
|
||||
}
|
||||
}
|
@ -54,7 +54,7 @@ public class CombinedListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onEntityDamage(final EntityDamageEvent event){
|
||||
final Entity entity = event.getEntity();
|
||||
if (!(entity instanceof Player)) return;
|
||||
|
@ -116,20 +116,16 @@ public class FightListener implements Listener {
|
||||
cancelled = true;
|
||||
}
|
||||
|
||||
|
||||
if (!cancelled && angle.isEnabled(player)){
|
||||
// Improbable yaw.
|
||||
if (Combined.checkYawRate(player, player.getLocation().getYaw(), now, worldName, cc.yawRateCheck)){
|
||||
// (Check or just feed).
|
||||
cancelled = true;
|
||||
}
|
||||
// Angle check.
|
||||
if (angle.check(player, worldChanged)) cancelled = true;
|
||||
}
|
||||
else{
|
||||
// Always feed yaw rate here.
|
||||
Combined.feedYawRate(player, player.getLocation().getYaw(), now, worldName);
|
||||
}
|
||||
if (angle.isEnabled(player)) {
|
||||
// The "fast turning" checks are checked in any case because they accumulate data.
|
||||
// Improbable yaw changing.
|
||||
if (Combined.checkYawRate(player, player.getLocation().getYaw(), now, worldName, cc.yawRateCheck)) {
|
||||
// (Check or just feed).
|
||||
cancelled = true;
|
||||
}
|
||||
// Angle check.
|
||||
if (angle.check(player, worldChanged)) cancelled = true;
|
||||
}
|
||||
|
||||
if (!cancelled && critical.isEnabled(player) && critical.check(player))
|
||||
cancelled = true;
|
||||
|
@ -87,7 +87,9 @@ public class MovingData extends ACheckData {
|
||||
/** Last from coordinates. */
|
||||
public double fromX = Double.MAX_VALUE, fromY, fromZ;
|
||||
/** Last to coordinates. */
|
||||
public double toX = Double.MAX_VALUE, toY, toZ;
|
||||
public double toX = Double.MAX_VALUE, toY, toZ;
|
||||
/** To was ground or web etc. */
|
||||
public boolean toWasReset;
|
||||
|
||||
// Data of the creative check.
|
||||
public boolean creativeFlyPreviousRefused;
|
||||
@ -153,6 +155,24 @@ public class MovingData extends ACheckData {
|
||||
clearNoFallData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mildly reset the flying data without losing any important information.
|
||||
*
|
||||
* @param setBack
|
||||
*/
|
||||
public void onSetBack(final Location setBack) {
|
||||
// Reset positions
|
||||
resetPositions(teleported);
|
||||
this.setBack = teleported;
|
||||
clearAccounting(); // Might be more safe to do this.
|
||||
// Keep no-fall data.
|
||||
// Fly data: problem is we don't remember the settings for the set back location.
|
||||
// Assume the player to start falling from there rather, or be on ground.
|
||||
// Keep jump amplifier
|
||||
// Keep bunny-hop delay (?)
|
||||
// keep jump phase.
|
||||
}
|
||||
|
||||
public void clearAccounting() {
|
||||
final long now = System.currentTimeMillis();
|
||||
hDistSum.clear(now);
|
||||
|
@ -26,6 +26,7 @@ import org.bukkit.event.player.PlayerBedLeaveEvent;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerGameModeChangeEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerKickEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerPortalEvent;
|
||||
@ -208,9 +209,18 @@ public class MovingListener implements Listener {
|
||||
final Player player = event.getPlayer();
|
||||
final MovingData data = MovingData.getData(player);
|
||||
|
||||
if (!creativeFly.isEnabled(player) && survivalFly.isEnabled(player) && survivalFly.check(player) && data.ground != null)
|
||||
// To cancel the event, we simply teleport the player to his last safe location.
|
||||
player.teleport(data.ground);
|
||||
if (!creativeFly.isEnabled(player) && survivalFly.isEnabled(player) && survivalFly.check(player)) {
|
||||
// To cancel the event, we simply teleport the player to his last
|
||||
// safe location.
|
||||
Location target = null;
|
||||
if (data.ground != null) target = data.ground;
|
||||
else if (data.setBack != null) target = data.setBack;
|
||||
// else target = player.getLocation(); // TODO
|
||||
|
||||
|
||||
if (target != null) player.teleport(target);// TODO: schedule / other measures ?
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -350,20 +360,11 @@ public class MovingListener implements Listener {
|
||||
data.noFallAssumeGround = false;
|
||||
data.teleported = null;
|
||||
|
||||
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
|
||||
// Potion effect "Jump".
|
||||
final double jumpAmplifier;
|
||||
if (mcPlayer.hasEffect(MobEffectList.JUMP)) {
|
||||
// final int amplifier = mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
|
||||
// if (amplifier > 20)
|
||||
// jumpAmplifier = 1.5D * (amplifier + 1D);
|
||||
// else
|
||||
// jumpAmplifier = 1.2D * (amplifier + 1D);
|
||||
jumpAmplifier = 1D + mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
|
||||
if (cc.debug) System.out.println(player.getName() + " Jump effect: " + data.jumpAmplifier);
|
||||
}
|
||||
else jumpAmplifier = 1D;
|
||||
if (jumpAmplifier > data.jumpAmplifier) data.jumpAmplifier = jumpAmplifier;
|
||||
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
|
||||
// Potion effect "Jump".
|
||||
final double jumpAmplifier = MovingListener.getJumpAmplifier(mcPlayer);
|
||||
if (jumpAmplifier > 0D && cc.debug) System.out.println(player.getName() + " Jump effect: " + data.jumpAmplifier);
|
||||
if (jumpAmplifier > data.jumpAmplifier) data.jumpAmplifier = jumpAmplifier;
|
||||
|
||||
// Just try to estimate velocities over time. Not very precise, but works good enough most of the time. Do
|
||||
// general data modifications one for each event.
|
||||
@ -386,13 +387,18 @@ public class MovingListener implements Listener {
|
||||
}
|
||||
|
||||
|
||||
Location newTo = null;
|
||||
Location newTo = null;
|
||||
|
||||
if (passable.isEnabled(player)) newTo = passable.check(player, pFrom, pTo, data, cc);
|
||||
final Location passableTo;
|
||||
// Check passable in any case (!)
|
||||
if (cc.passableCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_PASSABLE) && !player.hasPermission(Permissions.MOVING_PASSABLE)) {
|
||||
// Passable is checked first to get the original set-back locations from the other checks, if needed.
|
||||
passableTo = passable.check(player, pFrom, pTo, data, cc);
|
||||
}
|
||||
else passableTo = null;
|
||||
|
||||
// Optimized checking, giving creativefly permission precedence over survivalfly.
|
||||
if (newTo != null);
|
||||
else if (!player.hasPermission(Permissions.MOVING_CREATIVEFLY)){
|
||||
if (!player.hasPermission(Permissions.MOVING_CREATIVEFLY)){
|
||||
// Either survivalfly or speed check.
|
||||
if ((cc.ignoreCreative || player.getGameMode() != GameMode.CREATIVE) && (cc.ignoreAllowFlight || !player.getAllowFlight())
|
||||
&& cc.survivalFlyCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_SURVIVALFLY) && !player.hasPermission(Permissions.MOVING_SURVIVALFLY)){
|
||||
@ -411,13 +417,16 @@ public class MovingListener implements Listener {
|
||||
}
|
||||
else data.clearFlyData();
|
||||
|
||||
if (newTo == null
|
||||
&& cc.morePacketsCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_MOREPACKETS) && !player.hasPermission(Permissions.MOVING_MOREPACKETS))
|
||||
// If he hasn't been stopped by any other check and is handled by the more packets check, execute it.
|
||||
newTo = morePackets.check(player, pFrom, pTo, data, cc);
|
||||
else
|
||||
// Otherwise we need to clear his data.
|
||||
data.clearMorePacketsData();
|
||||
if (newTo == null && cc.morePacketsCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_MOREPACKETS) && !player.hasPermission(Permissions.MOVING_MOREPACKETS)) {
|
||||
// If he hasn't been stopped by any other check and is handled by the more packets check, execute it.
|
||||
newTo = morePackets.check(player, pFrom, pTo, data, cc);
|
||||
} else {
|
||||
// Otherwise we need to clear his data.
|
||||
data.clearMorePacketsData();
|
||||
}
|
||||
|
||||
// Prefer the location returned by passable.
|
||||
if (passableTo != null) newTo = passableTo;
|
||||
|
||||
// Did one of the checks decide we need a new "to"-location?
|
||||
if (newTo != null) {
|
||||
@ -427,13 +436,16 @@ public class MovingListener implements Listener {
|
||||
// Remember where we send the player to.
|
||||
data.teleported = newTo;
|
||||
}
|
||||
|
||||
// Set positions.
|
||||
// TODO: Should these be set on monitor ?
|
||||
data.fromX = from.getX();
|
||||
data.fromY = from.getY();
|
||||
data.fromZ = from.getZ();
|
||||
data.toX = to.getX();
|
||||
data.toY = to.getY();
|
||||
data.toZ = to.getZ();
|
||||
|
||||
// Cleanup.
|
||||
moveInfo.cleanup();
|
||||
parkedInfo.add(moveInfo);
|
||||
@ -517,15 +529,15 @@ public class MovingListener implements Listener {
|
||||
data.clearMorePacketsData();
|
||||
}
|
||||
|
||||
/**
|
||||
* When a player respawns, all information related to the moving checks becomes invalid.
|
||||
*
|
||||
* @param event
|
||||
* the event
|
||||
*/
|
||||
@EventHandler(
|
||||
priority = EventPriority.MONITOR)
|
||||
public void onPlayerRespawn(final PlayerRespawnEvent event) {
|
||||
/**
|
||||
* When a player respawns, all information related to the moving checks
|
||||
* becomes invalid.
|
||||
*
|
||||
* @param event
|
||||
* the event
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerRespawn(final PlayerRespawnEvent event) {
|
||||
/*
|
||||
* ____ _ ____
|
||||
* | _ \| | __ _ _ _ ___ _ __ | _ \ ___ ___ _ __ __ ___ ___ __
|
||||
@ -534,10 +546,15 @@ public class MovingListener implements Listener {
|
||||
* |_| |_|\__,_|\__, |\___|_| |_| \_\___||___/ .__/ \__,_| \_/\_/ |_| |_|
|
||||
* |___/ |_|
|
||||
*/
|
||||
final MovingData data = MovingData.getData(event.getPlayer());
|
||||
data.clearFlyData();
|
||||
data.clearMorePacketsData();
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
final MovingData data = MovingData.getData(player);
|
||||
data.clearFlyData();
|
||||
data.clearMorePacketsData();
|
||||
if (survivalFly.isEnabled(player)) {
|
||||
data.setBack = event.getRespawnLocation();
|
||||
data.ground = event.getRespawnLocation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a player gets teleported, it may have two reasons. Either it was NoCheat or another plugin. If it was
|
||||
@ -548,8 +565,7 @@ public class MovingListener implements Listener {
|
||||
* @param event
|
||||
* the event
|
||||
*/
|
||||
@EventHandler(
|
||||
ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
@EventHandler(ignoreCancelled = false, priority = EventPriority.HIGHEST)
|
||||
public void onPlayerTeleport(final PlayerTeleportEvent event) {
|
||||
/*
|
||||
* ____ _ _____ _ _
|
||||
@ -559,29 +575,34 @@ public class MovingListener implements Listener {
|
||||
* |_| |_|\__,_|\__, |\___|_| |_|\___|_|\___| .__/ \___/|_| \__|
|
||||
* |___/ |_|
|
||||
*/
|
||||
final Player player = event.getPlayer();
|
||||
final MovingData data = MovingData.getData(player);
|
||||
final Player player = event.getPlayer();
|
||||
final MovingData data = MovingData.getData(player);
|
||||
|
||||
final Location teleported = data.teleported;
|
||||
final Location teleported = data.teleported;
|
||||
|
||||
// If it was a teleport initialized by NoCheatPlus, do it anyway even if another plugin said "no".
|
||||
final Location to = event.getTo();
|
||||
if (event.isCancelled() && teleported != null && data.teleported.equals(to)){
|
||||
// TODO: even more strict enforcing ?
|
||||
event.setCancelled(false);
|
||||
event.setTo(teleported);
|
||||
event.setFrom(teleported);
|
||||
data.clearFlyData();
|
||||
data.resetPositions(teleported);
|
||||
}
|
||||
else{
|
||||
// Only if it wasn't NoCheatPlus, drop data from more packets check. If it was NoCheatPlus, we don't
|
||||
// want players to exploit the fly check teleporting to get rid of the "morepackets" data.
|
||||
// TODO: check if to do with cancelled teleports !
|
||||
data.clearMorePacketsData();
|
||||
data.clearFlyData();
|
||||
data.resetPositions(event.isCancelled() ? event.getFrom() : to);
|
||||
}
|
||||
// If it was a teleport initialized by NoCheatPlus, do it anyway even if another plugin said "no".
|
||||
final Location to = event.getTo();
|
||||
if (teleported != null && teleported.equals(to)) {
|
||||
// Teleport by NCP.
|
||||
// Prevent cheaters getting rid of flying data (morepackets, other).
|
||||
// TODO: even more strict enforcing ?
|
||||
if (event.isCancelled()) {
|
||||
event.setCancelled(false);
|
||||
event.setTo(teleported);
|
||||
event.setFrom(teleported);
|
||||
}
|
||||
else{
|
||||
// Not cancelled but NCP teleport.
|
||||
}
|
||||
// TODO: This could be done on MONITOR.
|
||||
data.onSetBack(teleported);
|
||||
} else {
|
||||
// Only if it wasn't NoCheatPlus, drop data from more packets check.
|
||||
// TODO: check if to do with cancelled teleports !
|
||||
data.clearMorePacketsData();
|
||||
data.clearFlyData();
|
||||
data.resetPositions(event.isCancelled() ? event.getFrom() : to);
|
||||
}
|
||||
|
||||
|
||||
// Always drop data from fly checks, as it always loses its validity after teleports. Always!
|
||||
@ -715,6 +736,22 @@ public class MovingListener implements Listener {
|
||||
// Entity fall-distance should be reset elsewhere.
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerJoin(final PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (survivalFly.isEnabled(player)){
|
||||
final MovingData data = MovingData.getData(player);
|
||||
// TODO: on existing set back: detect world changes and loss of world on join (+ set up some paradigm).
|
||||
if (data.setBack == null){
|
||||
data.setBack = player.getLocation();
|
||||
}
|
||||
if (data.fromX == Double.MAX_VALUE && data.toX == Double.MAX_VALUE){
|
||||
// TODO: re-think: more fine grained reset?
|
||||
data.resetPositions(data.setBack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(final PlayerQuitEvent event){
|
||||
noFall.onLeave(event.getPlayer());
|
||||
@ -724,4 +761,15 @@ public class MovingListener implements Listener {
|
||||
public void onPlayerKick(final PlayerKickEvent event){
|
||||
noFall.onLeave(event.getPlayer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine "some jump amplifier": 1 is jump boost, 2 is jump boost II.
|
||||
* @param mcPlayer
|
||||
* @return
|
||||
*/
|
||||
public static final double getJumpAmplifier(final EntityPlayer mcPlayer) {
|
||||
if (mcPlayer.hasEffect(MobEffectList.JUMP)) {
|
||||
return 1D + mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
|
||||
} else return 0D;
|
||||
}
|
||||
}
|
||||
|
@ -19,54 +19,63 @@ public class Passable extends Check {
|
||||
super(CheckType.MOVING_PASSABLE);
|
||||
}
|
||||
|
||||
public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc){
|
||||
public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc)
|
||||
{
|
||||
// Simple check.
|
||||
if (!to.isPassable()){
|
||||
Location loc = null; // players location if should be used.
|
||||
if (!to.isPassable()) {
|
||||
Location loc = null; // players location if should be used.
|
||||
// Allow moving into the same block.
|
||||
if (from.isSameBlock(to)){
|
||||
if (!from.isPassable()){
|
||||
final double eyeY = to.getY() + player.getEyeHeight();
|
||||
final int eyeBlockY = Location.locToBlock(eyeY);
|
||||
if (eyeBlockY != to.getBlockY()){
|
||||
if (BlockProperties.isPassable(to.getBlockAccess(), to.getX(), eyeY, to.getZ(), to.getTypeId(to.getBlockX(), eyeBlockY, to.getBlockZ()))){
|
||||
// Allow moving inside the same block if head is free.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Only allow moving further out of the block (still allows going round in circles :p)
|
||||
// TODO: account for actual bounding box.
|
||||
final Vector blockMiddle = new Vector(0.5 + from.getBlockX(), 0.5 + from.getBlockY(), 0.5 + from.getBlockZ());
|
||||
// TODO: Allow moving out of one block towards non-solid blocks (closest only ?).
|
||||
// TODO: Allow moving out of half steps ?
|
||||
// TODO: Allow moving towards non solid blocks.
|
||||
if (blockMiddle.distanceSquared(from.getVector()) < blockMiddle.distanceSquared(to.getVector())) {
|
||||
// Further check for the players location as possible set back.
|
||||
loc = player.getLocation();
|
||||
if (to.isSamePos(loc) ){
|
||||
loc = null;
|
||||
}
|
||||
else if (!BlockProperties.isPassable(from.getBlockAccess(), loc.getX(), loc.getY(), loc.getZ(), from.getTypeId(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()))){
|
||||
// Allow the move
|
||||
return null;
|
||||
}
|
||||
// else is passable: use the location instead of from.
|
||||
}
|
||||
if (from.isSameBlock(to)) {
|
||||
if (!from.isPassable()) {
|
||||
final double eyeY = to.getY() + player.getEyeHeight();
|
||||
final int eyeBlockY = Location.locToBlock(eyeY);
|
||||
if (eyeBlockY != to.getBlockY()) {
|
||||
if (BlockProperties.isPassable(to.getBlockAccess(), to.getX(), eyeY, to.getZ(), to.getTypeId(to.getBlockX(), eyeBlockY, to.getBlockZ()))) {
|
||||
// Allow moving inside the same block if head is
|
||||
// free.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Only allow moving further out of the block (still allows
|
||||
// going round in circles :p)
|
||||
// TODO: account for actual bounding box.
|
||||
final Vector blockMiddle = new Vector(0.5 + from.getBlockX(), 0.5 + from.getBlockY(), 0.5 + from.getBlockZ());
|
||||
// TODO: Allow moving out of one block towards non-solid
|
||||
// blocks (closest only ?).
|
||||
// TODO: Allow moving out of half steps ?
|
||||
// TODO: Allow moving towards non solid blocks.
|
||||
if (blockMiddle.distanceSquared(from.getVector()) < blockMiddle.distanceSquared(to.getVector())) {
|
||||
// Further check for the players location as possible
|
||||
// set back.
|
||||
loc = player.getLocation();
|
||||
if (to.isSamePos(loc)) {
|
||||
loc = null;
|
||||
} else if (!BlockProperties.isPassable(from.getBlockAccess(), loc.getX(), loc.getY(), loc.getZ(), from.getTypeId(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()))) {
|
||||
// Allow the move
|
||||
return null;
|
||||
}
|
||||
// else is passable: use the location instead of from.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer the set-back location from the data.
|
||||
if (data.setBack != null && BlockProperties.isPassable(from.getBlockAccess(), data.setBack)) loc = data.setBack;
|
||||
|
||||
// Return the reset position.
|
||||
data.passableVL += 1d;
|
||||
final ViolationData vd = new ViolationData(this, player, data.passableVL, 1, cc.passableActions);
|
||||
if (vd.needsParameters()) vd.setParameter(ParameterName.BLOCK_ID, "" + to.getTypeId());
|
||||
if (executeActions(vd)){
|
||||
// TODO: Consider another set back position for this, also keeping track of players moving around in blocks.
|
||||
if (executeActions(vd)) {
|
||||
// TODO: Consider another set back position for this, also
|
||||
// keeping track of players moving around in blocks.
|
||||
final Location newTo;
|
||||
if (!from.isPassable() && loc == null){
|
||||
// Check if passable.
|
||||
loc = player.getLocation();
|
||||
if (to.isSamePos(loc) || !BlockProperties.isPassable(from.getBlockAccess(), loc.getX(), loc.getY(), loc.getZ(), from.getTypeId(from.getBlockX(), from.getBlockY(), from.getBlockZ()))){
|
||||
loc = null;
|
||||
}
|
||||
if (loc == null && !from.isPassable()) {
|
||||
// Check if passable.
|
||||
loc = player.getLocation();
|
||||
if (to.isSamePos(loc) || !BlockProperties.isPassable(from.getBlockAccess(), loc.getX(), loc.getY(), loc.getZ(), from.getTypeId(from.getBlockX(), from.getBlockY(), from.getBlockZ()))) {
|
||||
loc = null;
|
||||
}
|
||||
}
|
||||
if (loc != null) newTo = loc;
|
||||
else newTo = from.getLocation();
|
||||
@ -74,19 +83,16 @@ public class Passable extends Check {
|
||||
newTo.setPitch(to.getPitch());
|
||||
return newTo;
|
||||
}
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
data.passableVL *= 0.99;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<ParameterName, String> getParameterMap(final ViolationData violationData) {
|
||||
// TODO Auto-generated method stub
|
||||
protected Map<ParameterName, String> getParameterMap(final ViolationData violationData)
|
||||
{
|
||||
return super.getParameterMap(violationData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package fr.neatmonster.nocheatplus.checks.moving;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.minecraft.server.EntityPlayer;
|
||||
@ -13,7 +14,9 @@ import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.ViolationData;
|
||||
import fr.neatmonster.nocheatplus.players.Permissions;
|
||||
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
|
||||
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
|
||||
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
|
||||
|
||||
/*
|
||||
@ -47,6 +50,9 @@ public class SurvivalFly extends Check {
|
||||
/** Faster moving down stream (water mainly). */
|
||||
public static final double modDownStream = 0.19 / swimmingSpeed;
|
||||
|
||||
/** To join some tags with moving check violations. */
|
||||
private final ArrayList<String> tags = new ArrayList<String>(15);
|
||||
|
||||
/**
|
||||
* Instantiates a new survival fly check.
|
||||
*/
|
||||
@ -91,7 +97,7 @@ public class SurvivalFly extends Check {
|
||||
*/
|
||||
public Location check(final Player player, final EntityPlayer mcPlayer, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc) {
|
||||
final long now = System.currentTimeMillis();
|
||||
|
||||
tags.clear();
|
||||
// A player is considered sprinting if the flag is set and if he has enough food level.
|
||||
final boolean sprinting = player.isSprinting() && player.getFoodLevel() > 5;
|
||||
|
||||
@ -109,54 +115,60 @@ public class SurvivalFly extends Check {
|
||||
if (data.setBack == null)
|
||||
data.setBack = from.getLocation();
|
||||
|
||||
boolean resetFrom = fromOnGround || from.isInLiquid() || from.isOnLadder() || from.isInWeb();
|
||||
boolean resetFrom = fromOnGround || from.isInLiquid() || from.isOnLadder() || from.isInWeb();
|
||||
|
||||
final double setBackYDistance = to.getY() - data.setBack.getY();
|
||||
// If the player has touched the ground but it hasn't been noticed by the plugin, the workaround is here.
|
||||
if (!resetFrom){
|
||||
// Don't set "useWorkaround = x()", to avoid potential trouble with reordering to come, and similar.
|
||||
boolean useWorkaround = false;
|
||||
// Check for moving off stairs.
|
||||
if (!useWorkaround && from.isAboveStairs()) useWorkaround = true;
|
||||
// Check for "lost touch", for when moving events were not created, for instance (1/256).
|
||||
if (!useWorkaround){
|
||||
final boolean inconsistent = yDistance > 0 && yDistance < 0.5 && data.survivalFlyLastYDist < 0
|
||||
&& setBackYDistance > 0D && setBackYDistance <= 1.5D;
|
||||
if (inconsistent){
|
||||
if (cc.debug) System.out.println(player.getName() + " Y-INCONSISTENCY");
|
||||
if (data.fromX != Double.MAX_VALUE){
|
||||
// Interpolate from last to-coordinates to the from coordinates (with some safe-guard).
|
||||
final double dX = from.getX() - data.fromX;
|
||||
final double dY = from.getY() - data.fromY;
|
||||
final double dZ = from.getZ() - data.fromZ;
|
||||
if (dX * dX + dY * dY + dZ * dZ < 0.5){ // TODO: adjust limit maybe.
|
||||
// Check full bounding box since last from.
|
||||
if (cc.debug) System.out.println(player.getName() + " CONSIDER WORKAROUND");
|
||||
final double minY = Math.min(data.toY, Math.min(data.fromY, from.getY()));
|
||||
final double iY = minY; // TODO ...
|
||||
final double r = from.getWidth() / 2.0;
|
||||
if (BlockProperties.isOnGround(from.getBlockAccess(), Math.min(data.fromX, from.getX()) - r, iY - cc.yOnGround, Math.min(data.fromZ, from.getZ()) - r, Math.max(data.fromX, from.getX()) + r, iY + 0.25, Math.max(data.fromZ, from.getZ()) + r)) useWorkaround = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (useWorkaround){ // !toOnGround && to.isAboveStairs()) {
|
||||
// Set the new setBack and reset the jumpPhase.
|
||||
|
||||
// Maybe don't adapt the setback (unless null)!
|
||||
// data.setBack = from.getLocation();
|
||||
data.setBack.setY(Location.locToBlock(data.setBack.getY()));
|
||||
// data.ground ?
|
||||
// ? set jumpphase to height / 0.15 ?
|
||||
data.survivalFlyJumpPhase = 0;
|
||||
data.jumpAmplifier = 0; // Might conflict, should probably fetch.
|
||||
data.clearAccounting();
|
||||
// Tell NoFall that we assume the player to have been on ground somehow.
|
||||
data.noFallAssumeGround = true;
|
||||
resetFrom = true;
|
||||
if (cc.debug) System.out.println(player.getName() + " Y-INCONSISTENCY WORKAROUND USED");
|
||||
}
|
||||
}
|
||||
final double setBackYDistance = to.getY() - data.setBack.getY();
|
||||
// If the player has touched the ground but it hasn't been noticed by
|
||||
// the plugin, the workaround is here.
|
||||
if (!resetFrom) {
|
||||
// Don't set "useWorkaround = x()", to avoid potential trouble with
|
||||
// reordering to come, and similar.
|
||||
boolean useWorkaround = false;
|
||||
boolean setBackSafe = false; // Let compiler remove this if necessary.
|
||||
// Check for moving off stairs.
|
||||
if (!useWorkaround && from.isAboveStairs()) {
|
||||
useWorkaround = true;
|
||||
setBackSafe = true;
|
||||
}
|
||||
// Check for "lost touch", for when moving events were not created,
|
||||
// for instance (1/256).
|
||||
if (!useWorkaround && yDistance > 0 && yDistance < 0.5 && data.survivalFlyLastYDist < 0
|
||||
&& setBackYDistance > 0D && setBackYDistance <= 1.5D) {
|
||||
if (data.fromX != Double.MAX_VALUE) {
|
||||
// Interpolate from last to-coordinates to the from
|
||||
// coordinates (with some safe-guard).
|
||||
final double dX = from.getX() - data.fromX;
|
||||
final double dY = from.getY() - data.fromY;
|
||||
final double dZ = from.getZ() - data.fromZ;
|
||||
if (dX * dX + dY * dY + dZ * dZ < 0.5) { // TODO: adjust
|
||||
// limit maybe.
|
||||
// Check full bounding box since last from.
|
||||
final double minY = Math.min(data.toY, Math.min(data.fromY, from.getY()));
|
||||
final double iY = minY; // TODO ...
|
||||
final double r = from.getWidth() / 2.0;
|
||||
if (BlockProperties.isOnGround(from.getBlockAccess(), Math.min(data.fromX, from.getX()) - r, iY - cc.yOnGround, Math.min(data.fromZ, from.getZ()) - r, Math.max(data.fromX, from.getX()) + r, iY + 0.25, Math.max(data.fromZ, from.getZ()) + r)) {
|
||||
useWorkaround = true;
|
||||
setBackSafe = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (useWorkaround) { // !toOnGround && to.isAboveStairs()) {
|
||||
// Set the new setBack and reset the jumpPhase.
|
||||
if (setBackSafe) data.setBack = from.getLocation();
|
||||
// TODO: This seems dubious !
|
||||
data.setBack.setY(Location.locToBlock(data.setBack.getY()));
|
||||
// data.ground ?
|
||||
// ? set jumpphase to height / 0.15 ?
|
||||
data.survivalFlyJumpPhase = 0;
|
||||
data.jumpAmplifier = MovingListener.getJumpAmplifier(mcPlayer);
|
||||
data.clearAccounting();
|
||||
// Tell NoFall that we assume the player to have been on ground somehow.
|
||||
data.noFallAssumeGround = true;
|
||||
resetFrom = true; // Note: if removing this, other conditions need to check noFallAssume...
|
||||
tags.add("lostground");
|
||||
}
|
||||
}
|
||||
|
||||
// Player on ice? Give him higher max speed.
|
||||
if (from.isOnIce() || to.isOnIce())
|
||||
@ -190,16 +202,14 @@ public class SurvivalFly extends Check {
|
||||
hAllowedDistance *= cc.survivalFlySpeedingSpeed/ 100D;
|
||||
}
|
||||
|
||||
// TODO: Optimize: maybe only do the permission checks and modifiers if the distance is too big.
|
||||
// (Depending on permission plugin, with pex it will be hardly 1000 ns for all moving perms, if all false.)
|
||||
// TODO: More after-failure checks, to prevent unnecessary permission checking etc.
|
||||
// TODO: Split off not frequently used parts to methods.
|
||||
|
||||
// If the player is on ice, give him an higher maximum speed.
|
||||
if (data.survivalFlyOnIce > 0)
|
||||
hAllowedDistance *= modIce;
|
||||
|
||||
// Taken directly from Minecraft code, should work.
|
||||
|
||||
// player.hasPotionEffect(PotionEffectType.SPEED);
|
||||
// Speed amplifier.
|
||||
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT))
|
||||
hAllowedDistance *= 1.0D + 0.2D * (mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier() + 1);
|
||||
|
||||
@ -211,12 +221,15 @@ public class SurvivalFly extends Check {
|
||||
// Judge if horizontal speed is above limit.
|
||||
double hDistanceAboveLimit = hDistance - hAllowedDistance - data.horizontalFreedom;
|
||||
|
||||
// Prevent players from walking on a liquid.
|
||||
// TODO: yDistance == 0D <- should there not be a tolerance +- or 0...x ?
|
||||
if (hDistanceAboveLimit <= 0D && hDistance > 0.1D && yDistance == 0D
|
||||
&& BlockProperties.isLiquid(to.getTypeId()) && !toOnGround
|
||||
&& to.getY() % 1D < 0.8D)
|
||||
hDistanceAboveLimit = hDistance;
|
||||
// Tag for simple speed violation (medium), might get overridden.
|
||||
if (hDistanceAboveLimit > 0) tags.add("hspeed");
|
||||
|
||||
// Prevent players from walking on a liquid.
|
||||
// TODO: yDistance == 0D <- should there not be a tolerance +- or 0...x ?
|
||||
if (hDistanceAboveLimit <= 0D && hDistance > 0.1D && yDistance == 0D && BlockProperties.isLiquid(to.getTypeId()) && !toOnGround && to.getY() % 1D < 0.8D) {
|
||||
hDistanceAboveLimit = Math.max(hDistanceAboveLimit, hDistance);
|
||||
tags.add("waterwalk");
|
||||
}
|
||||
|
||||
// Prevent players from sprinting if they're moving backwards.
|
||||
if (hDistanceAboveLimit <= 0D && sprinting) {
|
||||
@ -225,7 +238,10 @@ public class SurvivalFly extends Check {
|
||||
&& yaw > 270F && yaw < 360F || xDistance > 0D && zDistance < 0D && yaw > 0F && yaw < 90F
|
||||
|| xDistance > 0D && zDistance > 0D && yaw > 90F && yaw < 180F){
|
||||
// Assumes permission check to be the heaviest (might be mistaken).
|
||||
if (!player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING)) hDistanceAboveLimit = hDistance;
|
||||
if (!player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING)){
|
||||
hDistanceAboveLimit = Math.max(hDistanceAboveLimit, hDistance);
|
||||
tags.add("sprintback");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,10 +249,11 @@ public class SurvivalFly extends Check {
|
||||
|
||||
// Did he go too far?
|
||||
if (hDistanceAboveLimit > 0 && sprinting)
|
||||
// Try to treat it as a the "bunnyhop" problem.
|
||||
// Try to treat it as a the "bunny-hop" problem.
|
||||
if (data.bunnyhopDelay <= 0 && hDistanceAboveLimit > 0.05D && hDistanceAboveLimit < 0.28D) {
|
||||
data.bunnyhopDelay = 9;
|
||||
hDistanceAboveLimit = 0D;
|
||||
tags.add("bunny"); // TODO: Which here...
|
||||
}
|
||||
|
||||
if (hDistanceAboveLimit > 0D) {
|
||||
@ -244,9 +261,13 @@ public class SurvivalFly extends Check {
|
||||
hDistanceAboveLimit -= data.horizontalBuffer;
|
||||
data.horizontalBuffer = 0D;
|
||||
|
||||
// Put back the "overconsumed" buffer.
|
||||
if (hDistanceAboveLimit < 0D)
|
||||
data.horizontalBuffer = -hDistanceAboveLimit;
|
||||
// Put back the "over-consumed" buffer.
|
||||
if (hDistanceAboveLimit < 0D){
|
||||
data.horizontalBuffer = -hDistanceAboveLimit;
|
||||
}
|
||||
if (hDistanceAboveLimit <= 0){
|
||||
tags.add("hbuffer"); // TODO: ...
|
||||
}
|
||||
} else
|
||||
data.horizontalBuffer = Math.min(1D, data.horizontalBuffer - hDistanceAboveLimit);
|
||||
|
||||
@ -255,27 +276,22 @@ public class SurvivalFly extends Check {
|
||||
if (from.isInWeb()){
|
||||
// Very simple: force players to descend or stay.
|
||||
vAllowedDistance = from.isOnGround() ? 0.1D : 0;
|
||||
data.jumpAmplifier = 0;
|
||||
data.jumpAmplifier = 0; // TODO: later maybe fetch.
|
||||
vDistanceAboveLimit = yDistance;
|
||||
if (cc.survivalFlyCobwebHack && vDistanceAboveLimit > 0 && hDistanceAboveLimit <= 0){
|
||||
if (now - data.survivalFlyCobwebTime > 3000){
|
||||
data.survivalFlyCobwebTime = now;
|
||||
data.survivalFlyCobwebVL = vDistanceAboveLimit * 100D;
|
||||
}
|
||||
else data.survivalFlyCobwebVL += vDistanceAboveLimit * 100D;
|
||||
if (data.survivalFlyCobwebVL < 550) { // Totally random !
|
||||
if (cc.debug) System.out.println(player.getName()+ " (Cobweb: silent set-back-)");
|
||||
// Silently set back.
|
||||
if (data.setBack == null) data.setBack = player.getLocation();
|
||||
data.survivalFlyJumpPhase = 0;
|
||||
data.setBack.setYaw(to.getYaw());
|
||||
data.setBack.setPitch(to.getPitch());
|
||||
data.survivalFlyLastYDist = Double.MAX_VALUE;
|
||||
return data.setBack;
|
||||
// TODO: This seemed fixed by latest builds of CraftBukkit, test and remove if appropriate!
|
||||
final Location silentSetBack = hackCobweb(player, data, to, now, vDistanceAboveLimit);
|
||||
if (silentSetBack != null){
|
||||
if (cc.debug) System.out.println(player.getName()+ " (Cobweb: silent set-back)");
|
||||
return silentSetBack;
|
||||
}
|
||||
}
|
||||
if (vDistanceAboveLimit > 0) tags.add("vweb");
|
||||
}
|
||||
// else if (verticalFreedom <= 0.001 && from.isOnLadder) ....
|
||||
// else if (verticalFreedom <= 0.001 (?) & from.isInFluid
|
||||
else{
|
||||
// Check traveled y-distance, orientation is air + jumping + velocity (as far as it gets).
|
||||
vAllowedDistance = (!(fromOnGround || data.noFallAssumeGround) && !toOnGround ? 1.45D : 1.35D) + data.verticalFreedom;
|
||||
final int maxJumpPhase;
|
||||
if (data.jumpAmplifier > 0){
|
||||
@ -287,45 +303,43 @@ public class SurvivalFly extends Check {
|
||||
vAllowedDistance -= Math.max(0, (data.survivalFlyJumpPhase - maxJumpPhase) * 0.15D);
|
||||
}
|
||||
|
||||
vDistanceAboveLimit = to.getY() - data.setBack.getY() - vAllowedDistance;
|
||||
vDistanceAboveLimit = to.getY() - data.setBack.getY() - vAllowedDistance;
|
||||
|
||||
// System.out.println("vda = " +vDistanceAboveLimit + " / vc = " + data.verticalVelocityCounter + " / vf = " + data.verticalFreedom + " / v = " + player.getVelocity().length());
|
||||
// Simple-step blocker.
|
||||
if ((fromOnGround || data.noFallAssumeGround) && toOnGround && Math.abs(yDistance - 1D) <= cc.yStep && vDistanceAboveLimit <= 0D && !player.hasPermission(Permissions.MOVING_SURVIVALFLY_STEP)) {
|
||||
vDistanceAboveLimit = Math.max(vDistanceAboveLimit, Math.abs(yDistance));
|
||||
tags.add("step");
|
||||
}
|
||||
}
|
||||
|
||||
// Step can also be blocked.
|
||||
if ((fromOnGround || data.noFallAssumeGround) && toOnGround && Math.abs(yDistance - 1D) <= cc.yStep && vDistanceAboveLimit <= 0D
|
||||
&& !player.hasPermission(Permissions.MOVING_SURVIVALFLY_STEP))
|
||||
vDistanceAboveLimit = Math.max(vDistanceAboveLimit, Math.abs(yDistance));
|
||||
if (data.noFallAssumeGround || fromOnGround || toOnGround) {
|
||||
// Some reset condition.
|
||||
data.jumpAmplifier = MovingListener.getJumpAmplifier(mcPlayer);
|
||||
}
|
||||
|
||||
}
|
||||
if (data.noFallAssumeGround || fromOnGround || toOnGround)
|
||||
data.jumpAmplifier = 0D;
|
||||
final boolean resetTo = toOnGround || to.isInLiquid() || to.isOnLadder()|| to.isInWeb();
|
||||
|
||||
if (cc.survivalFlyAccounting && !resetFrom){
|
||||
final boolean useH = data.horizontalFreedom <= 0.001D;
|
||||
final boolean useV = data.verticalFreedom <= 0.001D;
|
||||
if (useH){
|
||||
data.hDistSum.add(now, (float) hDistance);
|
||||
data.hDistCount.add(now, 1f);
|
||||
}
|
||||
if (useV){
|
||||
data.vDistSum.add(now, (float) (yDistance));
|
||||
data.vDistCount.add(now, 1f);
|
||||
}
|
||||
if (useH && data.hDistCount.getScore(2) > 0 && data.hDistCount.getScore(1) > 0){
|
||||
final float hsc0 = data.hDistSum.getScore(1);
|
||||
final float hsc1 = data.hDistSum.getScore(2);
|
||||
if (hsc0 < hsc1 || hDistance < 3.9 && hsc0 == hsc1){
|
||||
hDistanceAboveLimit = Math.max(hDistanceAboveLimit, hsc0 - hsc1);
|
||||
}
|
||||
}
|
||||
if (useV && data.vDistCount.getScore(2) > 0 && data.vDistCount.getScore(1) > 0){
|
||||
final float vsc0 = data.vDistSum.getScore(1);
|
||||
final float vsc1 = data.vDistSum.getScore(2);
|
||||
if (vsc0 < vsc1 || yDistance < 3.9 && vsc0 == vsc1){
|
||||
vDistanceAboveLimit = Math.max(vDistanceAboveLimit, vsc0 - vsc1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Accounting support.
|
||||
if (cc.survivalFlyAccounting && !resetFrom && !resetTo) {
|
||||
// Currently only for "air" phases.
|
||||
// Horizontal.
|
||||
if (data.horizontalFreedom <= 0.001D){
|
||||
// This only checks general speed decrease oncevelocity is smoked up.
|
||||
hDistanceAboveLimit = Math.max(hDistanceAboveLimit, doAccounting(now, hDistance, data.hDistSum, data.hDistCount, tags, "hacc"));
|
||||
}
|
||||
// Vertical.
|
||||
if (data.verticalFreedom <= 0.001D) { // && ! resetTo) {
|
||||
// Here yDistance can be negative and positive (!).
|
||||
// TODO: Might demand resetting on some direction changes (bunny,)
|
||||
vDistanceAboveLimit = Math.max(vDistanceAboveLimit, doAccounting(now, yDistance, data.vDistSum, data.vDistCount, tags, "vacc"));
|
||||
// // Check if y-direction is going upwards without speed / ground.
|
||||
// if (yDistance >= 0 && data.survivalFlyLastYDist < 0 && !data.toWasReset) {
|
||||
// // Moving upwards without having touched the ground.
|
||||
// vDistanceAboveLimit = Math.max(vDistanceAboveLimit, Math.abs(yDistance));
|
||||
// tags.add("ychange");
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
final double result = (Math.max(hDistanceAboveLimit, 0D) + Math.max(vDistanceAboveLimit, 0D)) * 100D;
|
||||
|
||||
@ -336,11 +350,11 @@ public class SurvivalFly extends Check {
|
||||
System.out.println(player.getName() + " hDist: " + hDistance + " / " + hAllowedDistance + " , vDist: " + (yDistance) + " ("+player.getVelocity().getY()+")" + " / " + vAllowedDistance);
|
||||
System.out.println(player.getName() + " y" + (fromOnGround?"(onground)":"") + (data.noFallAssumeGround?"(assumeonground)":"") + ": " + from.getY() +"(" + player.getLocation().getY() + ") -> " + to.getY()+ (toOnGround?"(onground)":""));
|
||||
if (cc.survivalFlyAccounting) System.out.println(player.getName() + " h=" + data.hDistSum.getScore(1f)+"/" + data.hDistSum.getScore(1) + " , v=" + data.vDistSum.getScore(1f)+"/"+data.vDistSum.getScore(1) );
|
||||
System.out.println(player.getName() + " tags: " + CheckUtils.join(tags, "+"));
|
||||
}
|
||||
|
||||
// Did the player move in unexpected ways?// Did the player move in unexpected ways?
|
||||
if (result > 0D) {
|
||||
// System.out.println(BlockProperties.isStairs(from.getTypeIdBelow()) + " / " + BlockProperties.isStairs(to.getTypeIdBelow()));
|
||||
// Increment violation counter.
|
||||
data.survivalFlyVL += result;
|
||||
data.clearAccounting();
|
||||
@ -352,10 +366,12 @@ public class SurvivalFly extends Check {
|
||||
vd.setParameter(ParameterName.LOCATION_FROM, String.format(Locale.US, "%.2f, %.2f, %.2f", from.getX(), from.getY(), from.getZ()));
|
||||
vd.setParameter(ParameterName.LOCATION_TO, String.format(Locale.US, "%.2f, %.2f, %.2f", to.getX(), to.getY(), to.getZ()));
|
||||
vd.setParameter(ParameterName.DISTANCE, String.format(Locale.US, "%.2f", to.getLocation().distance(from.getLocation())));
|
||||
vd.setParameter(ParameterName.TAGS, CheckUtils.join(tags, "+")); // Always set.
|
||||
}
|
||||
data.survivalFlyVLTime = now;
|
||||
if (executeActions(vd)){
|
||||
data.survivalFlyLastYDist = Double.MAX_VALUE;
|
||||
data.toWasReset = false;
|
||||
// Compose a new location based on coordinates of "newTo" and viewing direction of "event.getTo()" to
|
||||
// allow the player to look somewhere else despite getting pulled back by NoCheatPlus.
|
||||
return new Location(player.getWorld(), data.setBack.getX(), data.setBack.getY(), data.setBack.getZ(),
|
||||
@ -368,7 +384,7 @@ public class SurvivalFly extends Check {
|
||||
}
|
||||
|
||||
// Violation or not, apply reset conditions (cancel would have returned above).
|
||||
final boolean resetTo = toOnGround || to.isInLiquid() || to.isOnLadder()|| to.isInWeb();
|
||||
data.toWasReset = resetTo || data.noFallAssumeGround;
|
||||
if (resetTo){
|
||||
// The player has moved onto ground.
|
||||
data.setBack = to.getLocation();
|
||||
@ -385,4 +401,58 @@ public class SurvivalFly extends Check {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow accumulating some vls and silently set the player back.
|
||||
*
|
||||
* @param player
|
||||
* @param data
|
||||
* @param cc
|
||||
* @param to
|
||||
* @param now
|
||||
* @param vDistanceAboveLimit
|
||||
* @return
|
||||
*/
|
||||
private final Location hackCobweb(final Player player, final MovingData data, final PlayerLocation to,
|
||||
final long now, final double vDistanceAboveLimit)
|
||||
{
|
||||
if (now - data.survivalFlyCobwebTime > 3000) {
|
||||
data.survivalFlyCobwebTime = now;
|
||||
data.survivalFlyCobwebVL = vDistanceAboveLimit * 100D;
|
||||
} else data.survivalFlyCobwebVL += vDistanceAboveLimit * 100D;
|
||||
if (data.survivalFlyCobwebVL < 550) { // Totally random !
|
||||
// Silently set back.
|
||||
if (data.setBack == null) data.setBack = player.getLocation();
|
||||
data.survivalFlyJumpPhase = 0;
|
||||
data.setBack.setYaw(to.getYaw());
|
||||
data.setBack.setPitch(to.getPitch());
|
||||
data.survivalFlyLastYDist = Double.MAX_VALUE;
|
||||
return data.setBack;
|
||||
} else return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep track of values, demanding that with time the values decrease.<br>
|
||||
* The ActionFrequency objects have 3 buckets.
|
||||
* @param now
|
||||
* @param value
|
||||
* @param sum
|
||||
* @param count
|
||||
* @param tags
|
||||
* @param tag
|
||||
* @return
|
||||
*/
|
||||
private static final double doAccounting(final long now, final double value, final ActionFrequency sum, final ActionFrequency count, final ArrayList<String> tags, String tag)
|
||||
{
|
||||
sum.add(now, (float) value);
|
||||
count.add(now, 1f);
|
||||
if (count.getScore(2) > 0 && count.getScore(1) > 0) {
|
||||
final float sc0 = sum.getScore(1);
|
||||
final float sc1 = sum.getScore(2);
|
||||
if (sc0 < sc1 || value < 3.9 && sc0 == sc1) {
|
||||
tags.add(tag);
|
||||
return sc0 - sc1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public class RemovePlayerCommand extends NCPCommand {
|
||||
|
||||
if (DataManager.removeExecutionHistory(checkType, playerName)) histRemoved = true;
|
||||
|
||||
final boolean dataRemoved = CheckType.removeData(playerName, checkType) || DataManager.clearComponentData(checkType, playerName);
|
||||
final boolean dataRemoved = DataManager.removeData(playerName, checkType);
|
||||
|
||||
if (dataRemoved || histRemoved){
|
||||
String which;
|
||||
|
@ -1,7 +1,8 @@
|
||||
package fr.neatmonster.nocheatplus.components;
|
||||
|
||||
/**
|
||||
* Interface for component registration to allow cleanup for player data.
|
||||
* Interface for component registration to allow cleanup for player data.<br>
|
||||
* NOTE: For CheckType-specific data removal, IHaveCheckType should be implemented, otherwise this data might get ignored until plugin-disable.
|
||||
* @author mc_dev
|
||||
*
|
||||
*/
|
||||
|
@ -111,37 +111,34 @@ public class NCPExemptionManager {
|
||||
exemptPermanently(player.getEntityId(), checkType);
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be registered before all other listeners of NoCheatPlus.
|
||||
*
|
||||
* NOTE: For internal use only, DO NOT CALL FROM OUTSIDE.
|
||||
*
|
||||
* @return the listener
|
||||
*/
|
||||
public static Listener getListener() {
|
||||
return new Listener() {
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler(
|
||||
ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onPlayerJoin(final PlayerJoinEvent event) {
|
||||
NCPExemptionManager.registerPlayer(event.getPlayer());
|
||||
}
|
||||
/**
|
||||
* This should be registered before all other listeners of NoCheatPlus.
|
||||
*
|
||||
* NOTE: For internal use only, DO NOT CALL FROM OUTSIDE.
|
||||
*
|
||||
* @return the listener
|
||||
*/
|
||||
public static Listener getListener() {
|
||||
return new Listener() {
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerJoin(final PlayerJoinEvent event) {
|
||||
NCPExemptionManager.registerPlayer(event.getPlayer());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler(
|
||||
ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(final PlayerQuitEvent event) {
|
||||
NCPExemptionManager.tryToRemove(event.getPlayer());
|
||||
}
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(final PlayerQuitEvent event) {
|
||||
NCPExemptionManager.tryToRemove(event.getPlayer());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler(
|
||||
ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onPlayerKick(final PlayerKickEvent event) {
|
||||
NCPExemptionManager.tryToRemove(event.getPlayer());
|
||||
}
|
||||
};
|
||||
}
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerKick(final PlayerKickEvent event) {
|
||||
NCPExemptionManager.tryToRemove(event.getPlayer());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an entity is exempted from a check right now by entity id.
|
||||
|
@ -0,0 +1,67 @@
|
||||
package fr.neatmonster.nocheatplus.permissions;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
public class PermissionUtil {
|
||||
|
||||
public static SimpleCommandMap getCommandMap(){
|
||||
return (((CraftServer) Bukkit.getServer()).getCommandMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Return undo info.
|
||||
* @param permissionBase
|
||||
* @param ignoredCommands
|
||||
* @param ops
|
||||
*/
|
||||
public static void alterCommandPermissions(String permissionBase, Set<String> ignoredCommands, boolean invertIgnored, boolean ops){
|
||||
PluginManager pm = Bukkit.getPluginManager();
|
||||
Permission rootPerm = pm.getPermission(permissionBase);
|
||||
if (rootPerm == null){
|
||||
rootPerm = new Permission(permissionBase);
|
||||
pm.addPermission(rootPerm);
|
||||
}
|
||||
SimpleCommandMap map = getCommandMap();
|
||||
for (Command command : map.getCommands()){
|
||||
String lcLabel = command.getLabel().trim().toLowerCase();
|
||||
if (ignoredCommands != null){
|
||||
if (ignoredCommands.contains(lcLabel)){
|
||||
if (!invertIgnored) continue;
|
||||
}
|
||||
else if (invertIgnored) continue;
|
||||
}
|
||||
// Set the permission for the command.
|
||||
String cmdPermName = command.getPermission();
|
||||
boolean cmdHadPerm;
|
||||
if (cmdPermName == null){
|
||||
// Set a permission.
|
||||
cmdPermName = permissionBase + "." + lcLabel;
|
||||
command.setPermission(cmdPermName);
|
||||
cmdHadPerm = false;
|
||||
}
|
||||
else cmdHadPerm = true;
|
||||
// Set permission default behavior.
|
||||
Permission cmdPerm = pm.getPermission(cmdPermName);
|
||||
if (cmdPerm == null){
|
||||
if (!cmdHadPerm){
|
||||
cmdPerm = new Permission(cmdPermName);
|
||||
cmdPerm.addParent(rootPerm, true);
|
||||
cmdPerm.setDefault(ops ? PermissionDefault.OP : PermissionDefault.FALSE);
|
||||
pm.addPermission(cmdPerm);
|
||||
}
|
||||
}
|
||||
else{
|
||||
// Change default of the permission.
|
||||
cmdPerm.setDefault(ops ? PermissionDefault.OP : PermissionDefault.FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -40,6 +40,14 @@ import fr.neatmonster.nocheatplus.config.ConfigFile;
|
||||
import fr.neatmonster.nocheatplus.config.ConfigManager;
|
||||
import fr.neatmonster.nocheatplus.hooks.APIUtils;
|
||||
|
||||
/**
|
||||
* Central access point for a lot of functionality for managing data, especially removing data for cleanup.<br>
|
||||
* Originally intended as temporary or intermediate design, this might help reorganizing the API at some point.<br>
|
||||
* However i could not yet find a pleasing way for generic configuration access for a centralized data management (all in one),
|
||||
* so this might just be a workarounds class for coping with the current design, until somehow resolved in another way.
|
||||
* @author mc_dev
|
||||
*
|
||||
*/
|
||||
public class DataManager implements Listener, INotifyReload, INeedConfig, IComponentRegistry{
|
||||
|
||||
protected static DataManager instance = null;
|
||||
@ -65,15 +73,28 @@ public class DataManager implements Listener, INotifyReload, INeedConfig, ICompo
|
||||
*/
|
||||
protected final Map<CheckType, Map<String, ExecutionHistory>> executionHistories = new HashMap<CheckType, Map<String,ExecutionHistory>>();
|
||||
|
||||
/**
|
||||
* Duration in milliseconds for expiration of logged off players data.
|
||||
* Disabled with 0, in the config minutes are used as unit.
|
||||
*/
|
||||
protected long durExpireData = 0;
|
||||
|
||||
/** Data and execution history. */
|
||||
protected boolean deleteData = true;
|
||||
/** Violation history and execution history. */
|
||||
protected boolean deleteHistory = false;
|
||||
|
||||
/**
|
||||
* Sets the static instance reference.
|
||||
*/
|
||||
public DataManager(){
|
||||
instance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the logged out players for if any data can be removed.<br>
|
||||
* Currently only "dumb" full removal is performed. Later it is thinkable to remove "as much as reasonable".
|
||||
*/
|
||||
public void checkExpiration(){
|
||||
if (durExpireData <= 0) return;
|
||||
final long now = System.currentTimeMillis();
|
||||
@ -119,6 +140,10 @@ public class DataManager implements Listener, INotifyReload, INeedConfig, ICompo
|
||||
onLeave(event.getPlayer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Quit or kick.
|
||||
* @param player
|
||||
*/
|
||||
private final void onLeave(final Player player) {
|
||||
final long now = System.currentTimeMillis();
|
||||
lastLogout.put(player.getName(), now);
|
||||
@ -127,10 +152,13 @@ public class DataManager implements Listener, INotifyReload, INeedConfig, ICompo
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
// future
|
||||
// present.
|
||||
adjustSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch settings from the current default config.
|
||||
*/
|
||||
private void adjustSettings() {
|
||||
final ConfigFile config = ConfigManager.getConfigFile();
|
||||
durExpireData = config.getLong(ConfPaths.DATA_EXPIRATION_DURATION) * 60000L; // in minutes
|
||||
@ -138,6 +166,12 @@ public class DataManager implements Listener, INotifyReload, INeedConfig, ICompo
|
||||
deleteHistory = config.getBoolean(ConfPaths.DATA_EXPIRATION_HISTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by checks to register the history for external access.<br>
|
||||
* NOTE: This method is not really meant ot be used from outside NCP.
|
||||
* @param type
|
||||
* @param histories
|
||||
*/
|
||||
public static void registerExecutionHistory(CheckType type, Map<String, ExecutionHistory> histories) {
|
||||
instance.executionHistories.put(type, histories);
|
||||
}
|
||||
@ -154,6 +188,12 @@ public class DataManager implements Listener, INotifyReload, INeedConfig, ICompo
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the execution history for a player for the given check type.
|
||||
* @param type
|
||||
* @param playerName
|
||||
* @return
|
||||
*/
|
||||
public static boolean removeExecutionHistory(final CheckType type, final String playerName){
|
||||
boolean removed = false;
|
||||
// TODO: design ...
|
||||
@ -197,9 +237,36 @@ public class DataManager implements Listener, INotifyReload, INeedConfig, ICompo
|
||||
ViolationHistory.clear(checkType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the player data for a given player and a given check type. CheckType.ALL and null will be interpreted as removing all data.<br>
|
||||
* @param playerName Exact player name.
|
||||
* @param checkType Check type to remove data for, null is regarded as ALL.
|
||||
* @return If any data was present.
|
||||
*/
|
||||
public static boolean removeData(final String playerName, CheckType checkType) {
|
||||
if (checkType == null) checkType = CheckType.ALL;
|
||||
boolean had = false;
|
||||
|
||||
// Check extended registered components.
|
||||
if (clearComponentData(checkType, playerName)) had = true;
|
||||
|
||||
// Collect factories.
|
||||
final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
|
||||
for (CheckType otherType : APIUtils.getWithChildren(checkType)){
|
||||
final CheckDataFactory otherFactory = otherType.getDataFactory();
|
||||
if (otherFactory != null) factories.add(otherFactory);
|
||||
}
|
||||
// Remove data.
|
||||
for (final CheckDataFactory otherFactory : factories){
|
||||
if (otherFactory.removeData(playerName) != null) had = true;
|
||||
}
|
||||
|
||||
return had;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear player related data, only for registered components (not execution history, violation history, normal check data).<br>
|
||||
* That should at least go for chat engione data.
|
||||
* That should at least go for chat engine data.
|
||||
* @param CheckType
|
||||
* @param PlayerName
|
||||
* @return If something was removed.
|
||||
@ -249,7 +316,7 @@ public class DataManager implements Listener, INotifyReload, INeedConfig, ICompo
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup method.
|
||||
* Cleanup method, removes all data and config, but does not call ConfigManager.cleanup.
|
||||
*/
|
||||
public void onDisable() {
|
||||
clearData(CheckType.ALL);
|
||||
|
@ -52,7 +52,7 @@ public class Permissions {
|
||||
|
||||
|
||||
// Permissions for the individual checks.
|
||||
private static final String CHECKS = NOCHEATPLUS + ".checks";
|
||||
public static final String CHECKS = NOCHEATPLUS + ".checks";
|
||||
|
||||
/*
|
||||
* 888 88b, 888 888 888 88b, 888
|
||||
@ -61,7 +61,7 @@ public class Permissions {
|
||||
* 888 88b, 888 Y888 888P Y888 , 888 b 888 88b, 888 888 , ,ee 888 888 b
|
||||
* 888 88P' 888 "88 88" "88,e8' 888 8b 888 88P' 888 "YeeP" "88 888 888 8b
|
||||
*/
|
||||
private static final String BLOCKBREAK = CHECKS + ".blockbreak";
|
||||
public static final String BLOCKBREAK = CHECKS + ".blockbreak";
|
||||
public static final String BLOCKBREAK_BREAK = BLOCKBREAK + ".break";
|
||||
public static final String BLOCKBREAK_BREAK_LIQUID = BLOCKBREAK_BREAK + ".liquid";
|
||||
public static final String BLOCKBREAK_DIRECTION = BLOCKBREAK + ".direction";
|
||||
@ -78,7 +78,7 @@ public class Permissions {
|
||||
* 888 88b, 888 Y888 888P Y888 , 888 b 888 888 888 888 888 , 888 ,ee 888 Y888 , 888
|
||||
* 888 88P' 888 "88 88" "88,e8' 888 8b 888 888 888 888 "YeeP" 888 "88 888 "88,e8' 888
|
||||
*/
|
||||
private static final String BLOCKINTERACT = CHECKS + ".blockinteract";
|
||||
public static final String BLOCKINTERACT = CHECKS + ".blockinteract";
|
||||
public static final String BLOCKINTERACT_DIRECTION = BLOCKINTERACT + ".direction";
|
||||
public static final String BLOCKINTERACT_REACH = BLOCKINTERACT + ".reach";
|
||||
|
||||
@ -89,9 +89,9 @@ public class Permissions {
|
||||
* 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"
|
||||
*/
|
||||
private static final String BLOCKPLACE = CHECKS + ".blockplace";
|
||||
public static final String BLOCKPLACE = CHECKS + ".blockplace";
|
||||
public static final String BLOCKPLACE_AGAINST = BLOCKPLACE + ".against";
|
||||
public static final String BLOCKPLACE_AGAINST_AIR = BLOCKPLACE_AGAINST + ".air";
|
||||
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_DIRECTION = BLOCKPLACE + ".direction";
|
||||
public static final String BLOCKPLACE_FASTPLACE = BLOCKPLACE + ".fastplace";
|
||||
@ -106,19 +106,19 @@ public class Permissions {
|
||||
* Y888 ,d 888 888 ,ee 888 888
|
||||
* "88,d88 888 888 "88 888 888
|
||||
*/
|
||||
private static final String CHAT = CHECKS + ".chat";
|
||||
public static final String CHAT = CHECKS + ".chat";
|
||||
public static final String CHAT_CAPTCHA = CHAT + ".captcha";
|
||||
public static final String CHAT_COLOR = CHAT + ".color";
|
||||
public static final String CHAT_COMMANDS = CHAT + ".commands";
|
||||
public static final String CHAT_TEXT = CHAT + ".text";
|
||||
public static final String CHAT_TEXT = CHAT + ".text";
|
||||
public static final String CHAT_LOGINS = CHAT + ".logins";
|
||||
public static final String CHAT_RELOG = CHAT + ".relog";
|
||||
|
||||
/*
|
||||
* Combined !
|
||||
*/
|
||||
private static final String COMBINED = CHECKS + ".combined";
|
||||
public static final String COMBINED_IMPROBABLE = COMBINED + ".improbable";
|
||||
public static final String COMBINED = CHECKS + ".combined";
|
||||
public static final String COMBINED_IMPROBABLE = COMBINED + ".improbable";
|
||||
|
||||
/*
|
||||
* 888'Y88 ,e, 888 d8
|
||||
@ -129,7 +129,7 @@ public class Permissions {
|
||||
* , 88P
|
||||
* "8",P"
|
||||
*/
|
||||
private static final String FIGHT = CHECKS + ".fight";
|
||||
public static final String FIGHT = CHECKS + ".fight";
|
||||
public static final String FIGHT_ANGLE = FIGHT + ".angle";
|
||||
public static final String FIGHT_CRITICAL = FIGHT + ".critical";
|
||||
public static final String FIGHT_DIRECTION = FIGHT + ".direction";
|
||||
@ -149,7 +149,7 @@ public class Permissions {
|
||||
* 888
|
||||
* 888
|
||||
*/
|
||||
private static final String INVENTORY = CHECKS + ".inventory";
|
||||
public static final String INVENTORY = CHECKS + ".inventory";
|
||||
public static final String INVENTORY_DROP = INVENTORY + ".drop";
|
||||
public static final String INVENTORY_FASTCLICK = INVENTORY + ".fastclick";
|
||||
public static final String INVENTORY_INSTANTBOW = INVENTORY + ".instantbow";
|
||||
@ -165,7 +165,7 @@ public class Permissions {
|
||||
* , 88P
|
||||
* "8",P"
|
||||
*/
|
||||
private static final String MOVING = CHECKS + ".moving";
|
||||
public static final String MOVING = CHECKS + ".moving";
|
||||
public static final String MOVING_BOATSANYWHERE = MOVING + ".boatsanywhere";
|
||||
public static final String MOVING_CREATIVEFLY = MOVING + ".creativefly";
|
||||
public static final String MOVING_MOREPACKETS = MOVING + ".morepackets";
|
||||
|
@ -107,8 +107,14 @@ public class ActionFrequency {
|
||||
cf *= factor;
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get reference time.
|
||||
* @return
|
||||
*/
|
||||
public final long lastAccess(){
|
||||
return time;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
package fr.neatmonster.nocheatplus.utilities;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.server.IBlockAccess;
|
||||
import net.minecraft.server.Material;
|
||||
import net.minecraft.server.TileEntity;
|
||||
@ -11,70 +8,25 @@ import net.minecraft.server.Vec3DPool;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.CoordMap;
|
||||
|
||||
/**
|
||||
* Access to type-ids and data using caching techniques.
|
||||
* @author mc_dev
|
||||
*
|
||||
*/
|
||||
public class BlockCache implements IBlockAccess{
|
||||
/**
|
||||
* TODO: Make a map for faster queries (without object creation).
|
||||
* TODO: Not sure the prime numbers are too big for normal use.
|
||||
* @author mc_dev
|
||||
*
|
||||
*/
|
||||
private static class Pos3D{
|
||||
private static final int p1 = 73856093;
|
||||
private static final int p2 = 19349663;
|
||||
private static final int p3 = 83492791;
|
||||
// Cube coordinates:
|
||||
public final int x;
|
||||
public final int y;
|
||||
public final int z;
|
||||
public final int hash;
|
||||
/**
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param size
|
||||
*/
|
||||
public Pos3D (final int x, final int y, final int z){
|
||||
// Cube related coordinates:
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
// Hash
|
||||
hash = getHash(this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(final Object obj) {
|
||||
if (obj instanceof Pos3D){
|
||||
final Pos3D other = (Pos3D) obj;
|
||||
return other.x == x && other.y == y && other.z == z;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static final int getHash(final int x, final int y, final int z) {
|
||||
return p1 * x ^ p2 * y ^ p3 * z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For getting ids.
|
||||
*/
|
||||
private IBlockAccess access = null;
|
||||
|
||||
/** Cached type-ids. */
|
||||
private final Map<Pos3D, Integer> idMap = new HashMap<Pos3D, Integer>();
|
||||
/** Cahced data values. */
|
||||
private final Map<Pos3D, Integer> dataMap = new HashMap<Pos3D, Integer>();
|
||||
private final CoordMap<Integer> idMap = new CoordMap<Integer>();
|
||||
|
||||
/** Cached data values. */
|
||||
private final CoordMap<Integer> dataMap = new CoordMap<Integer>();
|
||||
|
||||
// TODO: maybe make very fast access arrays for the ray tracing checks.
|
||||
// private int[] id = null;
|
||||
@ -117,23 +69,21 @@ public class BlockCache implements IBlockAccess{
|
||||
}
|
||||
|
||||
|
||||
public int getTypeId(final int x, final int y, final int z){
|
||||
final Pos3D pos = new Pos3D(x, y, z);
|
||||
final Integer pId = idMap.get(pos);
|
||||
if (pId != null) return pId;
|
||||
final Integer nId = access.getTypeId(x, y, z);
|
||||
idMap.put(pos, nId);
|
||||
return nId;
|
||||
}
|
||||
public int getTypeId(final int x, final int y, final int z) {
|
||||
final Integer pId = idMap.get(x, y, z);
|
||||
if (pId != null) return pId;
|
||||
final Integer nId = access.getTypeId(x, y, z);
|
||||
idMap.put(x, y, z, nId);
|
||||
return nId;
|
||||
}
|
||||
|
||||
public int getData(final int x, final int y, final int z){
|
||||
final Pos3D pos = new Pos3D(x, y, z);
|
||||
final Integer pData = dataMap.get(pos);
|
||||
if (pData != null) return pData;
|
||||
final Integer nData = access.getData(x, y, z);
|
||||
dataMap.put(pos, nData);
|
||||
return nData;
|
||||
}
|
||||
public int getData(final int x, final int y, final int z) {
|
||||
final Integer pData = dataMap.get(x, y, z);
|
||||
if (pData != null) return pData;
|
||||
final Integer nData = access.getData(x, y, z);
|
||||
dataMap.put(x, y, z, nData);
|
||||
return nData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not Optimized.
|
||||
|
@ -261,6 +261,8 @@ public class BlockProperties {
|
||||
public static final int F_HEIGHT150 = 0x40;
|
||||
/** The player can stand on these, sneaking or not. */
|
||||
public static final int F_GROUND = 0x80;
|
||||
/** 1 block height. */
|
||||
public static final int F_HEIGHT100 = 0x100;
|
||||
|
||||
static{
|
||||
init();
|
||||
@ -328,7 +330,7 @@ public class BlockProperties {
|
||||
for (final Material mat : new Material[] {Material.NETHER_BRICK_STAIRS,
|
||||
Material.COBBLESTONE_STAIRS, Material.SMOOTH_STAIRS, Material.BRICK_STAIRS, Material.SANDSTONE_STAIRS,
|
||||
Material.WOOD_STAIRS, Material.SPRUCE_WOOD_STAIRS, Material.BIRCH_WOOD_STAIRS, Material.JUNGLE_WOOD_STAIRS}){
|
||||
blockFlags[mat.getId()] |= F_STAIRS;
|
||||
blockFlags[mat.getId()] |= F_STAIRS | F_HEIGHT100;
|
||||
}
|
||||
// WATER.
|
||||
for (final Material mat : new Material[]{
|
||||
@ -356,6 +358,7 @@ public class BlockProperties {
|
||||
}){
|
||||
blockFlags[mat.getId()] |= F_GROUND;
|
||||
}
|
||||
blockFlags[Material.ENDER_PORTAL_FRAME.getId()] |= F_HEIGHT100;
|
||||
// Ignore for passable.
|
||||
for (final Material mat : new Material[]{
|
||||
Material.WOOD_PLATE, Material.STONE_PLATE,
|
||||
@ -502,6 +505,7 @@ public class BlockProperties {
|
||||
blocks[Material.SKULL.getId()] = new BlockProps(noTool, 8.5f, secToMs(1.45)); // TODO
|
||||
blockFlags[Material.SKULL.getId()] |= F_GROUND;
|
||||
blocks[Material.ANVIL.getId()] = new BlockProps(woodPickaxe, 5f); // TODO
|
||||
blockFlags[Material.FLOWER_POT.getId()] |= F_GROUND;
|
||||
|
||||
// Indestructible.
|
||||
for (Material mat : new Material[]{
|
||||
@ -978,6 +982,17 @@ public class BlockProperties {
|
||||
return isPassable(access, loc.getX(), loc.getY(), loc.getZ(), access.getTypeId(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to allow using an already fetched or prepared IBlockAccess.
|
||||
* @param access
|
||||
* @param loc
|
||||
* @return
|
||||
*/
|
||||
public static final boolean isPassable(final IBlockAccess access, final Location loc)
|
||||
{
|
||||
return isPassable(access, loc.getX(), loc.getY(), loc.getZ(), access.getTypeId(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
|
||||
/**
|
||||
* API access to read extra properties from files.
|
||||
* @param config
|
||||
@ -1093,7 +1108,7 @@ public class BlockProperties {
|
||||
final double bmaxY;
|
||||
// if ((blockFlags[id] & F_HEIGHT150) != 0) block.maxY = 1.5;
|
||||
if ((blockFlags[id] & F_HEIGHT150) != 0) bmaxY = 1.5;
|
||||
else if (isStairs(id)) bmaxY = 1.0;
|
||||
else if ((blockFlags[id] & F_HEIGHT100) != 0) bmaxY = 1.0;
|
||||
else bmaxY = block.y(); // maxY
|
||||
// if (minX > block.maxX + x || maxX < block.minX + x) return false;
|
||||
// else if (minY > block.maxY + y || maxY < block.minY + y) return false;
|
||||
|
@ -8,6 +8,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
@ -18,194 +19,195 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
/**
|
||||
* The Class CheckUtils.
|
||||
* Random auxiliary gear, some might have general quality.
|
||||
*/
|
||||
public class CheckUtils {
|
||||
|
||||
/** The file logger. */
|
||||
public static Logger fileLogger = null;
|
||||
/** The file logger. */
|
||||
public static Logger fileLogger = null;
|
||||
|
||||
/** Decimal format for "#.###" */
|
||||
public static final DecimalFormat fdec3 = new DecimalFormat();
|
||||
/** Decimal format for "#.###" */
|
||||
public static final DecimalFormat fdec3 = new DecimalFormat();
|
||||
|
||||
static{
|
||||
DecimalFormatSymbols sym = fdec3.getDecimalFormatSymbols();
|
||||
sym.setDecimalSeparator('.');
|
||||
fdec3.setDecimalFormatSymbols(sym);
|
||||
fdec3.setMaximumFractionDigits(3);
|
||||
fdec3.setMinimumIntegerDigits(1);
|
||||
}
|
||||
static {
|
||||
DecimalFormatSymbols sym = fdec3.getDecimalFormatSymbols();
|
||||
sym.setDecimalSeparator('.');
|
||||
fdec3.setDecimalFormatSymbols(sym);
|
||||
fdec3.setMaximumFractionDigits(3);
|
||||
fdec3.setMinimumIntegerDigits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a player looks at a target of a specific size, with a specific precision value (roughly).
|
||||
*
|
||||
* @param player
|
||||
* the player
|
||||
* @param targetX
|
||||
* the target x
|
||||
* @param targetY
|
||||
* the target y
|
||||
* @param targetZ
|
||||
* the target z
|
||||
* @param targetWidth
|
||||
* the target width
|
||||
* @param targetHeight
|
||||
* the target height
|
||||
* @param precision
|
||||
* the precision
|
||||
* @return the double
|
||||
*/
|
||||
public static double directionCheck(final Player player, final double targetX, final double targetY,
|
||||
final double targetZ, final double targetWidth, final double targetHeight, final double precision) {
|
||||
/**
|
||||
* Check if a player looks at a target of a specific size, with a specific
|
||||
* precision value (roughly).
|
||||
*
|
||||
* @param player
|
||||
* the player
|
||||
* @param targetX
|
||||
* the target x
|
||||
* @param targetY
|
||||
* the target y
|
||||
* @param targetZ
|
||||
* the target z
|
||||
* @param targetWidth
|
||||
* the target width
|
||||
* @param targetHeight
|
||||
* the target height
|
||||
* @param precision
|
||||
* the precision
|
||||
* @return the double
|
||||
*/
|
||||
public static double directionCheck(final Player player, final double targetX, final double targetY, final double targetZ, final double targetWidth, final double targetHeight, final double precision)
|
||||
{
|
||||
|
||||
// Get the eye location of the player.
|
||||
final Location eyes = player.getEyeLocation();
|
||||
// Get the eye location of the player.
|
||||
final Location eyes = player.getEyeLocation();
|
||||
|
||||
final double factor = Math.sqrt(Math.pow(eyes.getX() - targetX, 2) + Math.pow(eyes.getY() - targetY, 2)
|
||||
+ Math.pow(eyes.getZ() - targetZ, 2));
|
||||
final double factor = Math.sqrt(Math.pow(eyes.getX() - targetX, 2) + Math.pow(eyes.getY() - targetY, 2) + Math.pow(eyes.getZ() - targetZ, 2));
|
||||
|
||||
// Get the view direction of the player.
|
||||
final Vector direction = eyes.getDirection();
|
||||
// Get the view direction of the player.
|
||||
final Vector direction = eyes.getDirection();
|
||||
|
||||
final double x = targetX - eyes.getX();
|
||||
final double y = targetY - eyes.getY();
|
||||
final double z = targetZ - eyes.getZ();
|
||||
final double x = targetX - eyes.getX();
|
||||
final double y = targetY - eyes.getY();
|
||||
final double z = targetZ - eyes.getZ();
|
||||
|
||||
final double xPrediction = factor * direction.getX();
|
||||
final double yPrediction = factor * direction.getY();
|
||||
final double zPrediction = factor * direction.getZ();
|
||||
final double xPrediction = factor * direction.getX();
|
||||
final double yPrediction = factor * direction.getY();
|
||||
final double zPrediction = factor * direction.getZ();
|
||||
|
||||
double off = 0.0D;
|
||||
double off = 0.0D;
|
||||
|
||||
off += Math.max(Math.abs(x - xPrediction) - (targetWidth / 2 + precision), 0.0D);
|
||||
off += Math.max(Math.abs(z - zPrediction) - (targetWidth / 2 + precision), 0.0D);
|
||||
off += Math.max(Math.abs(y - yPrediction) - (targetHeight / 2 + precision), 0.0D);
|
||||
off += Math.max(Math.abs(x - xPrediction) - (targetWidth / 2 + precision), 0.0D);
|
||||
off += Math.max(Math.abs(z - zPrediction) - (targetWidth / 2 + precision), 0.0D);
|
||||
off += Math.max(Math.abs(y - yPrediction) - (targetHeight / 2 + precision), 0.0D);
|
||||
|
||||
if (off > 1)
|
||||
off = Math.sqrt(off);
|
||||
if (off > 1) off = Math.sqrt(off);
|
||||
|
||||
return off;
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the distance between two location, because for Bukkit distance is the distance squared and
|
||||
* distanceSquared is the distance non-squared.
|
||||
*
|
||||
* @param location1
|
||||
* the location1
|
||||
* @param location2
|
||||
* the location2
|
||||
* @return the double
|
||||
*/
|
||||
public static double distance(final Location location1, final Location location2) {
|
||||
return Math.sqrt(Math.pow(location2.getX() - location1.getX(), 2)
|
||||
+ Math.pow(location2.getY() - location1.getY(), 2) + Math.pow(location2.getZ() - location1.getZ(), 2));
|
||||
}
|
||||
/**
|
||||
* Calculate the distance between two location, because for Bukkit distance
|
||||
* is the distance squared and distanceSquared is the distance non-squared.
|
||||
*
|
||||
* @param location1
|
||||
* the location1
|
||||
* @param location2
|
||||
* the location2
|
||||
* @return the double
|
||||
*/
|
||||
public static double distance(final Location location1, final Location location2)
|
||||
{
|
||||
return Math.sqrt(Math.pow(location2.getX() - location1.getX(), 2) + Math.pow(location2.getY() - location1.getY(), 2) + Math.pow(location2.getZ() - location1.getZ(), 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the two Strings are similar based on the given threshold.
|
||||
*
|
||||
* @param s
|
||||
* the first String, must not be null
|
||||
* @param t
|
||||
* the second String, must not be null
|
||||
* @param threshold
|
||||
* the minimum value of the correlation coefficient
|
||||
* @return result true if the two Strings are similar, false otherwise
|
||||
*/
|
||||
public static boolean isSimilar(final String s, final String t, final float threshold) {
|
||||
return 1.0f - (float) levenshteinDistance(s, t) / Math.max(1.0, Math.max(s.length(), t.length())) > threshold;
|
||||
}
|
||||
/**
|
||||
* Return if the two Strings are similar based on the given threshold.
|
||||
*
|
||||
* @param s
|
||||
* the first String, must not be null
|
||||
* @param t
|
||||
* the second String, must not be null
|
||||
* @param threshold
|
||||
* the minimum value of the correlation coefficient
|
||||
* @return result true if the two Strings are similar, false otherwise
|
||||
*/
|
||||
public static boolean isSimilar(final String s, final String t, final float threshold)
|
||||
{
|
||||
return 1.0f - (float) levenshteinDistance(s, t) / Math.max(1.0, Math.max(s.length(), t.length())) > threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the Levenshtein distance between two Strings.
|
||||
*
|
||||
* This is the number of changes needed to change one String into another, where each change is a single character
|
||||
* modification (deletion, insertion or substitution).
|
||||
*
|
||||
* @param s
|
||||
* the first String, must not be null
|
||||
* @param t
|
||||
* the second String, must not be null
|
||||
* @return result distance
|
||||
*/
|
||||
private static int levenshteinDistance(CharSequence s, CharSequence t) {
|
||||
if (s == null || t == null)
|
||||
throw new IllegalArgumentException("Strings must not be null");
|
||||
/**
|
||||
* Find the Levenshtein distance between two Strings.
|
||||
*
|
||||
* This is the number of changes needed to change one String into another,
|
||||
* where each change is a single character modification (deletion, insertion or substitution).
|
||||
*
|
||||
* @param s
|
||||
* the first String, must not be null
|
||||
* @param t
|
||||
* the second String, must not be null
|
||||
* @return result distance
|
||||
*/
|
||||
private static int levenshteinDistance(CharSequence s, CharSequence t) {
|
||||
if (s == null || t == null) throw new IllegalArgumentException("Strings must not be null");
|
||||
|
||||
int n = s.length();
|
||||
int m = t.length();
|
||||
int n = s.length();
|
||||
int m = t.length();
|
||||
|
||||
if (n == 0)
|
||||
return m;
|
||||
else if (m == 0)
|
||||
return n;
|
||||
if (n == 0) return m;
|
||||
else if (m == 0) return n;
|
||||
|
||||
if (n > m) {
|
||||
final CharSequence tmp = s;
|
||||
s = t;
|
||||
t = tmp;
|
||||
n = m;
|
||||
m = t.length();
|
||||
}
|
||||
if (n > m) {
|
||||
final CharSequence tmp = s;
|
||||
s = t;
|
||||
t = tmp;
|
||||
n = m;
|
||||
m = t.length();
|
||||
}
|
||||
|
||||
int p[] = new int[n + 1];
|
||||
int d[] = new int[n + 1];
|
||||
int _d[];
|
||||
int p[] = new int[n + 1];
|
||||
int d[] = new int[n + 1];
|
||||
int _d[];
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
char t_j;
|
||||
char t_j;
|
||||
|
||||
int cost;
|
||||
int cost;
|
||||
|
||||
for (i = 0; i <= n; i++)
|
||||
p[i] = i;
|
||||
for (i = 0; i <= n; i++)
|
||||
p[i] = i;
|
||||
|
||||
for (j = 1; j <= m; j++) {
|
||||
t_j = t.charAt(j - 1);
|
||||
d[0] = j;
|
||||
for (j = 1; j <= m; j++) {
|
||||
t_j = t.charAt(j - 1);
|
||||
d[0] = j;
|
||||
|
||||
for (i = 1; i <= n; i++) {
|
||||
cost = s.charAt(i - 1) == t_j ? 0 : 1;
|
||||
d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
|
||||
}
|
||||
for (i = 1; i <= n; i++) {
|
||||
cost = s.charAt(i - 1) == t_j ? 0 : 1;
|
||||
d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
|
||||
}
|
||||
|
||||
_d = p;
|
||||
p = d;
|
||||
d = _d;
|
||||
}
|
||||
_d = p;
|
||||
p = d;
|
||||
d = _d;
|
||||
}
|
||||
|
||||
return p[n];
|
||||
}
|
||||
return p[n];
|
||||
}
|
||||
|
||||
/**
|
||||
* Join parts with link.
|
||||
* @param input
|
||||
* @param link
|
||||
* @return
|
||||
*/
|
||||
public static <O extends Object> String join(final Collection<O> input, final String link){
|
||||
final StringBuilder builder = new StringBuilder(Math.max(300, input.size() * 10));
|
||||
boolean first = true;
|
||||
for (final Object obj : input){
|
||||
if (!first) builder.append(link);
|
||||
builder.append(obj.toString());
|
||||
first = false;
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
/**
|
||||
* Join parts with link.
|
||||
*
|
||||
* @param input
|
||||
* @param link
|
||||
* @return
|
||||
*/
|
||||
public static <O extends Object> String join(final Collection<O> input, final String link)
|
||||
{
|
||||
final StringBuilder builder = new StringBuilder(Math.max(300, input.size() * 10));
|
||||
boolean first = true;
|
||||
for (final Object obj : input) {
|
||||
if (!first) builder.append(link);
|
||||
builder.append(obj.toString());
|
||||
first = false;
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method.
|
||||
* @param parts
|
||||
* @param link
|
||||
* @return
|
||||
*/
|
||||
public static <O extends Object> boolean scheduleOutputJoined(final List<O> parts, String link){
|
||||
return scheduleOutput(join(parts, link));
|
||||
}
|
||||
/**
|
||||
* Convenience method.
|
||||
*
|
||||
* @param parts
|
||||
* @param link
|
||||
* @return
|
||||
*/
|
||||
public static <O extends Object> boolean scheduleOutputJoined(final List<O> parts, String link)
|
||||
{
|
||||
return scheduleOutput(join(parts, link));
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a message to be output by the bukkit logger.
|
||||
@ -307,15 +309,15 @@ public class CheckUtils {
|
||||
/**
|
||||
* Get the height from getLocation().getY() to head / above head.<br>
|
||||
* NOTE: Currently this is pretty much useless, it returns 1.0 most of the time.
|
||||
*
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
public static double getHeight(final Entity entity) {
|
||||
final net.minecraft.server.Entity mcEntity = ((CraftEntity)entity).getHandle();
|
||||
final double entityHeight = mcEntity.height;
|
||||
if (entity instanceof LivingEntity){
|
||||
return Math.max(((LivingEntity) entity).getEyeHeight(), entityHeight);
|
||||
}
|
||||
else return mcEntity.height;
|
||||
}
|
||||
public static double getHeight(final Entity entity) {
|
||||
final net.minecraft.server.Entity mcEntity = ((CraftEntity) entity).getHandle();
|
||||
final double entityHeight = mcEntity.height;
|
||||
if (entity instanceof LivingEntity) {
|
||||
return Math.max(((LivingEntity) entity).getEyeHeight(), entityHeight);
|
||||
} else return mcEntity.height;
|
||||
}
|
||||
}
|
||||
|
@ -334,10 +334,13 @@ public class PlayerLocation {
|
||||
onGround = BlockProperties.isOnGround(getBlockAccess(), minX, minY - yOnGround, minZ, maxX, maxY + 0.25, maxZ);
|
||||
if (!onGround){
|
||||
// TODO: Probably check other ids too before doing this ?
|
||||
final double d0 = 0.25D;
|
||||
final double d0 = 1D; //0.25D;
|
||||
// for (org.bukkit.entity.Entity test : entity.getBukkitEntity().getNearbyEntities(1, 1, 1)){
|
||||
// System.out.println("*" + test.getType());
|
||||
// }
|
||||
final AxisAlignedBB box = useBox.b(minX - d0, minY - getyOnGround() - d0, minZ - d0, maxX + d0, maxY + d0, maxZ + d0);
|
||||
@SuppressWarnings("rawtypes")
|
||||
List list = worldServer.getEntities(entity, box);
|
||||
final List list = worldServer.getEntities(entity, box);
|
||||
@SuppressWarnings("rawtypes")
|
||||
Iterator iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
|
162
src/fr/neatmonster/nocheatplus/utilities/ds/CoordMap.java
Normal file
162
src/fr/neatmonster/nocheatplus/utilities/ds/CoordMap.java
Normal file
@ -0,0 +1,162 @@
|
||||
package fr.neatmonster.nocheatplus.utilities.ds;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Map int coordinates to values (just for fun). Intended for Minecraft coordinates, probably not for too high values.<br>
|
||||
* This implementation is not thread safe, though changing values and get/contains should work if the map stays unchanged.
|
||||
* @author mc_dev
|
||||
*
|
||||
* @param <V>
|
||||
*/
|
||||
public class CoordMap<V> {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static final class Entry<V>{
|
||||
protected final int x;
|
||||
protected final int y;
|
||||
protected final int z;
|
||||
protected V value;
|
||||
protected final int hash;
|
||||
public Entry(final int x, final int y, final int z, final V value, final int hash){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.value = value;
|
||||
this.hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
// Core data.
|
||||
private final float loadFactor;
|
||||
private List<Entry<V>>[] entries;
|
||||
/** Current size. */
|
||||
private int size = 0;
|
||||
|
||||
public CoordMap(){
|
||||
this(10, 0.75f);
|
||||
}
|
||||
|
||||
public CoordMap(final int initialCapacity){
|
||||
this(initialCapacity, 0.75f);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param initialCapacity Initial internal array size. <br>
|
||||
* TODO: change to expected number of elements (len = cap/load).
|
||||
* @param loadFactor
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public CoordMap(final int initialCapacity, float loadFactor){
|
||||
this.loadFactor = loadFactor;
|
||||
entries = new List[initialCapacity];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the map contains a value for the given coordinates.<br>
|
||||
* NOTE: Delegates to get, use get for fastest checks.
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @return
|
||||
*/
|
||||
public final boolean contains(final int x, final int y, final int z){
|
||||
return get(x,y,z) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value if there is a mapping for the given coordinates.
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @return
|
||||
*/
|
||||
public final V get(final int x, final int y, final int z){
|
||||
final int hash = getHash(x, y, z);
|
||||
final int slot = Math.abs(hash) % entries.length;
|
||||
final List<Entry<V>> bucket = entries[slot];
|
||||
if (bucket == null) return null;;
|
||||
for (final Entry<V> entry : bucket){
|
||||
if (hash == entry.hash && x == entry.x && z == entry.z && y == entry.y) return entry.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add value with the coordinates + hash from the last contains call.
|
||||
* @param value
|
||||
* @return If a value was replaced.
|
||||
*/
|
||||
public final boolean put(final int x, final int y, final int z, final V value){
|
||||
final int hash = getHash(x, y, z);
|
||||
final int absHash = Math.abs(hash);
|
||||
int slot = absHash % entries.length;
|
||||
List<Entry<V>> bucket = entries[slot];
|
||||
if (bucket != null){
|
||||
for (final Entry<V> entry : bucket){
|
||||
if (hash == entry.hash && x == entry.x && y == entry.z && z == entry.y){
|
||||
entry.value = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (size + 1 > entries.length * loadFactor){
|
||||
resize(size + 1);
|
||||
slot = absHash % entries.length;
|
||||
bucket = entries[slot];
|
||||
}
|
||||
if (bucket == null) {
|
||||
// TODO: use array list ?
|
||||
bucket = new LinkedList<Entry<V>>();
|
||||
entries[slot] = bucket;
|
||||
}
|
||||
entries[slot] = bucket;
|
||||
bucket.add(new Entry<V>(x, y, z, value, hash));
|
||||
size ++;
|
||||
return false;
|
||||
}
|
||||
|
||||
private final void resize(final int size) {
|
||||
// TODO: other capacity?
|
||||
final int newCapacity = (int) ((size + 4) / loadFactor);
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Entry<V>>[] newEntries = new List[newCapacity];
|
||||
for (int oldSlot = 0; oldSlot < entries.length; oldSlot++){
|
||||
final List<Entry<V>> oldBucket = entries[oldSlot];
|
||||
if (oldBucket != null){
|
||||
for (final Entry<V> entry : oldBucket){
|
||||
final int newSlot = Math.abs(entry.hash) % newCapacity;
|
||||
List<Entry<V>> newBucket = newEntries[oldSlot];
|
||||
if (newBucket == null){
|
||||
newBucket = new LinkedList<Entry<V>>();
|
||||
newEntries[newSlot] = newBucket;
|
||||
}
|
||||
newBucket.add(entry);
|
||||
}
|
||||
oldBucket.clear();
|
||||
}
|
||||
entries[oldSlot] = null;
|
||||
}
|
||||
entries = newEntries;
|
||||
}
|
||||
|
||||
public final int size(){
|
||||
return size;
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
size = 0;
|
||||
Arrays.fill(entries, null);
|
||||
// TODO: resize ?
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user