diff --git a/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/ds/count/ActionFrequency.java b/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/ds/count/ActionFrequency.java index 43519409..95614113 100644 --- a/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/ds/count/ActionFrequency.java +++ b/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/ds/count/ActionFrequency.java @@ -276,6 +276,38 @@ public class ActionFrequency { return buffer.toString(); } + /** + * Update and then reduce all given ActionFrequency instances by the given + * amount, capped at a maximum of 0 for the resulting first bucket score. + * + * @param amount + * The amount to subtract. + * @param freqs + */ + public static void reduce(final long time, final float amount, final ActionFrequency... freqs) { + for (int i = 0; i < freqs.length; i++) { + final ActionFrequency freq = freqs[i]; + freq.update(time); + freq.setBucket(0, Math.max(0f, freq.bucketScore(0) - amount)); + } + } + + /** + * Update and then reduce all given ActionFrequency instances by the given + * amount, without capping the result. + * + * @param amount + * The amount to subtract. + * @param freqs + */ + public static void subtract(final long time, final float amount, final ActionFrequency... freqs) { + for (int i = 0; i < freqs.length; i++) { + final ActionFrequency freq = freqs[i]; + freq.update(time); + freq.setBucket(0, freq.bucketScore(0) - amount); + } + } + /** * Deserialize from a string. * @param line diff --git a/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/ds/map/HashMapLOW.java b/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/ds/map/HashMapLOW.java index a1115da4..6132b3b5 100644 --- a/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/ds/map/HashMapLOW.java +++ b/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/ds/map/HashMapLOW.java @@ -321,7 +321,7 @@ public class HashMapLOW { private LHMEntry currentEntry = null; private K lastReturnedKey = null; - public LHMIterator(HashMapLOW map, LHMBucket[] buckets) { + LHMIterator(HashMapLOW map, LHMBucket[] buckets) { this.map = map; this.buckets = buckets; // (Lazily advance.) @@ -412,6 +412,21 @@ public class HashMapLOW { } + static class LHMIterable implements Iterable> { + + private final Iterator> iterator; + + LHMIterable(Iterator> iterator) { + this.iterator = iterator; + } + + @Override + public Iterator> iterator() { + return iterator; + } + + } + /////////////////////// // Instance members @@ -697,6 +712,16 @@ public class HashMapLOW { return size == 0 ? new LHMIterator(null, null) : new LHMIterator(this, buckets); } + /** + * Get an Iterable containing the same iterator, as is returned by + * iterator(). See: {@link #iterator()} + * + * @return + */ + public Iterable> iterable() { + return new LHMIterable(iterator()); + } + /** * Get all keys as a LinkedHashSet fit for iteration. The returned set is a * new instance, so changes don't affect the original HashMapLOW instance. diff --git a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/FastConsume.java b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/FastConsume.java index 5d1563d6..fdea495f 100644 --- a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/FastConsume.java +++ b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/FastConsume.java @@ -27,12 +27,13 @@ import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; import fr.neatmonster.nocheatplus.compat.BridgeHealth; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; import fr.neatmonster.nocheatplus.components.registry.feature.INotifyReload; -import fr.neatmonster.nocheatplus.config.ConfPaths; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.logging.StaticLog; import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.InventoryUtil; import fr.neatmonster.nocheatplus.utilities.TickTask; @@ -62,7 +63,9 @@ public class FastConsume extends Check implements Listener, INotifyReload { private void disableInstantEat() { // TODO: Do this kind of thing via registries later on. - ConfigManager.setForAllConfigs(ConfPaths.INVENTORY_INSTANTEAT_CHECK, false); + //ConfigManager.setForAllConfigs(ConfPaths.INVENTORY_INSTANTEAT_CHECK, false); + NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().overrideCheckActivation( + this.type, AlmostBoolean.NO, OverrideType.PERMANENT, true); StaticLog.logInfo("Inventory checks: FastConsume is available, disabled InstantEat."); } @@ -75,18 +78,20 @@ public class FastConsume extends Check implements Listener, INotifyReload { counters.addPrimaryThread(idCancelDead, 1); return; } - if (!isEnabled(player)) { + final IPlayerData pData = DataManager.getPlayerData(player); + if (!pData.isCheckActive(type, player)) { return; } - final InventoryData data = InventoryData.getData(player); + final InventoryData data = pData.getGenericInstance(InventoryData.class); final long time = System.currentTimeMillis(); - if (check(player, event.getItem(), time, data)){ + if (check(player, event.getItem(), time, data, pData)){ event.setCancelled(true); DataManager.getPlayerData(player).requestUpdateInventory(); } } - private boolean check(final Player player, final ItemStack stack, final long time, final InventoryData data){ + private boolean check(final Player player, final ItemStack stack, + final long time, final InventoryData data, final IPlayerData pData){ // Uses the instant-eat data for convenience. // Consistency checks... if (stack == null){ // || stack.getType() != data.instantEatFood){ @@ -100,7 +105,7 @@ public class FastConsume extends Check implements Listener, INotifyReload { return false; } // Check exceptions. - final InventoryConfig cc = InventoryConfig.getConfig(player); + final InventoryConfig cc = pData.getGenericInstance(InventoryConfig.class); final Material mat = stack == null ? null : stack.getType(); if (mat != null){ if (cc.fastConsumeWhitelist){ @@ -144,8 +149,9 @@ public class FastConsume extends Check implements Listener, INotifyReload { final ItemStack actualStack = InventoryUtil.getFirstConsumableItemInHand(player); data.instantEatFood = actualStack == null ? null : actualStack.getType(); // TODO: Allows some abuse: 1. try instantly eat (cancelled) 2. consume item directly when needed. - } else { - if (data.debug) { + } + else { + if (pData.isDebugActive(type)) { debug(player, "PlayerItemConsumeEvent, reset fastconsume: " + data.instantEatFood); } data.instantEatFood = null; diff --git a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Gutenberg.java b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Gutenberg.java index 8cac0b85..da11dec0 100644 --- a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Gutenberg.java +++ b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Gutenberg.java @@ -23,6 +23,8 @@ import org.bukkit.inventory.meta.BookMeta; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; public class Gutenberg extends Check implements Listener { @@ -42,7 +44,8 @@ public class Gutenberg extends Check implements Listener { if (!isEnabled(player)) { return; } - final InventoryConfig cc = InventoryConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final InventoryConfig cc = pData.getGenericInstance(InventoryConfig.class); final BookMeta newMeta = event.getNewBookMeta(); final int pages = newMeta.getPageCount(); if (pages <= 50) { diff --git a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/HotFixFallingBlockPortalEnter.java b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/HotFixFallingBlockPortalEnter.java index 1a776f5f..2c24ceaf 100644 --- a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/HotFixFallingBlockPortalEnter.java +++ b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/HotFixFallingBlockPortalEnter.java @@ -33,6 +33,7 @@ import fr.neatmonster.nocheatplus.utilities.location.LocUtil; import fr.neatmonster.nocheatplus.utilities.map.BlockCache; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; import fr.neatmonster.nocheatplus.utilities.map.WrapBlockCache; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Hot fix for 1.9 and 1.10 (possibly later?): falling block duplication via end @@ -87,7 +88,8 @@ public class HotFixFallingBlockPortalEnter implements Listener { if (mat != null) { final Location loc = entity.getLocation(useLoc); final World world = loc.getWorld(); - if (InventoryConfig.getConfig(world).hotFixFallingBlockEndPortalActive) { + final IWorldData worldData = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().getWorldData(world); + if (worldData.getGenericInstance(InventoryConfig.class).hotFixFallingBlockEndPortalActive) { final BlockCache blockCache = wrapBlockCache.getBlockCache(); blockCache.setAccess(world); final boolean nearbyPortal = BlockProperties.collidesId(blockCache, loc.getX() - 2.0, loc.getY() - 2.0, loc.getZ() - 2.0, loc.getX() + 3.0, loc.getY() + 3.0, loc.getZ() + 3.0, Material.ENDER_PORTAL); diff --git a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/BaseAdapter.java b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/BaseAdapter.java index d8481cb9..264fd6dd 100644 --- a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/BaseAdapter.java +++ b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/BaseAdapter.java @@ -24,8 +24,6 @@ import com.comphenix.protocol.events.PacketAdapter; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.checks.net.NetConfigCache; -import fr.neatmonster.nocheatplus.checks.net.NetDataFactory; import fr.neatmonster.nocheatplus.components.debug.IDebugPlayer; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.CheckUtils; @@ -38,8 +36,6 @@ import fr.neatmonster.nocheatplus.utilities.CheckUtils; public abstract class BaseAdapter extends PacketAdapter implements IDebugPlayer { protected final Counters counters = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class); - protected final NetConfigCache configFactory = (NetConfigCache) CheckType.NET.getConfigFactory(); - protected final NetDataFactory dataFactory = (NetDataFactory) CheckType.NET.getDataFactory(); /** Override for specific output on the debug method. */ protected CheckType checkType = CheckType.NET; diff --git a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/CatchAllAdapter.java b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/CatchAllAdapter.java index 15e782de..0d479430 100644 --- a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/CatchAllAdapter.java +++ b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/CatchAllAdapter.java @@ -27,10 +27,9 @@ import com.comphenix.protocol.events.PacketEvent; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.net.NetConfig; import fr.neatmonster.nocheatplus.checks.net.NetData; -import fr.neatmonster.nocheatplus.checks.net.NetStatic; import fr.neatmonster.nocheatplus.checks.net.PacketFrequency; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * Pre-1.9. @@ -74,22 +73,12 @@ public class CatchAllAdapter extends BaseAdapter { // TODO: Is this a problem, as the server has the player so it could break a block)? return; } - final NetConfig cc; - try { - cc = NetStatic.getWorldConfig(player, configFactory, dataFactory); - } - catch (UnsupportedOperationException e) { - // Legacy +-. - // TODO: Get from PlayerData, once HashMapLOW is used. - return; - } - if (cc.packetFrequencyActive) { - final PlayerData pData = DataManager.getPlayerData(player); - if (packetFrequency.isEnabled(player, cc, pData)) { - final NetData data = dataFactory.getData(player); - if (packetFrequency.check(player, data, cc)) { - event.setCancelled(true); - } + final IPlayerData pData = DataManager.getPlayerData(player); + if (packetFrequency.isEnabled(player, pData)) { + final NetConfig cc = pData.getGenericInstance(NetConfig.class); + final NetData data = pData.getGenericInstance(NetData.class); + if (packetFrequency.check(player, data, cc)) { + event.setCancelled(true); } } } diff --git a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/DebugAdapter.java b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/DebugAdapter.java index 474c69fe..28fb6dc9 100644 --- a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/DebugAdapter.java +++ b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/DebugAdapter.java @@ -21,6 +21,9 @@ import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.ListenerPriority; import com.comphenix.protocol.events.PacketEvent; +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.DataManager; + public class DebugAdapter extends BaseAdapter { public DebugAdapter(Plugin plugin) { @@ -33,7 +36,7 @@ public class DebugAdapter extends BaseAdapter { @Override public void onPacketReceiving(PacketEvent event) { final Player player = event.getPlayer(); - if (dataFactory.getData(player).debug) { + if (DataManager.getPlayerData(player).isDebugActive(CheckType.NET)) { debug(player, "packet: " + event.getPacketType()); } } diff --git a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/KeepAliveAdapter.java b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/KeepAliveAdapter.java index ee963bb4..c7041c3f 100644 --- a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/KeepAliveAdapter.java +++ b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/KeepAliveAdapter.java @@ -24,13 +24,12 @@ import com.comphenix.protocol.events.ListenerPriority; import com.comphenix.protocol.events.PacketEvent; import fr.neatmonster.nocheatplus.NCPAPIProvider; +import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.net.KeepAliveFrequency; import fr.neatmonster.nocheatplus.checks.net.NetConfig; import fr.neatmonster.nocheatplus.checks.net.NetData; -import fr.neatmonster.nocheatplus.config.ConfPaths; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * Limit keep alive packet frequency, set lastKeepAliveTime (even if disabled, @@ -46,10 +45,12 @@ public class KeepAliveAdapter extends BaseAdapter { public KeepAliveAdapter(Plugin plugin) { super(plugin, ListenerPriority.LOW, PacketType.Play.Client.KEEP_ALIVE); - + this.checkType = CheckType.NET_KEEPALIVEFREQUENCY; // Add feature tags for checks. - if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_KEEPALIVEFREQUENCY_ACTIVE)) { - NCPAPIProvider.getNoCheatPlusAPI().addFeatureTags("checks", Arrays.asList(KeepAliveFrequency.class.getSimpleName())); + if (NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().isActiveAnywhere( + CheckType.NET_KEEPALIVEFREQUENCY)) { + NCPAPIProvider.getNoCheatPlusAPI().addFeatureTags( + "checks", Arrays.asList(KeepAliveFrequency.class.getSimpleName())); } NCPAPIProvider.getNoCheatPlusAPI().addComponent(frequencyCheck); } @@ -64,16 +65,17 @@ public class KeepAliveAdapter extends BaseAdapter { return; } // Always update last received time. - final PlayerData pData = DataManager.getPlayerData(player); - final NetData data = dataFactory.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final NetData data = pData.getGenericInstance(NetData.class); data.lastKeepAliveTime = time; - final NetConfig cc = configFactory.getConfig(player); + final NetConfig cc = pData.getGenericInstance(NetConfig.class); // Run check(s). // TODO: Match vs. outgoing keep alive requests. // TODO: Better modeling of actual packet sequences (flying vs. keep alive vs. request/ping). // TODO: Better integration with god-mode check / trigger reset ndt. - if (cc.keepAliveFrequencyActive && frequencyCheck.check(player, time, data, cc, pData)) { + if (frequencyCheck.isEnabled(player, pData) + && frequencyCheck.check(player, time, data, cc, pData)) { event.setCancelled(true); } } diff --git a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/MovingFlying.java b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/MovingFlying.java index 14ff01e2..2bd73098 100644 --- a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/MovingFlying.java +++ b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/MovingFlying.java @@ -33,6 +33,7 @@ import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.reflect.StructureModifier; import fr.neatmonster.nocheatplus.NCPAPIProvider; +import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.net.FlyingFrequency; import fr.neatmonster.nocheatplus.checks.net.NetConfig; import fr.neatmonster.nocheatplus.checks.net.NetData; @@ -40,16 +41,16 @@ import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying; import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying.PACKET_CONTENT; import fr.neatmonster.nocheatplus.checks.net.model.TeleportQueue.AckReference; import fr.neatmonster.nocheatplus.compat.AlmostBoolean; -import fr.neatmonster.nocheatplus.config.ConfPaths; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.logging.StaticLog; import fr.neatmonster.nocheatplus.logging.Streams; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.time.monotonic.Monotonic; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.StringUtil; +import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; import fr.neatmonster.nocheatplus.utilities.location.LocUtil; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Run checks related to moving (pos/look/flying). Skip packets that shouldn't @@ -110,10 +111,12 @@ public class MovingFlying extends BaseAdapter { public MovingFlying(Plugin plugin) { // PacketPlayInFlying[3, legacy: 10] super(plugin, ListenerPriority.LOW, initPacketTypes()); - + // Keep the CheckType NET for now. // Add feature tags for checks. - if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_FLYINGFREQUENCY_ACTIVE)) { - NCPAPIProvider.getNoCheatPlusAPI().addFeatureTags("checks", Arrays.asList(FlyingFrequency.class.getSimpleName())); + if (NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().isActiveAnywhere( + CheckType.NET_FLYINGFREQUENCY)) { + NCPAPIProvider.getNoCheatPlusAPI().addFeatureTags( + "checks", Arrays.asList(FlyingFrequency.class.getSimpleName())); } NCPAPIProvider.getNoCheatPlusAPI().addComponent(flyingFrequency); } @@ -155,12 +158,13 @@ public class MovingFlying extends BaseAdapter { return; } final Player player = event.getPlayer(); - final NetData data = dataFactory.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final NetData data = pData.getGenericInstance(NetData.class); final AlmostBoolean matched = data.teleportQueue.processAck(teleportId); if (matched.decideOptimistically()) { - CheckUtils.subtract(System.currentTimeMillis(), 1, data.flyingFrequencyAll); + ActionFrequency.subtract(System.currentTimeMillis(), 1, data.flyingFrequencyAll); } - if (data.debug) { + if (pData.isDebugActive(this.checkType)) { // TODO: FlyingFrequency / NET_MOVING? + check others who depend debug(player, "Confirm teleport packet" + (matched.decideOptimistically() ? (" (matched=" + matched + ")") : "") + ": " + teleportId); } } @@ -191,14 +195,17 @@ public class MovingFlying extends BaseAdapter { return; } - final NetConfig cc = configFactory.getConfig(player.getWorld()); + final IPlayerData pData = DataManager.getPlayerData(player); // Always update last received time. - final NetData data = dataFactory.getData(player); + final NetData data = pData.getGenericInstance(NetData.class); data.lastKeepAliveTime = time; // Update without much of a contract. // TODO: Leniency options too (packet order inversion). -> current: flyingQueue is fetched. - if (!cc.flyingFrequencyActive) { + final IWorldData worldData = pData.getCurrentWorldDataSafe(); + if (!worldData.isCheckActive(CheckType.NET_FLYINGFREQUENCY)) { return; } + + final NetConfig cc = pData.getGenericInstance(NetConfig.class); boolean cancel = false; // Interpret the packet content. @@ -211,14 +218,14 @@ public class MovingFlying extends BaseAdapter { if (isInvalidContent(packetData)) { // TODO: extra actions: log and kick (cancel state is not evaluated) event.setCancelled(true); - if (data.debug) { + if (pData.isDebugActive(this.checkType)) { debug(player, "Incoming packet, cancel due to malicious content: " + packetData.toString()); } return; } switch(data.teleportQueue.processAck(packetData)) { case WAITING: { - if (data.debug) { + if (pData.isDebugActive(this.checkType)) { debug(player, "Incoming packet, still waiting for ACK on outgoing position."); } if (confirmTeleportType != null && cc.supersededFlyingCancelWaiting) { @@ -250,7 +257,7 @@ public class MovingFlying extends BaseAdapter { case ACK: { // Skip processing ACK packets, no cancel. skipFlyingFrequency = true; - if (data.debug) { + if (pData.isDebugActive(this.checkType)) { debug(player, "Incoming packet, interpret as ACK for outgoing position."); } } @@ -267,8 +274,8 @@ public class MovingFlying extends BaseAdapter { // Actual packet frequency check. // TODO: Consider using the NetStatic check. - final PlayerData pData = DataManager.getPlayerData(player); if (!cancel && !skipFlyingFrequency + && !pData.hasBypass(CheckType.NET_FLYINGFREQUENCY, player) && flyingFrequency.check(player, packetData, time, data, cc, pData)) { cancel = true; } @@ -285,7 +292,7 @@ public class MovingFlying extends BaseAdapter { if (cancel) { event.setCancelled(true); } - if (data.debug) { + if (pData.isDebugActive(this.checkType)) { debug(player, (packetData == null ? "(Incompatible data)" : packetData.toString()) + (event.isCancelled() ? " CANCEL" : "")); } } diff --git a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/OutgoingPosition.java b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/OutgoingPosition.java index 90001d64..1e6c49d4 100644 --- a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/OutgoingPosition.java +++ b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/OutgoingPosition.java @@ -24,9 +24,12 @@ import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.reflect.StructureModifier; import fr.neatmonster.nocheatplus.NCPAPIProvider; +import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.net.NetData; import fr.neatmonster.nocheatplus.checks.net.model.CountableLocation; import fr.neatmonster.nocheatplus.logging.Streams; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; public class OutgoingPosition extends BaseAdapter { @@ -37,7 +40,7 @@ public class OutgoingPosition extends BaseAdapter { public static final int indexPitch = 1; private final Integer ID_OUTGOING_POSITION_UNTRACKED = counters.registerKey("packet.outgoing_position.untracked"); - + private boolean hasTeleportId = true; public OutgoingPosition(Plugin plugin) { @@ -55,12 +58,17 @@ public class OutgoingPosition extends BaseAdapter { } final long time = System.currentTimeMillis(); final Player player = event.getPlayer(); - if (configFactory.getConfig(player).flyingFrequencyActive) { - interpretPacket(player, event.getPacket(), time, dataFactory.getData(player)); + final IPlayerData pData = DataManager.getPlayerData(player); + // TODO: In future multiple checks might use this (!) + if (pData.isCheckActive(CheckType.NET_FLYINGFREQUENCY, player)) { + interpretPacket(player, event.getPacket(), time, + pData.getGenericInstance(NetData.class), + pData.isDebugActive(CheckType.NET_FLYINGFREQUENCY)); } } - private void interpretPacket(final Player player, final PacketContainer packet, final long time, final NetData data) { + private void interpretPacket(final Player player, final PacketContainer packet, + final long time, final NetData data, final boolean debug) { final StructureModifier doubles = packet.getDoubles(); final StructureModifier floats = packet.getFloat(); @@ -78,7 +86,7 @@ public class OutgoingPosition extends BaseAdapter { final float yaw = floats.read(indexYaw); final float pitch = floats.read(indexPitch); Integer teleportId = Integer.MIN_VALUE; - + if (hasTeleportId) { try { final StructureModifier integers = packet.getIntegers(); @@ -88,7 +96,7 @@ public class OutgoingPosition extends BaseAdapter { if (teleportId == null) { teleportId = Integer.MIN_VALUE; } - if (teleportId != Integer.MIN_VALUE && data.debug) { + if (teleportId != Integer.MIN_VALUE && debug) { debug(player, "Outgoing confirm teleport id: " + teleportId); } } @@ -108,12 +116,12 @@ public class OutgoingPosition extends BaseAdapter { // Add counter for untracked (by Bukkit API) outgoing teleport. // TODO: There may be other cases which are indicated by Bukkit API events. counters.add(ID_OUTGOING_POSITION_UNTRACKED, 1); - if (data.debug) { + if (debug) { debug(player, "Untracked outgoing position: " + x + ", " + y + ", " + z + " (yaw=" + yaw + ", pitch=" + pitch + ")."); } } else { - if (data.debug) { + if (debug) { debug(player, "Expect ACK on outgoing position: " + packetData); } } diff --git a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/ProtocolLibComponent.java b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/ProtocolLibComponent.java index 9571022f..6ababb02 100644 --- a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/ProtocolLibComponent.java +++ b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/ProtocolLibComponent.java @@ -37,10 +37,7 @@ import com.comphenix.protocol.events.PacketAdapter; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.checks.net.NetConfig; -import fr.neatmonster.nocheatplus.checks.net.NetConfigCache; import fr.neatmonster.nocheatplus.checks.net.NetData; -import fr.neatmonster.nocheatplus.checks.net.NetDataFactory; import fr.neatmonster.nocheatplus.compat.versions.ServerVersion; import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI; import fr.neatmonster.nocheatplus.components.registry.feature.IDisableListener; @@ -50,8 +47,11 @@ import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.logging.StaticLog; import fr.neatmonster.nocheatplus.logging.Streams; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.StringUtil; +import fr.neatmonster.nocheatplus.worlds.IWorldDataManager; /** * Quick and dirty ProtocolLib setup. @@ -89,15 +89,17 @@ public class ProtocolLibComponent implements IDisableListener, INotifyReload, Jo private final List registeredPacketAdapters = new LinkedList(); - protected final NetConfigCache configFactory = (NetConfigCache) CheckType.NET.getConfigFactory(); - protected final NetDataFactory dataFactory = (NetDataFactory) CheckType.NET.getDataFactory(); - public ProtocolLibComponent(Plugin plugin) { register(plugin); + /* + * TODO: Register listeners iff any check is enabled - unregister from + * EventRegistry with unregister. + */ } private void register(Plugin plugin) { StaticLog.logInfo("Adding packet level hooks for ProtocolLib (MC " + ProtocolLibrary.getProtocolManager().getMinecraftVersion().getVersion() + ")..."); + final IWorldDataManager worldMan = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); //Special purpose. if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET + ConfPaths.SUB_DEBUG) || ConfigManager.isTrueForAnyConfig(ConfPaths.CHECKS_DEBUG) ) { // (Debug logging. Only activates if debug is set for checks or checks.net, not on the fly.) @@ -108,25 +110,29 @@ public class ProtocolLibComponent implements IDisableListener, INotifyReload, Jo // Don't use this listener. NCPAPIProvider.getNoCheatPlusAPI().getLogManager().info(Streams.STATUS, "Disable EntityUseAdapter due to incompatibilities. Use fight.speed instead of net.attackfrequency."); } - else if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_ATTACKFREQUENCY_ACTIVE)) { + else if (worldMan.isActiveAnywhere(CheckType.NET_ATTACKFREQUENCY)) { // (Also sets lastKeepAliveTime, if enabled.) register("fr.neatmonster.nocheatplus.checks.net.protocollib.UseEntityAdapter", plugin); } - if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_FLYINGFREQUENCY_ACTIVE)) { + if (worldMan.isActiveAnywhere(CheckType.NET_FLYINGFREQUENCY)) { // (Also sets lastKeepAliveTime, if enabled.) register("fr.neatmonster.nocheatplus.checks.net.protocollib.MovingFlying", plugin); register("fr.neatmonster.nocheatplus.checks.net.protocollib.OutgoingPosition", plugin); } - if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_KEEPALIVEFREQUENCY_ACTIVE) || ConfigManager.isTrueForAnyConfig(ConfPaths.FIGHT_GODMODE_CHECK)) { + if (worldMan.isActiveAnywhere(CheckType.NET_KEEPALIVEFREQUENCY) + || worldMan.isActiveAnywhere(CheckType.FIGHT_GODMODE)) { // (Set lastKeepAlive if this or fight.godmode is enabled.) register("fr.neatmonster.nocheatplus.checks.net.protocollib.KeepAliveAdapter", plugin); } - if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_SOUNDDISTANCE_ACTIVE)) { + if (worldMan.isActiveAnywhere(CheckType.NET_SOUNDDISTANCE)) { register("fr.neatmonster.nocheatplus.checks.net.protocollib.SoundDistance", plugin); } - if (ConfigManager.isAlmostTrueForAnyConfig(ConfPaths.NET_PACKETFREQUENCY_ACTIVE, ServerVersion.compareMinecraftVersion("1.9") < 0, false)) { - register("fr.neatmonster.nocheatplus.checks.net.protocollib.CatchAllAdapter", plugin); + if (ServerVersion.compareMinecraftVersion("1.9") < 0) { + if (worldMan.isActiveAnywhere(CheckType.NET_PACKETFREQUENCY)) { + register("fr.neatmonster.nocheatplus.checks.net.protocollib.CatchAllAdapter", plugin); + } } + if (!registeredPacketAdapters.isEmpty()) { List names = new ArrayList(registeredPacketAdapters.size()); for (PacketAdapter adapter : registeredPacketAdapters) { @@ -178,8 +184,8 @@ public class ProtocolLibComponent implements IDisableListener, INotifyReload, Jo @Override public void onReload() { unregister(); - CheckType.NET.getDataFactory().removeAllData(); // Currently needed for FlyingFrequency. - register(Bukkit.getPluginManager().getPlugin("NoCheatPlus")); // Store instead ? + NCPAPIProvider.getNoCheatPlusAPI().getPlayerDataManager().removeGenericInstance(NetData.class); // Currently needed for FlyingFrequency. + register(Bukkit.getPluginManager().getPlugin("NoCheatPlus")); // TODO: static plugin getter? } private void unregister() { @@ -200,14 +206,14 @@ public class ProtocolLibComponent implements IDisableListener, INotifyReload, Jo @Override public void playerJoins(final Player player) { if (!registeredPacketAdapters.isEmpty()) { - dataFactory.getData(player).onJoin(player); + DataManager.getGenericInstance(player, NetData.class).onJoin(player); } } @Override public void playerLeaves(final Player player) { if (!registeredPacketAdapters.isEmpty()) { - dataFactory.getData(player).onLeave(player); + DataManager.getGenericInstance(player, NetData.class).onLeave(player); } } @@ -215,7 +221,7 @@ public class ProtocolLibComponent implements IDisableListener, INotifyReload, Jo public void onPlayerRespawn(final PlayerRespawnEvent event) { if (!registeredPacketAdapters.isEmpty()) { final Player player = event.getPlayer(); - final NetData data = dataFactory.getData(player); + final NetData data = DataManager.getGenericInstance(player, NetData.class); data.onJoin(player); final Location loc = event.getRespawnLocation(); data.teleportQueue.onTeleportEvent(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); @@ -232,9 +238,9 @@ public class ProtocolLibComponent implements IDisableListener, INotifyReload, Jo return; } final Player player = event.getPlayer(); - final NetConfig cc = configFactory.getConfig(player); - final NetData data = dataFactory.getData(player); - if (cc.flyingFrequencyActive) { + final IPlayerData pData = DataManager.getPlayerData(player); + final NetData data = pData.getGenericInstance(NetData.class); + if (pData.isCheckActive(CheckType.NET_FLYINGFREQUENCY, player)) { // Register expected location for comparison with outgoing packets. data.teleportQueue.onTeleportEvent(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); } diff --git a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/SoundDistance.java b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/SoundDistance.java index 977b7ca8..cf683ce5 100644 --- a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/SoundDistance.java +++ b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/SoundDistance.java @@ -33,8 +33,9 @@ import com.comphenix.protocol.reflect.StructureModifier; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.net.NetConfig; -import fr.neatmonster.nocheatplus.checks.net.NetConfigCache; import fr.neatmonster.nocheatplus.compat.versions.ServerVersion; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.location.TrigUtil; public class SoundDistance extends BaseAdapter { @@ -92,14 +93,12 @@ public class SoundDistance extends BaseAdapter { )); private final Integer idSoundEffectCancel = counters.registerKey("packet.sound.cancel"); - private final NetConfigCache configs; private final Location useLoc = new Location(null, 0, 0, 0); /** Legacy check behavior. */ private final boolean pre1_9; public SoundDistance(Plugin plugin) { super(plugin, ListenerPriority.LOW, PacketType.Play.Server.NAMED_SOUND_EFFECT); - this.configs = (NetConfigCache) CheckType.NET.getConfigFactory(); // TODO: DataManager.getConfig(NetConfigCache.class); this.checkType = CheckType.NET_SOUNDDISTANCE; pre1_9 = ServerVersion.compareMinecraftVersion("1.9") < 0; inflateEffectNames(); @@ -151,8 +150,8 @@ public class SoundDistance extends BaseAdapter { } final Player player = event.getPlayer(); - final NetConfig cc = configs.getConfig(player.getWorld()); - if (!cc.soundDistanceActive) { + final IPlayerData pData = DataManager.getPlayerData(player); + if (!pData.isCheckActive(CheckType.NET_SOUNDDISTANCE, player)) { return; } @@ -163,6 +162,7 @@ public class SoundDistance extends BaseAdapter { // if (data.debug) { // debug(player, "SoundDistance(" + soundName + "): " + StringUtil.fdec1.format(Math.sqrt(dSq))); // } + final NetConfig cc = pData.getGenericInstance(NetConfig.class); if (dSq > cc.soundDistanceSq) { event.setCancelled(true); counters.add(idSoundEffectCancel, 1); diff --git a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/UseEntityAdapter.java b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/UseEntityAdapter.java index c50b1148..935aaf29 100644 --- a/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/UseEntityAdapter.java +++ b/NCPCompatProtocolLib/src/main/java/fr/neatmonster/nocheatplus/checks/net/protocollib/UseEntityAdapter.java @@ -27,13 +27,12 @@ import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction; import fr.neatmonster.nocheatplus.NCPAPIProvider; +import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.net.AttackFrequency; import fr.neatmonster.nocheatplus.checks.net.NetConfig; import fr.neatmonster.nocheatplus.checks.net.NetData; -import fr.neatmonster.nocheatplus.config.ConfPaths; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.ReflectionUtil; public class UseEntityAdapter extends BaseAdapter { @@ -100,10 +99,12 @@ public class UseEntityAdapter extends BaseAdapter { public UseEntityAdapter(Plugin plugin) { super(plugin, PacketType.Play.Client.USE_ENTITY); - + this.checkType = CheckType.NET_ATTACKFREQUENCY; // Add feature tags for checks. - if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_ATTACKFREQUENCY_ACTIVE)) { - NCPAPIProvider.getNoCheatPlusAPI().addFeatureTags("checks", Arrays.asList(AttackFrequency.class.getSimpleName())); + if (NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().isActiveAnywhere( + CheckType.NET_ATTACKFREQUENCY)) { + NCPAPIProvider.getNoCheatPlusAPI().addFeatureTags( + "checks", Arrays.asList(AttackFrequency.class.getSimpleName())); } attackFrequency = new AttackFrequency(); @@ -129,14 +130,14 @@ public class UseEntityAdapter extends BaseAdapter { // TODO: Warn once? return; } - final NetConfig cc = configFactory.getConfig(player); - final NetData data = dataFactory.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final NetData data = pData.getGenericInstance(NetData.class); // Always set last received time. data.lastKeepAliveTime = time; // Quick return, if no checks are active. - if (!cc.attackFrequencyActive) { + if (!pData.isCheckActive(CheckType.NET_ATTACKFREQUENCY, player)) { return; } @@ -174,8 +175,9 @@ public class UseEntityAdapter extends BaseAdapter { // AttackFrequency if (isAttack) { - final PlayerData pData = DataManager.getPlayerData(player); - if (attackFrequency.isEnabled(player, cc, pData) && attackFrequency.check(player, time, data, cc)) { + final NetConfig cc = pData.getGenericInstance(NetConfig.class); + if (attackFrequency.isEnabled(player, pData) + && attackFrequency.check(player, time, data, cc, pData)) { cancel = true; } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/Check.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/Check.java index abaf3da6..167fc2aa 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/Check.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/Check.java @@ -23,16 +23,16 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.actions.ActionList; import fr.neatmonster.nocheatplus.actions.types.penalty.IPenaltyList; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; import fr.neatmonster.nocheatplus.compat.MCAccess; import fr.neatmonster.nocheatplus.components.debug.IDebugPlayer; import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle; import fr.neatmonster.nocheatplus.hooks.NCPHookManager; import fr.neatmonster.nocheatplus.players.DataManager; import fr.neatmonster.nocheatplus.players.ExecutionHistory; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.TickTask; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * The parent class of all checks. Don't let this implement Listener without @@ -71,6 +71,7 @@ import fr.neatmonster.nocheatplus.utilities.TickTask; * actual check. * */ +// TODO: javadocs redo (above) public abstract class Check implements IDebugPlayer { // TODO: Do these get cleaned up ? @@ -102,6 +103,7 @@ public abstract class Check implements IDebugPlayer { * @param type * the type */ + @SuppressWarnings("deprecation") public Check(final CheckType type) { this.type = type; mcAccess = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstanceHandle(MCAccess.class); @@ -185,51 +187,38 @@ public abstract class Check implements IDebugPlayer { } /** - * Checks both configuration flags and if the player is exempted from this - * check (hasBypass). Intended for higher efficiency with multiple calls. + * Full activation check (configuration, exemption, permission). * * @param player * @param data - * @param cc + * @param worldData * @return */ - public boolean isEnabled(final Player player, final ICheckConfig cc, final PlayerData pData) { - return cc.isEnabled(type) && !CheckUtils.hasBypass(type, player, pData); + public boolean isEnabled(final Player player, final IPlayerData pData, + final IWorldData worldData) { + return pData.isCheckActive(type, player, worldData); } /** - * Checks both configuration flags and if the player is exempted from this - * check (hasBypass). Intended for higher efficiency with multiple calls. + * Full activation check (configuration, exemption, permission). * * @param player - * @param cc + * @param data * @return */ - public boolean isEnabled(final Player player, final ICheckConfig cc) { - return cc.isEnabled(type) && !CheckUtils.hasBypass(type, player, DataManager.getPlayerData(player)); + public boolean isEnabled(final Player player, final IPlayerData pData) { + return pData.isCheckActive(type, player); } /** - * Checks both configuration flags and if the player is exempted from this - * check (hasBypass). + * Full activation check (configuration, exemption, permission). * * @param player * the player * @return true, if the check is enabled */ public boolean isEnabled(final Player player) { - return type.isEnabled(player) && !CheckUtils.hasBypass(type, player, DataManager.getPlayerData(player)); - } - - /** - * Check if the player is exempted by permissions or otherwise.
- * - * - * @param player - * @return - */ - public boolean hasBypass(final Player player) { - return CheckUtils.hasBypass(type, player, DataManager.getPlayerData(player)); + return isEnabled(player, DataManager.getPlayerData(player)); } @Override diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/CheckType.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/CheckType.java index ad6d9b07..e4e276d3 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/CheckType.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/CheckType.java @@ -14,28 +14,7 @@ */ package fr.neatmonster.nocheatplus.checks; -import org.bukkit.entity.Player; - -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.blockbreak.BlockBreakConfig; -import fr.neatmonster.nocheatplus.checks.blockbreak.BlockBreakData; -import fr.neatmonster.nocheatplus.checks.blockinteract.BlockInteractConfig; -import fr.neatmonster.nocheatplus.checks.blockinteract.BlockInteractData; -import fr.neatmonster.nocheatplus.checks.blockplace.BlockPlaceConfig; -import fr.neatmonster.nocheatplus.checks.blockplace.BlockPlaceData; -import fr.neatmonster.nocheatplus.checks.chat.ChatConfig; -import fr.neatmonster.nocheatplus.checks.chat.ChatData; -import fr.neatmonster.nocheatplus.checks.combined.CombinedConfig; -import fr.neatmonster.nocheatplus.checks.combined.CombinedData; -import fr.neatmonster.nocheatplus.checks.fight.FightConfig; -import fr.neatmonster.nocheatplus.checks.fight.FightData; -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.checks.net.NetConfigCache; -import fr.neatmonster.nocheatplus.checks.net.NetDataFactory; +import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; @@ -46,86 +25,88 @@ import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; public enum CheckType { ALL(Permissions.CHECKS), - BLOCKBREAK(CheckType.ALL, BlockBreakConfig.factory, BlockBreakData.factory, Permissions.BLOCKBREAK), - /** This will allow breaking all special blocks, currently only liquid. Later there might be more sub-types. */ - BLOCKBREAK_BREAK(BLOCKBREAK, Permissions.BLOCKBREAK_BREAK), - BLOCKBREAK_DIRECTION(BLOCKBREAK, Permissions.BLOCKBREAK_DIRECTION), - BLOCKBREAK_FASTBREAK(BLOCKBREAK, Permissions.BLOCKBREAK_FASTBREAK), - BLOCKBREAK_FREQUENCY(BLOCKBREAK, Permissions.BLOCKBREAK_FREQUENCY), - BLOCKBREAK_NOSWING(BLOCKBREAK, Permissions.BLOCKBREAK_NOSWING), - BLOCKBREAK_REACH(BLOCKBREAK, Permissions.BLOCKBREAK_REACH), - BLOCKBREAK_WRONGBLOCK(BLOCKBREAK, Permissions.BLOCKBREAK_WRONGBLOCK), + BLOCKBREAK(CheckTypeType.GROUP, CheckType.ALL, Permissions.BLOCKBREAK), + /** + * This will allow breaking all special blocks, currently only liquid. Later + * there might be more sub-types. + */ + BLOCKBREAK_BREAK(CheckTypeType.CHECK, BLOCKBREAK, Permissions.BLOCKBREAK_BREAK), + BLOCKBREAK_DIRECTION(CheckTypeType.CHECK, BLOCKBREAK, Permissions.BLOCKBREAK_DIRECTION), + BLOCKBREAK_FASTBREAK(CheckTypeType.CHECK, BLOCKBREAK, Permissions.BLOCKBREAK_FASTBREAK), + BLOCKBREAK_FREQUENCY(CheckTypeType.CHECK, BLOCKBREAK, Permissions.BLOCKBREAK_FREQUENCY), + BLOCKBREAK_NOSWING(CheckTypeType.CHECK, BLOCKBREAK, Permissions.BLOCKBREAK_NOSWING), + BLOCKBREAK_REACH(CheckTypeType.CHECK, BLOCKBREAK, Permissions.BLOCKBREAK_REACH), + BLOCKBREAK_WRONGBLOCK(CheckTypeType.CHECK, BLOCKBREAK, Permissions.BLOCKBREAK_WRONGBLOCK), - BLOCKINTERACT(CheckType.ALL, BlockInteractConfig.factory, BlockInteractData.factory, Permissions.BLOCKINTERACT), - BLOCKINTERACT_DIRECTION(BLOCKINTERACT, Permissions.BLOCKINTERACT_DIRECTION), - BLOCKINTERACT_REACH(BLOCKINTERACT, Permissions.BLOCKINTERACT_REACH), - BLOCKINTERACT_SPEED(BLOCKINTERACT, Permissions.BLOCKINTERACT_SPEED), - BLOCKINTERACT_VISIBLE(BLOCKINTERACT, Permissions.BLOCKINTERACT_VISIBLE), + BLOCKINTERACT(CheckTypeType.GROUP, CheckType.ALL, Permissions.BLOCKINTERACT), + BLOCKINTERACT_DIRECTION(CheckTypeType.CHECK, BLOCKINTERACT, Permissions.BLOCKINTERACT_DIRECTION), + BLOCKINTERACT_REACH(CheckTypeType.CHECK, BLOCKINTERACT, Permissions.BLOCKINTERACT_REACH), + BLOCKINTERACT_SPEED(CheckTypeType.CHECK, BLOCKINTERACT, Permissions.BLOCKINTERACT_SPEED), + BLOCKINTERACT_VISIBLE(CheckTypeType.CHECK, BLOCKINTERACT, Permissions.BLOCKINTERACT_VISIBLE), - BLOCKPLACE(CheckType.ALL, BlockPlaceConfig.factory, BlockPlaceData.factory, Permissions.BLOCKPLACE), - BLOCKPLACE_AGAINST(BLOCKPLACE, Permissions.BLOCKPLACE_AGAINST), - BLOCKPLACE_AUTOSIGN(BLOCKPLACE, Permissions.BLOCKPLACE_AUTOSIGN), - BLOCKPLACE_DIRECTION(BLOCKPLACE, Permissions.BLOCKPLACE_DIRECTION), - BLOCKPLACE_FASTPLACE(BLOCKPLACE, Permissions.BLOCKPLACE_FASTPLACE), - BLOCKPLACE_NOSWING(BLOCKPLACE, Permissions.BLOCKPLACE_NOSWING), - BLOCKPLACE_REACH(BLOCKPLACE, Permissions.BLOCKBREAK_REACH), - BLOCKPLACE_SPEED(BLOCKPLACE, Permissions.BLOCKPLACE_SPEED), + BLOCKPLACE(CheckTypeType.GROUP, CheckType.ALL, Permissions.BLOCKPLACE), + BLOCKPLACE_AGAINST(CheckTypeType.CHECK, BLOCKPLACE, Permissions.BLOCKPLACE_AGAINST), + BLOCKPLACE_AUTOSIGN(CheckTypeType.CHECK, BLOCKPLACE, Permissions.BLOCKPLACE_AUTOSIGN), + BLOCKPLACE_DIRECTION(CheckTypeType.CHECK, BLOCKPLACE, Permissions.BLOCKPLACE_DIRECTION), + BLOCKPLACE_FASTPLACE(CheckTypeType.CHECK, BLOCKPLACE, Permissions.BLOCKPLACE_FASTPLACE), + BLOCKPLACE_NOSWING(CheckTypeType.CHECK, BLOCKPLACE, Permissions.BLOCKPLACE_NOSWING), + BLOCKPLACE_REACH(CheckTypeType.CHECK, BLOCKPLACE, Permissions.BLOCKBREAK_REACH), + BLOCKPLACE_SPEED(CheckTypeType.CHECK, BLOCKPLACE, Permissions.BLOCKPLACE_SPEED), - CHAT(CheckType.ALL, ChatConfig.factory, ChatData.factory, Permissions.CHAT), - CHAT_CAPTCHA(CHAT, Permissions.CHAT_CAPTCHA), - CHAT_COLOR(CHAT, Permissions.CHAT_COLOR), - CHAT_COMMANDS(CHAT, Permissions.CHAT_COMMANDS), - CHAT_TEXT(CHAT, Permissions.CHAT_TEXT), - CHAT_LOGINS(CHAT, Permissions.CHAT_LOGINS), - CHAT_RELOG(CHAT, Permissions.CHAT_RELOG), + CHAT(CheckTypeType.GROUP, CheckType.ALL, Permissions.CHAT), + CHAT_CAPTCHA(CheckTypeType.CHECK, CHAT, Permissions.CHAT_CAPTCHA), + CHAT_COLOR(CheckTypeType.CHECK, CHAT, Permissions.CHAT_COLOR), + CHAT_COMMANDS(CheckTypeType.CHECK, CHAT, Permissions.CHAT_COMMANDS), + CHAT_TEXT(CheckTypeType.CHECK, CHAT, Permissions.CHAT_TEXT), + CHAT_LOGINS(CheckTypeType.CHECK, CHAT, Permissions.CHAT_LOGINS), + CHAT_RELOG(CheckTypeType.CHECK, CHAT, Permissions.CHAT_RELOG), - COMBINED(CheckType.ALL, CombinedConfig.factory, CombinedData.factory, Permissions.COMBINED), - COMBINED_BEDLEAVE(COMBINED, Permissions.COMBINED_BEDLEAVE), - COMBINED_IMPROBABLE(COMBINED, Permissions.COMBINED_IMPROBABLE), - COMBINED_MUNCHHAUSEN(COMBINED, Permissions.COMBINED_MUNCHHAUSEN), + COMBINED(CheckTypeType.GROUP, CheckType.ALL, Permissions.COMBINED), + COMBINED_BEDLEAVE(CheckTypeType.CHECK, COMBINED, Permissions.COMBINED_BEDLEAVE), + COMBINED_IMPROBABLE(CheckTypeType.CHECK, COMBINED, Permissions.COMBINED_IMPROBABLE), + COMBINED_MUNCHHAUSEN(CheckTypeType.CHECK, COMBINED, Permissions.COMBINED_MUNCHHAUSEN), /** Rather for data removal and exemption. */ - COMBINED_YAWRATE(COMBINED), + COMBINED_YAWRATE(CheckTypeType.CHECK, COMBINED), - FIGHT(CheckType.ALL, FightConfig.factory, FightData.factory, Permissions.FIGHT), - FIGHT_ANGLE(FIGHT, Permissions.FIGHT_ANGLE), - FIGHT_CRITICAL(FIGHT, Permissions.FIGHT_CRITICAL), - FIGHT_DIRECTION(FIGHT, Permissions.FIGHT_DIRECTION), - FIGHT_FASTHEAL(FIGHT, Permissions.FIGHT_FASTHEAL), - FIGHT_GODMODE(FIGHT, Permissions.FIGHT_GODMODE), - FIGHT_NOSWING(FIGHT, Permissions.FIGHT_NOSWING), - FIGHT_REACH(FIGHT, Permissions.FIGHT_REACH), - FIGHT_SELFHIT(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_SELFHIT, - FightConfig.factory, FightData.selfHitDataFactory), - FIGHT_SPEED(FIGHT, Permissions.FIGHT_SPEED), - FIGHT_WRONGTURN(FIGHT, null), + FIGHT(CheckTypeType.CHECK, CheckType.ALL, Permissions.FIGHT), + FIGHT_ANGLE(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_ANGLE), + FIGHT_CRITICAL(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_CRITICAL), + FIGHT_DIRECTION(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_DIRECTION), + FIGHT_FASTHEAL(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_FASTHEAL), + FIGHT_GODMODE(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_GODMODE), + FIGHT_NOSWING(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_NOSWING), + FIGHT_REACH(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_REACH), + FIGHT_SELFHIT(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_SELFHIT), + FIGHT_SPEED(CheckTypeType.CHECK, FIGHT, Permissions.FIGHT_SPEED), + FIGHT_WRONGTURN(CheckTypeType.CHECK, FIGHT, null), - INVENTORY(CheckType.ALL, InventoryConfig.factory, InventoryData.factory, Permissions.INVENTORY), - INVENTORY_DROP(INVENTORY, Permissions.INVENTORY_DROP), - INVENTORY_FASTCLICK(INVENTORY, Permissions.INVENTORY_FASTCLICK), - INVENTORY_FASTCONSUME(INVENTORY, Permissions.INVENTORY_FASTCONSUME), - INVENTORY_GUTENBERG(INVENTORY, Permissions.INVENTORY_GUTENBERG), - INVENTORY_INSTANTBOW(INVENTORY, Permissions.INVENTORY_INSTANTBOW), - INVENTORY_INSTANTEAT(INVENTORY, Permissions.INVENTORY_INSTANTEAT), - INVENTORY_ITEMS(INVENTORY, Permissions.INVENTORY_ITEMS), - INVENTORY_OPEN(INVENTORY, Permissions.INVENTORY_OPEN), + INVENTORY(CheckTypeType.GROUP, CheckType.ALL, Permissions.INVENTORY), + INVENTORY_DROP(CheckTypeType.CHECK, INVENTORY, Permissions.INVENTORY_DROP), + INVENTORY_FASTCLICK(CheckTypeType.CHECK, INVENTORY, Permissions.INVENTORY_FASTCLICK), + INVENTORY_FASTCONSUME(CheckTypeType.CHECK, INVENTORY, Permissions.INVENTORY_FASTCONSUME), + INVENTORY_GUTENBERG(CheckTypeType.CHECK, INVENTORY, Permissions.INVENTORY_GUTENBERG), + INVENTORY_INSTANTBOW(CheckTypeType.CHECK, INVENTORY, Permissions.INVENTORY_INSTANTBOW), + INVENTORY_INSTANTEAT(CheckTypeType.CHECK, INVENTORY, Permissions.INVENTORY_INSTANTEAT), + INVENTORY_ITEMS(CheckTypeType.CHECK, INVENTORY, Permissions.INVENTORY_ITEMS), + INVENTORY_OPEN(CheckTypeType.CHECK, INVENTORY, Permissions.INVENTORY_OPEN), - MOVING(CheckType.ALL, MovingConfig.factory, MovingData.factory, Permissions.MOVING), - MOVING_CREATIVEFLY(MOVING, Permissions.MOVING_CREATIVEFLY), - MOVING_MOREPACKETS(MOVING, Permissions.MOVING_MOREPACKETS), - MOVING_NOFALL(MOVING, Permissions.MOVING_NOFALL), - MOVING_PASSABLE(MOVING, Permissions.MOVING_PASSABLE), - MOVING_SURVIVALFLY(MOVING, Permissions.MOVING_SURVIVALFLY), - MOVING_VEHICLE(MOVING, Permissions.MOVING_VEHICLE), - MOVING_VEHICLE_MOREPACKETS(MOVING_VEHICLE, Permissions.MOVING_VEHICLE_MOREPACKETS), - MOVING_VEHICLE_ENVELOPE(MOVING_VEHICLE, Permissions.MOVING_VEHICLE_ENVELOPE), + MOVING(CheckTypeType.GROUP, CheckType.ALL, Permissions.MOVING), + MOVING_CREATIVEFLY(CheckTypeType.CHECK, MOVING, Permissions.MOVING_CREATIVEFLY), + MOVING_MOREPACKETS(CheckTypeType.CHECK, MOVING, Permissions.MOVING_MOREPACKETS), + MOVING_NOFALL(CheckTypeType.CHECK, MOVING, Permissions.MOVING_NOFALL), + MOVING_PASSABLE(CheckTypeType.CHECK, MOVING, Permissions.MOVING_PASSABLE), + MOVING_SURVIVALFLY(CheckTypeType.CHECK, MOVING, Permissions.MOVING_SURVIVALFLY), + MOVING_VEHICLE(CheckTypeType.GROUP, MOVING, Permissions.MOVING_VEHICLE), + MOVING_VEHICLE_MOREPACKETS(CheckTypeType.CHECK, MOVING_VEHICLE, Permissions.MOVING_VEHICLE_MOREPACKETS), + MOVING_VEHICLE_ENVELOPE(CheckTypeType.CHECK, MOVING_VEHICLE, Permissions.MOVING_VEHICLE_ENVELOPE), - NET(CheckType.ALL, new NetConfigCache(), new NetDataFactory(), Permissions.NET), - NET_ATTACKFREQUENCY(NET, Permissions.NET_ATTACKFREQUENCY), - NET_FLYINGFREQUENCY(NET, Permissions.NET_FLYINGFREQUENCY), - NET_KEEPALIVEFREQUENCY(NET, Permissions.NET_KEEPALIVEFREQUENCY), - NET_PACKETFREQUENCY(NET, Permissions.NET_PACKETFREQUENCY), - NET_SOUNDDISTANCE(NET), // Can not exempt players from this one. + NET(CheckTypeType.GROUP, CheckType.ALL, Permissions.NET), + NET_ATTACKFREQUENCY(CheckTypeType.CHECK, NET, Permissions.NET_ATTACKFREQUENCY), + NET_FLYINGFREQUENCY(CheckTypeType.CHECK, NET, Permissions.NET_FLYINGFREQUENCY), + NET_KEEPALIVEFREQUENCY(CheckTypeType.CHECK, NET, Permissions.NET_KEEPALIVEFREQUENCY), + NET_PACKETFREQUENCY(CheckTypeType.CHECK, NET, Permissions.NET_PACKETFREQUENCY), + NET_SOUNDDISTANCE(CheckTypeType.CHECK, NET), // Can not exempt players from this one. ; @@ -144,56 +125,36 @@ public enum CheckType { /** If not null, this is the check group usually. */ private final CheckType parent; - /** The check config factory (access CheckConfig instances by CheckType). */ - private final CheckConfigFactory configFactory; - - /** The check data factory (access CheckData instances by CheckType). */ - private final CheckDataFactory dataFactory; - /** The bypass permission. */ private final RegisteredPermission permission; + /** Configuration path for the active flag. */ + private final String configPathActive; + + /** Configuration path for the debug flag. */ + private final String configPathDebug; + + /** Configuration path for the lag flag. */ + private final String configPathLag; + /** * Special purpose for grouping (ALL). * * @param permission */ private CheckType(final RegisteredPermission permission){ - this(CheckTypeType.SPECIAL, null, permission, null, null); + // TODO: Might as well interpret as GROUP. + this(CheckTypeType.SPECIAL, null, 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 CheckType parent, - final CheckConfigFactory configFactory, final CheckDataFactory dataFactory, - final RegisteredPermission permission) { - this(CheckTypeType.GROUP, parent, permission, configFactory, dataFactory); - } - - /** - * Constructor for sub-checks grouped under another check type, without - * having a permission set. + * Constructor for checks or groups grouped under another check type, + * without having a permission set, with default activation flag path. * * @param parent */ - private CheckType(final CheckType parent) { - this(parent, null); - } - - /** - * Constructor for sub-checks grouped under another check type. - * - * @param parent - * @param permission - */ - private CheckType(final CheckType parent, final RegisteredPermission permission) { - this(CheckTypeType.CHECK, parent, permission, parent.getConfigFactory(), parent.getDataFactory()); + private CheckType(final CheckTypeType type, final CheckType parent) { + this(type, parent, null); } /** @@ -205,43 +166,48 @@ public enum CheckType { * Super check type (usually the group). * @param permission * Bypass permission. - * @param configFactory - * Check config factory. - * @param dataFactory - * Check data factory. + */ + private CheckType(final CheckTypeType type, final CheckType parent, + final RegisteredPermission permission) { + this(type, parent, permission, null); + } + + /** + * General constructor (bottom). + * + * @param type + * @param parent + * @param permission + * @param configPathActive */ private CheckType(final CheckTypeType type, final CheckType parent, final RegisteredPermission permission, - final CheckConfigFactory configFactory, final CheckDataFactory dataFactory) { + final String configPathActive) { this.type = type; this.parent = parent; this.permission = permission; - this.configFactory = configFactory; - this.dataFactory = dataFactory; + this.configPathActive = configPathActive == null ? guessConfigPathActive() : configPathActive ; + this.configPathDebug = guessConfigPath(this.configPathActive, ConfPaths.SUB_DEBUG); + this.configPathLag = guessConfigPath(this.configPathActive, ConfPaths.SUB_LAG); + } + + private String guessConfigPathActive() { + return guessConfigPathRoot() + ConfPaths.SUB_ACTIVE; + } + + private String guessConfigPath(String configPathActive, String suffix) { + final int index = configPathActive.lastIndexOf("."); + return index == -1 ? suffix: configPathActive.substring(0, index + 1) + suffix; + } + + private String guessConfigPathRoot() { + return name().toLowerCase().replace('_', '.') + "."; } public CheckTypeType getType() { return type; } - /** - * Gets the configFactory. - * - * @return the configFactory - */ - public CheckConfigFactory getConfigFactory() { - return configFactory; - } - - /** - * Gets the dataFactory. - * - * @return the dataFactory - */ - public CheckDataFactory getDataFactory() { - return dataFactory; - } - /** * Gets the name. * @@ -270,14 +236,20 @@ public enum CheckType { } /** - * Check if the check is enabled by configuration (no permission check). + * Return the configuration path for the activation flag. * - * @param player - * the player - * @return true, if the check is enabled + * @return */ - public final boolean isEnabled(final Player player) { - return configFactory.getConfig(player).isEnabled(this); + public String getConfigPathActive() { + return configPathActive; + } + + public String getConfigPathDebug() { + return configPathDebug; + } + + public String getConfigPathLag() { + return configPathLag; } } \ No newline at end of file diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ACheckConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ACheckConfig.java index a41baafa..0fb36a39 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ACheckConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ACheckConfig.java @@ -14,21 +14,17 @@ */ package fr.neatmonster.nocheatplus.checks.access; -import fr.neatmonster.nocheatplus.config.ConfPaths; -import fr.neatmonster.nocheatplus.config.ConfigFile; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Minimal implementation, doing nothing. - * @author mc_dev + * @author asofold * */ public abstract class ACheckConfig implements ICheckConfig { - /** For on the fly debug setting. */ - public boolean debug = false; // TODO: Might make private. - - /** If to adapt to server side lag. */ - public final boolean lag; + /** World data storage for this world. */ + public final IWorldData worldData; /** * @@ -36,21 +32,9 @@ public abstract class ACheckConfig implements ICheckConfig { * @param pathPrefix Path prefix for the check section (example for use: prefix+"debug"). * @param cachePermissions cachePermissions Permissions to hold in player data cache. Can be null. */ - public ACheckConfig(final ConfigFile config, final String pathPrefix){ - // TODO: Path prefix construction is somewhat inconsistent with debug hierarchy ? - debug = config.getBoolean(pathPrefix + ConfPaths.SUB_DEBUG, config.getBoolean(ConfPaths.CHECKS_DEBUG, false)); - // TODO: Use lag flag where appropriate and document it (or get rid of it). - lag = config.getBoolean(pathPrefix + ConfPaths.SUB_LAG, true) && config.getBoolean(ConfPaths.MISCELLANEOUS_LAG, true); + public ACheckConfig(final IWorldData worldData){ + this.worldData = worldData; } - @Override - public boolean getDebug() { - return debug; - } - - @Override - public void setDebug(final boolean debug) { - this.debug = debug; - } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ACheckData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ACheckData.java index 86914423..dad8398e 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ACheckData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ACheckData.java @@ -16,25 +16,11 @@ package fr.neatmonster.nocheatplus.checks.access; /** * Abstract implementation to do nothing. - * @author mc_dev + * + * @author asofold + * @TODO: Keep/remove. * */ public abstract class ACheckData implements ICheckData { - public boolean debug; // TODO: Might make private. - - public ACheckData(ICheckConfig config) { - setDebug(config.getDebug()); - } - - @Override - public void setDebug(boolean debug) { - this.debug = debug; - } - - @Override - public boolean getDebug() { - return debug; - } - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/AsyncCheckData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/AsyncCheckData.java index 92feff13..321c157d 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/AsyncCheckData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/AsyncCheckData.java @@ -15,16 +15,11 @@ package fr.neatmonster.nocheatplus.checks.access; /** - * ChecData for async checks like chat, actually implementing cached permissions. - * @author mc_dev + * + * @author asofold + * @TODO Keep / remove. * */ public abstract class AsyncCheckData extends ACheckData { - - // TODO: Still needed ? - - public AsyncCheckData(ICheckConfig config) { - super(config); - } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/CheckDataFactory.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/CheckDataFactory.java deleted file mode 100644 index 09dd90f1..00000000 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/CheckDataFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package fr.neatmonster.nocheatplus.checks.access; - -import java.util.UUID; - -import org.bukkit.entity.Player; - -import fr.neatmonster.nocheatplus.components.registry.feature.IRemoveData; - -/** - * A factory for creating and accessing data. This design may be outdated, due - * to PlayerData soon holding the check data instances and factories becoming - * factories again. - * - * @author asofold - */ -public interface CheckDataFactory extends IRemoveData{ - - /** - * Gets the data of the specified player. Data might get created, if not - * present already. - * - * @param player - * the player - * @return the data - */ - public ICheckData getData(Player player); - - /** - * Get data, but don't create if not present. - * - * @param playerId - * @param playerName - * @return The data instance, if present. Null otherwise. - */ - public ICheckData getDataIfPresent(UUID playerId, String playerName); - - @Override - public ICheckData removeData(String playerName); - -} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ICheckConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ICheckConfig.java index 57ac3409..13089bc4 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ICheckConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ICheckConfig.java @@ -14,28 +14,12 @@ */ package fr.neatmonster.nocheatplus.checks.access; -import fr.neatmonster.nocheatplus.checks.CheckType; - /** - * This interface must be implemented by all configuration classes. + * TODO: Keep / Remove. * * @author asofold */ public interface ICheckConfig { - /** - * Checks if a check is enabled. - * - * @param checkType - * the check type - * @return true, if the check is enabled - */ - public boolean isEnabled(CheckType checkType); - - /** On the fly debug flags, to be set by commands and similar. */ - public boolean getDebug(); - - /** On the fly debug flags, to be set by commands and similar. */ - public void setDebug(boolean debug); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ICheckData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ICheckData.java index ae4fbc9a..49e16946 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ICheckData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/ICheckData.java @@ -18,24 +18,15 @@ import fr.neatmonster.nocheatplus.components.data.IData; /** * This is for future purposes. Might remove...
- * Some checks in chat synchronize over data, so using this from exectueActions can deadlock.
- * One might think of making this an interface not for the internally used data, but for copy of data for external use - * only. Then sync could go over other objects for async access. + * Some checks in chat synchronize over data, so using this from exectueActions + * can deadlock.
+ * One might think of making this an interface not for the internally used data, + * but for copy of data for external use only. Then sync could go over other + * objects for async access. * * @author asofold + * @TODO Keep/Remove */ public interface ICheckData extends IData{ - /** - * Set if to trace/debug this player for the associated checks. - * @param debug - */ - public void setDebug(boolean debug); - - /** - * Test if to trace/debug this player for the associated checks. - * @return - */ - public boolean getDebug(); - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/SubCheckDataFactory.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/SubCheckDataFactory.java deleted file mode 100644 index 50f43407..00000000 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/SubCheckDataFactory.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package fr.neatmonster.nocheatplus.checks.access; - -import java.util.Collection; - -import org.bukkit.entity.Player; - -import fr.neatmonster.nocheatplus.checks.CheckType; - -/** - * Quick and dirty way to add factories for sub checks for more precise data removal from a more general data object. - * @author mc_dev - * - */ -public abstract class SubCheckDataFactory implements CheckDataFactory { - protected final CheckDataFactory parentFactory; - protected final CheckType checkType; - - public SubCheckDataFactory(CheckType checkType, CheckDataFactory parentFactory) { - this.checkType = checkType; - this.parentFactory = parentFactory; - } - - /* (non-Javadoc) - * @see fr.neatmonster.nocheatplus.components.IRemoveData#removeAllData() - */ - @Override - public void removeAllData() { - for (String playerName : getPresentData()) { - D data = getData(playerName); - if (data != null) { - removeFromData(playerName, data); - } - } - } - - /* (non-Javadoc) - * @see fr.neatmonster.nocheatplus.checks.access.CheckDataFactory#getData(org.bukkit.entity.Player) - */ - @Override - public ICheckData getData(Player player) { - return parentFactory.getData(player); - } - - /* (non-Javadoc) - * @see fr.neatmonster.nocheatplus.checks.access.CheckDataFactory#removeData(java.lang.String) - */ - @Override - public ICheckData removeData(String playerName) { - if (!hasData(playerName)) { - return null; - } - D data = getData(playerName); - if (data != null) { - if (removeFromData(playerName, data)) { - // Return data instance, if changed. - return data; - } - } - return null; - } - - /** - * - * @param playerName Exact case lookup. - * @return Can return null. - */ - protected abstract D getData(String playerName); - - /** - * Names are expected to be exact case. This collection is demanded to be iterable (eclipse: adorable) in case the check runs asynchronously.
- * This method might change "a lot" with time. - * @return - */ - protected abstract Collection getPresentData(); - - /** - * Fast check, if there is data for the player. - * @param playerName Exact case lookup. - * @return - */ - protected abstract boolean hasData(String playerName); - - /** - * Remove the specific data from the given data instance.
- * TODO: Might add timestamp as argument (ms). - * @param playerName Exact case. Just for reference. - * @param data The data from which to remove the checkType-specific parts. This will never be null. - * @return If changed. - */ - protected abstract boolean removeFromData(String playerName, D data); -} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakConfig.java index 60de3281..a5295f3b 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakConfig.java @@ -14,20 +14,12 @@ */ package fr.neatmonster.nocheatplus.checks.blockbreak; -import java.util.HashMap; -import java.util.Map; - -import org.bukkit.entity.Player; - import fr.neatmonster.nocheatplus.actions.ActionList; -import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckConfig; -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.permissions.Permissions; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Configurations specific for the block break checks. Every world gets one of these assigned to it, or if a world @@ -35,47 +27,8 @@ import fr.neatmonster.nocheatplus.permissions.Permissions; */ public class BlockBreakConfig extends ACheckConfig { - /** The factory creating configurations. */ - public static final CheckConfigFactory factory = new CheckConfigFactory() { - @Override - public final ICheckConfig getConfig(final Player player) { - return BlockBreakConfig.getConfig(player); - } - - @Override - public void removeAllConfigs() { - clear(); // Band-aid. - } - }; - - /** The map containing the configurations per world. */ - private static final Map worldsMap = new HashMap(); - - /** - * Clear all the configurations. - */ - public static void clear() { - worldsMap.clear(); - } - - /** - * Gets the configuration for a specified player. - * - * @param player - * the player - * @return the configuration - */ - public static BlockBreakConfig getConfig(final Player player) { - if (!worldsMap.containsKey(player.getWorld().getName())) - worldsMap.put(player.getWorld().getName(), - new BlockBreakConfig(ConfigManager.getConfigFile(player.getWorld().getName()))); - return worldsMap.get(player.getWorld().getName()); - } - - public final boolean directionCheck; public final ActionList directionActions; - public final boolean fastBreakCheck; public final boolean fastBreakStrict; public final int fastBreakBuckets; public final long fastBreakBucketDur; @@ -86,7 +39,6 @@ public class BlockBreakConfig extends ACheckConfig { public final ActionList fastBreakActions; - public final boolean frequencyCheck; public final int frequencyBuckets; public final long frequencyBucketDur; public final float frequencyBucketFactor; @@ -99,13 +51,10 @@ public class BlockBreakConfig extends ACheckConfig { public boolean improbableFastBreakCheck; - public final boolean noSwingCheck; public final ActionList noSwingActions; - public final boolean reachCheck; public final ActionList reachActions; - public final boolean wrongBlockCheck; public final float wrongBLockLevel; public final ActionList wrongBlockActions; @@ -115,67 +64,38 @@ public class BlockBreakConfig extends ACheckConfig { * @param data * the data */ - public BlockBreakConfig(final ConfigFile data) { - super(data, ConfPaths.BLOCKBREAK); - directionCheck = data.getBoolean(ConfPaths.BLOCKBREAK_DIRECTION_CHECK); - directionActions = data.getOptimizedActionList(ConfPaths.BLOCKBREAK_DIRECTION_ACTIONS, Permissions.BLOCKBREAK_DIRECTION); + public BlockBreakConfig(final IWorldData worldData) { + super(worldData); + final ConfigFile config = worldData.getRawConfiguration(); + directionActions = config.getOptimizedActionList(ConfPaths.BLOCKBREAK_DIRECTION_ACTIONS, Permissions.BLOCKBREAK_DIRECTION); // Fastbreak. - fastBreakCheck = data.getBoolean(ConfPaths.BLOCKBREAK_FASTBREAK_CHECK); - fastBreakStrict = data.getBoolean(ConfPaths.BLOCKBREAK_FASTBREAK_STRICT); - fastBreakDelay = data.getLong(ConfPaths.BLOCKBREAK_FASTBREAK_DELAY); - fastBreakGrace = data.getLong(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_CONTENTION, - data.getLong(ConfPaths.BLOCKBREAK_FASTBREAK_GRACE, 2000)); - fastBreakBucketDur = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_DUR, 4000); - fastBreakBucketFactor = (float) data.getDouble(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_FACTOR, 0.99); - fastBreakBuckets = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_N, 30); - fastBreakModSurvival = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_MOD_SURVIVAL); + fastBreakStrict = config.getBoolean(ConfPaths.BLOCKBREAK_FASTBREAK_STRICT); + fastBreakDelay = config.getLong(ConfPaths.BLOCKBREAK_FASTBREAK_DELAY); + fastBreakGrace = config.getLong(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_CONTENTION, + config.getLong(ConfPaths.BLOCKBREAK_FASTBREAK_GRACE, 2000)); + fastBreakBucketDur = config.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_DUR, 4000); + fastBreakBucketFactor = (float) config.getDouble(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_FACTOR, 0.99); + fastBreakBuckets = config.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_N, 30); + fastBreakModSurvival = config.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_MOD_SURVIVAL); // Fastbreak actions, shared. - fastBreakActions = data.getOptimizedActionList(ConfPaths.BLOCKBREAK_FASTBREAK_ACTIONS, Permissions.BLOCKBREAK_FASTBREAK); + fastBreakActions = config.getOptimizedActionList(ConfPaths.BLOCKBREAK_FASTBREAK_ACTIONS, Permissions.BLOCKBREAK_FASTBREAK); - frequencyCheck = data.getBoolean(ConfPaths.BLOCKBREAK_FREQUENCY_CHECK); - frequencyBuckets = data.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_BUCKETS_N, 2); - frequencyBucketDur = data.getLong(ConfPaths.BLOCKBREAK_FREQUENCY_BUCKETS_DUR, 1000); - frequencyBucketFactor = (float) data.getDouble(ConfPaths.BLOCKBREAK_FREQUENCY_BUCKETS_FACTOR, 1f); - frequencyIntervalCreative = data.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_MOD_CREATIVE); - frequencyIntervalSurvival = data.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_MOD_SURVIVAL); - frequencyShortTermLimit = data.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_SHORTTERM_LIMIT); - frequencyShortTermTicks = data.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_SHORTTERM_TICKS); - frequencyActions = data.getOptimizedActionList(ConfPaths.BLOCKBREAK_FREQUENCY_ACTIONS, Permissions.BLOCKBREAK_FREQUENCY); + frequencyBuckets = config.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_BUCKETS_N, 2); + frequencyBucketDur = config.getLong(ConfPaths.BLOCKBREAK_FREQUENCY_BUCKETS_DUR, 1000); + frequencyBucketFactor = (float) config.getDouble(ConfPaths.BLOCKBREAK_FREQUENCY_BUCKETS_FACTOR, 1f); + frequencyIntervalCreative = config.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_MOD_CREATIVE); + frequencyIntervalSurvival = config.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_MOD_SURVIVAL); + frequencyShortTermLimit = config.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_SHORTTERM_LIMIT); + frequencyShortTermTicks = config.getInt(ConfPaths.BLOCKBREAK_FREQUENCY_SHORTTERM_TICKS); + frequencyActions = config.getOptimizedActionList(ConfPaths.BLOCKBREAK_FREQUENCY_ACTIONS, Permissions.BLOCKBREAK_FREQUENCY); - noSwingCheck = data.getBoolean(ConfPaths.BLOCKBREAK_NOSWING_CHECK); - noSwingActions = data.getOptimizedActionList(ConfPaths.BLOCKBREAK_NOSWING_ACTIONS, Permissions.BLOCKBREAK_NOSWING); + noSwingActions = config.getOptimizedActionList(ConfPaths.BLOCKBREAK_NOSWING_ACTIONS, Permissions.BLOCKBREAK_NOSWING); - reachCheck = data.getBoolean(ConfPaths.BLOCKBREAK_REACH_CHECK); - reachActions = data.getOptimizedActionList(ConfPaths.BLOCKBREAK_REACH_ACTIONS, Permissions.BLOCKBREAK_REACH); + reachActions = config.getOptimizedActionList(ConfPaths.BLOCKBREAK_REACH_ACTIONS, Permissions.BLOCKBREAK_REACH); - wrongBlockCheck = data.getBoolean(ConfPaths.BLOCKBREAK_WRONGBLOCK_CHECK); - wrongBLockLevel = data.getInt(ConfPaths.BLOCKBREAK_WRONGBLOCK_LEVEL); - wrongBlockActions = data.getOptimizedActionList(ConfPaths.BLOCKBREAK_WRONGBLOCK_ACTIONS, Permissions.BLOCKBREAK_WRONGBLOCK); + wrongBLockLevel = config.getInt(ConfPaths.BLOCKBREAK_WRONGBLOCK_LEVEL); + wrongBlockActions = config.getOptimizedActionList(ConfPaths.BLOCKBREAK_WRONGBLOCK_ACTIONS, Permissions.BLOCKBREAK_WRONGBLOCK); } - /* (non-Javadoc) - * @see fr.neatmonster.nocheatplus.checks.ICheckConfig#isEnabled(fr.neatmonster.nocheatplus.checks.CheckType) - */ - @Override - public final boolean isEnabled(final CheckType checkType) { - switch (checkType) { - case BLOCKBREAK_DIRECTION: - return directionCheck; - case BLOCKBREAK_FASTBREAK: - return fastBreakCheck; - case BLOCKBREAK_FREQUENCY: - return frequencyCheck; - case BLOCKBREAK_NOSWING: - return noSwingCheck; - case BLOCKBREAK_REACH: - return reachCheck; - case BLOCKBREAK_WRONGBLOCK: - return wrongBlockCheck; - case BLOCKBREAK_BREAK: - return true; - default: - return true; - } - } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakData.java index 12077616..038df40d 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakData.java @@ -14,18 +14,11 @@ */ package fr.neatmonster.nocheatplus.checks.blockbreak; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import fr.neatmonster.nocheatplus.checks.access.ACheckData; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.stats.Timings; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; @@ -35,53 +28,6 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; */ public class BlockBreakData extends ACheckData { - /** The factory creating data. */ - public static final CheckDataFactory factory = new CheckDataFactory() { - @Override - public final ICheckData getData(final Player player) { - return BlockBreakData.getData(player); - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return BlockBreakData.playersMap.get(playerName); - } - - @Override - public ICheckData removeData(final String playerName) { - return BlockBreakData.removeData(playerName); - } - - @Override - public void removeAllData() { - clear(); - } - }; - - /** The map containing the data per players. */ - private static final Map playersMap = new HashMap(); - - /** - * Gets the data of a specified player. - * - * @param player - * the player - * @return the data - */ - public static BlockBreakData getData(final Player player) { - if (!playersMap.containsKey(player.getName())) - playersMap.put(player.getName(), new BlockBreakData(BlockBreakConfig.getConfig(player))); - return playersMap.get(player.getName()); - } - - public static ICheckData removeData(final String playerName) { - return playersMap.remove(playerName); - } - - public static void clear(){ - playersMap.clear(); - } - // Violation levels. public double directionVL; public double fastBreakVL; @@ -121,26 +67,15 @@ public class BlockBreakData extends ACheckData { public BlockBreakData(final BlockBreakConfig cc) { - super(cc); setStats(); fastBreakPenalties = new ActionFrequency(cc.fastBreakBuckets, cc.fastBreakBucketDur); frequencyBuckets = new ActionFrequency(cc.frequencyBuckets, cc.frequencyBucketDur); wrongBlockVL = new ActionFrequency(6, 20000); } - @Override - public void setDebug(boolean debug) { - super.setDebug(debug); - setStats(); - } - - private void setStats() { - if (getDebug()) { - if (stats == null) { - stats = new Timings("NCP/FASTBREAK"); - } - } else { - stats = null; + void setStats() { + if (stats == null) { + stats = new Timings("NCP/FASTBREAK"); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakListener.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakListener.java index db8ad66f..64bca89e 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakListener.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/BlockBreakListener.java @@ -44,7 +44,7 @@ import fr.neatmonster.nocheatplus.compat.Bridge1_9; import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; @@ -96,10 +96,11 @@ public class BlockBreakListener extends CheckListener { public void onBlockBreak(final BlockBreakEvent event) { final long now = System.currentTimeMillis(); final Player player = event.getPlayer(); + final IPlayerData pData = DataManager.getPlayerData(player); // Illegal enchantments hotfix check. // TODO: Legacy / encapsulate fully there. - if (Items.checkIllegalEnchantmentsAllHands(player)) { + if (Items.checkIllegalEnchantmentsAllHands(player, pData)) { event.setCancelled(true); counters.addPrimaryThread(idCancelDIllegalItem, 1); } @@ -122,10 +123,9 @@ public class BlockBreakListener extends CheckListener { // Do the actual checks, if still needed. It's a good idea to make computationally cheap checks first, because // it may save us from doing the computationally expensive checks. - final PlayerData pData = DataManager.getPlayerData(player); // TODO: Use for data + config getting etc. - final BlockBreakConfig cc = BlockBreakConfig.getConfig(player); - final BlockBreakData data = BlockBreakData.getData(player); - final BlockInteractData bdata = BlockInteractData.getData(player); + final BlockBreakConfig cc = pData.getGenericInstance(BlockBreakConfig.class); + final BlockBreakData data = pData.getGenericInstance(BlockBreakData.class); + final BlockInteractData bdata = pData.getGenericInstance(BlockInteractData.class); /* * Re-check if this is a block interacted with before. With instantly * broken blocks, this may be off by one orthogonally. @@ -138,30 +138,35 @@ public class BlockBreakListener extends CheckListener { final GameMode gameMode = player.getGameMode(); // Has the player broken a block that was not damaged before? - final boolean wrongBlockEnabled = wrongBlock.isEnabled(player); + final boolean wrongBlockEnabled = wrongBlock.isEnabled(player, pData); if (wrongBlockEnabled && wrongBlock.check(player, block, cc, data, pData, isInstaBreak)) { cancelled = true; } // Has the player broken more blocks per second than allowed? - if (!cancelled && frequency.isEnabled(player) && frequency.check(player, tick, cc, data)) { + if (!cancelled && frequency.isEnabled(player, pData) + && frequency.check(player, tick, cc, data, pData)) { cancelled = true; } // Has the player broken blocks faster than possible? if (!cancelled && gameMode != GameMode.CREATIVE - && fastBreak.isEnabled(player) && fastBreak.check(player, block, isInstaBreak, cc, data, pData)) { + && fastBreak.isEnabled(player, pData) + && fastBreak.check(player, block, isInstaBreak, cc, data, pData)) { cancelled = true; } // Did the arm of the player move before breaking this block? - if (!cancelled && noSwing.isEnabled(player) && noSwing.check(player, data)) { + if (!cancelled && noSwing.isEnabled(player, pData) + && noSwing.check(player, data, pData)) { cancelled = true; } final FlyingQueueHandle flyingHandle; - if (cc.reachCheck || cc.directionCheck) { - flyingHandle = new FlyingQueueHandle(player); + final boolean reachEnabled = reach.isEnabled(player, pData); + final boolean directionEnabled = direction.isEnabled(player, pData); + if (reachEnabled || directionEnabled) { + flyingHandle = new FlyingQueueHandle(pData); final Location loc = player.getLocation(useLoc); final double eyeHeight = MovingUtil.getEyeHeight(player); // Is the block really in reach distance? @@ -169,7 +174,7 @@ public class BlockBreakListener extends CheckListener { if (isInteractBlock && bdata.isPassedCheck(CheckType.BLOCKINTERACT_REACH)) { skippedRedundantChecks ++; } - else if (reach.isEnabled(player) && reach.check(player, eyeHeight, block, data)) { + else if (reachEnabled && reach.check(player, eyeHeight, block, data, cc)) { cancelled = true; } } @@ -181,8 +186,8 @@ public class BlockBreakListener extends CheckListener { || bdata.isPassedCheck(CheckType.BLOCKINTERACT_VISIBLE))) { skippedRedundantChecks ++; } - else if (direction.isEnabled(player) && direction.check(player, loc, eyeHeight, block, - flyingHandle, data, cc)) { + else if (directionEnabled && direction.check(player, loc, eyeHeight, block, + flyingHandle, data, cc, pData)) { cancelled = true; } } @@ -212,8 +217,9 @@ public class BlockBreakListener extends CheckListener { // Invalidate last damage position: // data.clickedX = Integer.MAX_VALUE; // Debug log (only if not cancelled, to avoid spam). - if (data.debug) { - debugBlockBreakResult(player, block, skippedRedundantChecks, flyingHandle); + if (pData.isDebugActive(CheckType.BLOCKBREAK)) { + debugBlockBreakResult(player, block, skippedRedundantChecks, + flyingHandle, pData); } } @@ -231,10 +237,10 @@ public class BlockBreakListener extends CheckListener { } private void debugBlockBreakResult(final Player player, final Block block, final int skippedRedundantChecks, - final FlyingQueueHandle flyingHandle) { + final FlyingQueueHandle flyingHandle, final IPlayerData pData) { debug(player, "Block break(" + block.getType() + "): " + block.getX() + ", " + block.getY() + ", " + block.getZ()); BlockInteractListener.debugBlockVSBlockInteract(player, checkType, block, "onBlockBreak", - Action.LEFT_CLICK_BLOCK); + Action.LEFT_CLICK_BLOCK, pData); if (skippedRedundantChecks > 0) { debug(player, "Skipped redundant checks: " + skippedRedundantChecks); } @@ -260,7 +266,7 @@ public class BlockBreakListener extends CheckListener { public void onPlayerAnimation(final PlayerAnimationEvent event) { // Just set a flag to true when the arm was swung. // debug(player, "Animation"); - BlockBreakData.getData(event.getPlayer()).noSwingArmSwung = true; + DataManager.getPlayerData(event.getPlayer()).getGenericInstance(BlockBreakData.class).noSwingArmSwung = true; } /** @@ -317,7 +323,8 @@ public class BlockBreakListener extends CheckListener { private void checkBlockDamage(final Player player, final Block block, final Cancellable event){ final long now = System.currentTimeMillis(); - final BlockBreakData data = BlockBreakData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final BlockBreakData data = pData.getGenericInstance(BlockBreakData.class); // if (event.isCancelled()){ // // Reset the time, to avoid certain kinds of cheating. => WHICH ? @@ -351,9 +358,9 @@ public class BlockBreakListener extends CheckListener { // Only record first damage: data.setClickedBlock(block, tick, now, tool); // Compare with BlockInteract data (debug first). - if (data.debug) { - BlockInteractListener.debugBlockVSBlockInteract(player, this.checkType, block, "checkBlockDamage", - Action.LEFT_CLICK_BLOCK); + if (pData.isDebugActive(CheckType.BLOCKBREAK)) { + BlockInteractListener.debugBlockVSBlockInteract(player, this.checkType, + block, "checkBlockDamage", Action.LEFT_CLICK_BLOCK, pData); } } @@ -362,7 +369,7 @@ public class BlockBreakListener extends CheckListener { // Reset clicked block. // TODO: Not for 1.5.2 and before? final Player player = event.getPlayer(); - final BlockBreakData data = BlockBreakData.getData(player); + final BlockBreakData data = DataManager.getPlayerData(player).getGenericInstance(BlockBreakData.class); if (data.toolChanged(player.getInventory().getItem(event.getNewSlot()))) { data.resetClickedBlock(); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/FastBreak.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/FastBreak.java index 5ee2e9ea..29312188 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/FastBreak.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/FastBreak.java @@ -27,7 +27,7 @@ import fr.neatmonster.nocheatplus.checks.ViolationData; import fr.neatmonster.nocheatplus.compat.AlmostBoolean; import fr.neatmonster.nocheatplus.compat.Bridge1_9; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.PotionUtil; import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; @@ -58,7 +58,7 @@ public class FastBreak extends Check { * @return true, if successful */ public boolean check(final Player player, final Block block, final AlmostBoolean isInstaBreak, - final BlockBreakConfig cc, final BlockBreakData data, final PlayerData pData) { + final BlockBreakConfig cc, final BlockBreakData data, final IPlayerData pData) { final long now = System.currentTimeMillis(); boolean cancel = false; @@ -91,57 +91,71 @@ public class FastBreak extends Check { // lag or cheat or Minecraft. // Count in server side lag, if desired. - final float lag = cc.lag ? TickTask.getLag(expectedBreakingTime, true) : 1f; + final float lag = pData.getCurrentWorldDataSafe().shouldAdjustToLag(type) + ? TickTask.getLag(expectedBreakingTime, true) : 1f; - final long missingTime = expectedBreakingTime - (long) (lag * elapsedTime); + final long missingTime = expectedBreakingTime - (long) (lag * elapsedTime); - if (missingTime > 0) { - // Add as penalty - data.fastBreakPenalties.add(now, (float) missingTime); + if (missingTime > 0) { + // Add as penalty + data.fastBreakPenalties.add(now, (float) missingTime); - // Only raise a violation, if the total penalty score exceeds the contention duration (for lag, delay). - if (data.fastBreakPenalties.score(cc.fastBreakBucketFactor) > cc.fastBreakGrace) { - // TODO: maybe add one absolute penalty time for big amounts to stop breaking until then - final double vlAdded = (double) missingTime / 1000.0; - data.fastBreakVL += vlAdded; - final ViolationData vd = new ViolationData(this, player, data.fastBreakVL, vlAdded, cc.fastBreakActions); - if (vd.needsParameters()) { - vd.setParameter(ParameterName.BLOCK_TYPE, blockType.toString()); + // Only raise a violation, if the total penalty score exceeds the contention duration (for lag, delay). + if (data.fastBreakPenalties.score(cc.fastBreakBucketFactor) > cc.fastBreakGrace) { + // TODO: maybe add one absolute penalty time for big amounts to stop breaking until then + final double vlAdded = (double) missingTime / 1000.0; + data.fastBreakVL += vlAdded; + final ViolationData vd = new ViolationData(this, player, data.fastBreakVL, vlAdded, cc.fastBreakActions); + if (vd.needsParameters()) { + vd.setParameter(ParameterName.BLOCK_TYPE, blockType.toString()); + } + cancel = executeActions(vd).willCancel(); + } + // else: still within contention limits. } - cancel = executeActions(vd).willCancel(); - } - // else: still within contention limits. - } } else if (expectedBreakingTime > cc.fastBreakDelay) { // Fast breaking does not decrease violation level. data.fastBreakVL *= 0.9D; } - if ((data.debug) && pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)) { - // General stats: - // TODO: Replace stats by new system (BlockBreakKey once complete), commands to inspect / auto-config. - if (data.stats != null) { - data.stats.addStats(data.stats.getId(blockType+ "/u", true), elapsedTime); - data.stats.addStats(data.stats.getId(blockType + "/r", true), expectedBreakingTime); - player.sendMessage(data.stats.getStatsStr(true)); - } - // Send info about current break: - final ItemStack stack = Bridge1_9.getItemInMainHand(player); - final boolean isValidTool = BlockProperties.isValidTool(blockType, stack); - final double haste = PotionUtil.getPotionEffectAmplifier(player, PotionEffectType.FAST_DIGGING); - String msg = (isInstaBreak.decideOptimistically() ? ("[Insta=" + isInstaBreak + "]") : "[Normal]") + "[" + blockType + "] "+ elapsedTime + "u / " + expectedBreakingTime +"r (" + (isValidTool?"tool":"no-tool") + ")" + (Double.isInfinite(haste) ? "" : " haste=" + ((int) haste + 1)); - player.sendMessage(msg); - // net.minecraft.server.Item mcItem = net.minecraft.server.Item.byId[stack.getTypeId()]; - // if (mcItem != null) { - // double x = mcItem.getDestroySpeed(((CraftItemStack) stack).getHandle(), net.minecraft.server.Block.byId[blockId]); - // player.sendMessage("mc speed: " + x); - // } + // TODO: Rework to use (then hopefully completed) BlockBreakKey. + if (pData.isDebugActive(type)) { + tailDebugStats(player, isInstaBreak, blockType, + elapsedTime, expectedBreakingTime, data, pData); + } + else { + data.stats = null; } // (The break time is set in the listener). return cancel; } + + private void tailDebugStats(final Player player, final AlmostBoolean isInstaBreak, + final Material blockType, final long elapsedTime, final long expectedBreakingTime, + final BlockBreakData data, final IPlayerData pData) { + if (pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)) { + // General stats: + // TODO: Replace stats by new system (BlockBreakKey once complete), commands to inspect / auto-config. + data.setStats(); + data.stats.addStats(data.stats.getId(blockType+ "/u", true), elapsedTime); + data.stats.addStats(data.stats.getId(blockType + "/r", true), expectedBreakingTime); + player.sendMessage(data.stats.getStatsStr(true)); + // Send info about current break: + final ItemStack stack = Bridge1_9.getItemInMainHand(player); + final boolean isValidTool = BlockProperties.isValidTool(blockType, stack); + final double haste = PotionUtil.getPotionEffectAmplifier(player, PotionEffectType.FAST_DIGGING); + String msg = (isInstaBreak.decideOptimistically() ? ("[Insta=" + isInstaBreak + "]") : "[Normal]") + "[" + blockType + "] "+ elapsedTime + "u / " + expectedBreakingTime +"r (" + (isValidTool?"tool":"no-tool") + ")" + (Double.isInfinite(haste) ? "" : " haste=" + ((int) haste + 1)); + player.sendMessage(msg); + // net.minecraft.server.Item mcItem = net.minecraft.server.Item.byId[stack.getTypeId()]; + // if (mcItem != null) { + // double x = mcItem.getDestroySpeed(((CraftItemStack) stack).getHandle(), net.minecraft.server.Block.byId[blockId]); + // player.sendMessage("mc speed: " + x); + // } + } + } + } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/Frequency.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/Frequency.java index 6c591669..6151a70c 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/Frequency.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/Frequency.java @@ -19,6 +19,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.TickTask; /** @@ -33,7 +34,8 @@ public class Frequency extends Check { } public boolean check(final Player player, final int tick, - final BlockBreakConfig cc, final BlockBreakData data){ + final BlockBreakConfig cc, final BlockBreakData data, + final IPlayerData pData){ final float interval = (float) ((player.getGameMode() == GameMode.CREATIVE)?(cc.frequencyIntervalCreative):(cc.frequencyIntervalSurvival)); data.frequencyBuckets.add(System.currentTimeMillis(), interval); @@ -41,6 +43,7 @@ public class Frequency extends Check { // Full period frequency. final float fullScore = data.frequencyBuckets.score(cc.frequencyBucketFactor); final long fullTime = cc.frequencyBucketDur * cc.frequencyBuckets; + final boolean lag = pData.getCurrentWorldData().shouldAdjustToLag(type); // Short term arrivals. if (tick < data.frequencyShortTermTick){ @@ -50,7 +53,7 @@ public class Frequency extends Check { } else if (tick - data.frequencyShortTermTick < cc.frequencyShortTermTicks){ // Account for server side lag. - final float stLag = cc.lag ? TickTask.getLag(50L * (tick - data.frequencyShortTermTick), true) : 1f; + final float stLag = lag ? TickTask.getLag(50L * (tick - data.frequencyShortTermTick), true) : 1f; if (stLag < 1.5){ // Within range, add. data.frequencyShortTermCount ++; @@ -67,7 +70,7 @@ public class Frequency extends Check { } // Account for server side lag. - final float fullLag = cc.lag ? TickTask.getLag(fullTime, true) : 1f; + final float fullLag = lag ? TickTask.getLag(fullTime, true) : 1f; // Find if one of both or both are violations: final float fullViolation = (fullScore > fullTime * fullLag) ? (fullScore - fullTime * fullLag) : 0; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/NoSwing.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/NoSwing.java index 33d4a9b2..0b0db560 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/NoSwing.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/NoSwing.java @@ -18,6 +18,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * We require that the player moves their arm between block breaks, this is what gets checked here. @@ -38,7 +39,8 @@ public class NoSwing extends Check { * the player * @return true, if successful */ - public boolean check(final Player player, final BlockBreakData data) { + public boolean check(final Player player, final BlockBreakData data, + final IPlayerData pData) { boolean cancel = false; @@ -54,7 +56,7 @@ public class NoSwing extends Check { // Execute whatever actions are associated with this check and the violation level and find out if we should // cancel the event. - cancel = executeActions(player, data.noSwingVL, 1D, BlockBreakConfig.getConfig(player).noSwingActions).willCancel(); + cancel = executeActions(player, data.noSwingVL, 1D, pData.getGenericInstance(BlockBreakConfig.class).noSwingActions).willCancel(); } return cancel; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/Reach.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/Reach.java index cce9fcc2..2eb6ba35 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/Reach.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/Reach.java @@ -51,11 +51,13 @@ public class Reach extends Check { * * @param player * the player + * @param cc * @param location * the location * @return true, if successful */ - public boolean check(final Player player, final double eyeHeight, final Block block, final BlockBreakData data) { + public boolean check(final Player player, final double eyeHeight, final Block block, + final BlockBreakData data, final BlockBreakConfig cc) { boolean cancel = false; @@ -77,7 +79,7 @@ public class Reach extends Check { // Execute whatever actions are associated with this check and the violation level and find out if we should // cancel the event. - final ViolationData vd = new ViolationData(this, player, data.reachVL, distance, BlockBreakConfig.getConfig(player).reachActions); + final ViolationData vd = new ViolationData(this, player, data.reachVL, distance, cc.reachActions); vd.setParameter(ParameterName.REACH_DISTANCE, String.valueOf(Math.round(data.reachDistance))); cancel = executeActions(vd).willCancel(); } else{ diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/WrongBlock.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/WrongBlock.java index 1892b927..fc5f8191 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/WrongBlock.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockbreak/WrongBlock.java @@ -22,7 +22,7 @@ import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.combined.Improbable; import fr.neatmonster.nocheatplus.compat.AlmostBoolean; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.location.TrigUtil; public class WrongBlock extends Check { @@ -43,7 +43,7 @@ public class WrongBlock extends Check { * @return */ public boolean check(final Player player, final Block block, - final BlockBreakConfig cc, final BlockBreakData data, final PlayerData pData, + final BlockBreakConfig cc, final BlockBreakData data, final IPlayerData pData, final AlmostBoolean isInstaBreak) { boolean cancel = false; @@ -52,6 +52,7 @@ public class WrongBlock extends Check { final int dist = Math.min(4, data.clickedX == Integer.MAX_VALUE ? 100 : TrigUtil.manhattan(data.clickedX, data.clickedY, data.clickedZ, block)); final boolean wrongBlock; final long now = System.currentTimeMillis(); + final boolean debug = pData.isDebugActive(type); // TODO: Remove isInstaBreak argument or use it. if (dist == 0) { if (wrongTime) { @@ -65,7 +66,7 @@ public class WrongBlock extends Check { // One might to a concession in case of instant breaking. // TODO: WHY ? if (now - data.wasInstaBreak < 60) { - if (data.debug) { + if (debug) { debug(player, "Skip on Manhattan 1 and wasInstaBreak within 60 ms."); } wrongBlock = false; @@ -80,7 +81,7 @@ public class WrongBlock extends Check { } if (wrongBlock) { - if ((data.debug) && pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)) { + if ((debug) && pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)) { player.sendMessage("WrongBlock failure with dist: " + dist); } data.wrongBlockVL.add(now, (float) (dist + 1) / 2f); @@ -89,7 +90,7 @@ public class WrongBlock extends Check { if (executeActions(player, score, 1D, cc.wrongBlockActions).willCancel()) { cancel = true; } - if (Improbable.check(player, 2.0f, now, "blockbreak.wrongblock")) { + if (Improbable.check(player, 2.0f, now, "blockbreak.wrongblock", pData)) { cancel = true; } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractConfig.java index 47897d5c..5717a64d 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractConfig.java @@ -14,20 +14,12 @@ */ package fr.neatmonster.nocheatplus.checks.blockinteract; -import java.util.HashMap; -import java.util.Map; - -import org.bukkit.entity.Player; - import fr.neatmonster.nocheatplus.actions.ActionList; -import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckConfig; -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.permissions.Permissions; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Configurations specific for the block interact checks. Every world gets one of these assigned to it, or if a world @@ -35,55 +27,14 @@ import fr.neatmonster.nocheatplus.permissions.Permissions; */ public class BlockInteractConfig extends ACheckConfig { - /** The factory creating configurations. */ - public static final CheckConfigFactory factory = new CheckConfigFactory() { - @Override - public final ICheckConfig getConfig(final Player player) { - return BlockInteractConfig.getConfig(player); - } - - @Override - public void removeAllConfigs() { - clear(); // Band-aid. - } - }; - - /** The map containing the configurations per world. */ - private static final Map worldsMap = new HashMap(); - - /** - * Clear all the configurations. - */ - public static void clear() { - worldsMap.clear(); - } - - /** - * Gets the configuration for a specified player. - * - * @param player - * the player - * @return the configuration - */ - public static BlockInteractConfig getConfig(final Player player) { - if (!worldsMap.containsKey(player.getWorld().getName())) - worldsMap.put(player.getWorld().getName(), - new BlockInteractConfig(ConfigManager.getConfigFile(player.getWorld().getName()))); - return worldsMap.get(player.getWorld().getName()); - } - - public final boolean directionCheck; public final ActionList directionActions; - public final boolean reachCheck; public final ActionList reachActions; - public final boolean speedCheck; public final long speedInterval; public final int speedLimit; public final ActionList speedActions; - public final boolean visibleCheck; public final ActionList visibleActions; /** @@ -92,40 +43,19 @@ public class BlockInteractConfig extends ACheckConfig { * @param data * the data */ - public BlockInteractConfig(final ConfigFile data) { - super(data, ConfPaths.BLOCKINTERACT); - directionCheck = data.getBoolean(ConfPaths.BLOCKINTERACT_DIRECTION_CHECK); + public BlockInteractConfig(final IWorldData worldData) { + super(worldData); + final ConfigFile data = worldData.getRawConfiguration(); directionActions = data.getOptimizedActionList(ConfPaths.BLOCKINTERACT_DIRECTION_ACTIONS, Permissions.BLOCKINTERACT_DIRECTION); - reachCheck = data.getBoolean(ConfPaths.BLOCKINTERACT_REACH_CHECK); reachActions = data.getOptimizedActionList(ConfPaths.BLOCKINTERACT_REACH_ACTIONS, Permissions.BLOCKINTERACT_REACH); - speedCheck = data.getBoolean(ConfPaths.BLOCKINTERACT_SPEED_CHECK); speedInterval = data.getLong(ConfPaths.BLOCKINTERACT_SPEED_INTERVAL); speedLimit = data.getInt(ConfPaths.BLOCKINTERACT_SPEED_LIMIT); speedActions = data.getOptimizedActionList(ConfPaths.BLOCKINTERACT_SPEED_ACTIONS, Permissions.BLOCKINTERACT_SPEED); - visibleCheck = data.getBoolean(ConfPaths.BLOCKINTERACT_VISIBLE_CHECK); visibleActions = data.getOptimizedActionList(ConfPaths.BLOCKINTERACT_VISIBLE_ACTIONS, Permissions.BLOCKINTERACT_VISIBLE); } - /* (non-Javadoc) - * @see fr.neatmonster.nocheatplus.checks.ICheckConfig#isEnabled(fr.neatmonster.nocheatplus.checks.CheckType) - */ - @Override - public final boolean isEnabled(final CheckType checkType) { - switch (checkType) { - case BLOCKINTERACT_SPEED: - return speedCheck; - case BLOCKINTERACT_DIRECTION: - return directionCheck; - case BLOCKINTERACT_REACH: - return reachCheck; - case BLOCKINTERACT_VISIBLE: - return visibleCheck; - default: - return true; - } - } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractData.java index c8a8a609..2ed7d52c 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractData.java @@ -16,23 +16,17 @@ package fr.neatmonster.nocheatplus.checks.blockinteract; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Set; -import java.util.UUID; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.entity.Player; import org.bukkit.event.Event.Result; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckData; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.location.TrigUtil; @@ -41,53 +35,6 @@ import fr.neatmonster.nocheatplus.utilities.location.TrigUtil; */ public class BlockInteractData extends ACheckData { - /** The factory creating data. */ - public static final CheckDataFactory factory = new CheckDataFactory() { - @Override - public final ICheckData getData(final Player player) { - return BlockInteractData.getData(player); - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return BlockInteractData.playersMap.get(playerName); - } - - @Override - public ICheckData removeData(final String playerName) { - return BlockInteractData.removeData(playerName); - } - - @Override - public void removeAllData() { - clear(); - } - }; - - /** The map containing the data per players. */ - private static final Map playersMap = new HashMap(); - - /** - * Gets the data of a specified player. - * - * @param player - * the player - * @return the data - */ - public static BlockInteractData getData(final Player player) { - if (!playersMap.containsKey(player.getName())) - playersMap.put(player.getName(), new BlockInteractData(BlockInteractConfig.getConfig(player))); - return playersMap.get(player.getName()); - } - - public static ICheckData removeData(final String playerName) { - return playersMap.remove(playerName); - } - - public static void clear(){ - playersMap.clear(); - } - // Violation levels. public double directionVL = 0; public double reachVL = 0; @@ -136,10 +83,6 @@ public class BlockInteractData extends ACheckData { */ private final Set consumedChecks = new HashSet(); - public BlockInteractData(final BlockInteractConfig config) { - super(config); - } - /** * Set last interacted block (coordinates, type, tick). Also resets the * passed checks. diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractListener.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractListener.java index 0fa1af15..657abaf7 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractListener.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/BlockInteractListener.java @@ -37,6 +37,8 @@ import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying; import fr.neatmonster.nocheatplus.compat.Bridge1_9; import fr.neatmonster.nocheatplus.compat.BridgeHealth; import fr.neatmonster.nocheatplus.compat.BridgeMisc; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.InventoryUtil; @@ -52,8 +54,9 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; public class BlockInteractListener extends CheckListener { public static void debugBlockVSBlockInteract(final Player player, final CheckType checkType, - final Block block, final String prefix, final Action expectedAction) { - final BlockInteractData bdata = BlockInteractData.getData(player); + final Block block, final String prefix, final Action expectedAction, + final IPlayerData pData) { + final BlockInteractData bdata = pData.getGenericInstance(BlockInteractData.class); final int manhattan = bdata.manhattanLastBlock(block); String msg; if (manhattan == Integer.MAX_VALUE) { @@ -109,7 +112,8 @@ public class BlockInteractListener extends CheckListener { @EventHandler(ignoreCancelled = false, priority = EventPriority.LOWEST) public void onPlayerInteract(final PlayerInteractEvent event) { final Player player = event.getPlayer(); - final BlockInteractData data = BlockInteractData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final BlockInteractData data = pData.getGenericInstance(BlockInteractData.class); data.resetLastBlock(); // Early cancel for interact events with dead players and other. final int cancelId; @@ -168,7 +172,7 @@ public class BlockInteractListener extends CheckListener { case RIGHT_CLICK_BLOCK: stack = Bridge1_9.getUsedItem(player, event); if (stack != null && stack.getType() == Material.ENDER_PEARL) { - checkEnderPearlRightClickBlock(player, block, face, event, previousLastTick, data); + checkEnderPearlRightClickBlock(player, block, face, event, previousLastTick, data, pData); } break; default: @@ -189,16 +193,16 @@ public class BlockInteractListener extends CheckListener { } } - final BlockInteractConfig cc = BlockInteractConfig.getConfig(player); + final BlockInteractConfig cc = pData.getGenericInstance(BlockInteractConfig.class); boolean preventUseItem = false; final Location loc = player.getLocation(useLoc); - final FlyingQueueHandle flyingHandle = new FlyingQueueHandle(player); + final FlyingQueueHandle flyingHandle = new FlyingQueueHandle(pData); // TODO: Always run all checks, also for !isBlock ? // Interaction speed. - if (!cancelled && speed.isEnabled(player) + if (!cancelled && speed.isEnabled(player, pData) && speed.check(player, data, cc)) { cancelled = true; preventUseItem = true; @@ -207,27 +211,30 @@ public class BlockInteractListener extends CheckListener { if (blockChecks) { final double eyeHeight = MovingUtil.getEyeHeight(player); // First the reach check. - if (!cancelled && reach.isEnabled(player) + if (!cancelled && reach.isEnabled(player, pData) && reach.check(player, loc, eyeHeight, block, data, cc)) { cancelled = true; } // Second the direction check - if (!cancelled && direction.isEnabled(player) - && direction.check(player, loc, eyeHeight, block, flyingHandle, data, cc)) { + if (!cancelled && direction.isEnabled(player, pData) + && direction.check(player, loc, eyeHeight, block, flyingHandle, + data, cc, pData)) { cancelled = true; } // Ray tracing for freecam use etc. - if (!cancelled && visible.isEnabled(player) - && visible.check(player, loc, eyeHeight, block, face, action, flyingHandle, data, cc)) { + if (!cancelled && visible.isEnabled(player, pData) + && visible.check(player, loc, eyeHeight, block, face, action, flyingHandle, + data, cc, pData)) { cancelled = true; } } // If one of the checks requested to cancel the event, do so. if (cancelled) { - onCancelInteract(player, block, face, event, previousLastTick, preventUseItem, data, cc); + onCancelInteract(player, block, face, event, previousLastTick, preventUseItem, + data, cc, pData); } else { if (flyingHandle.isFlyingQueueFetched()) { @@ -241,7 +248,7 @@ public class BlockInteractListener extends CheckListener { cId = idInteractLookFlyingOther; } counters.add(cId, 1); - if (data.debug) { + if (pData.isDebugActive(CheckType.BLOCKINTERACT)) { // Log which entry was used. logUsedFlyingPacket(player, flyingHandle, flyingIndex); } @@ -266,11 +273,12 @@ public class BlockInteractListener extends CheckListener { private void onCancelInteract(final Player player, final Block block, final BlockFace face, final PlayerInteractEvent event, final int previousLastTick, final boolean preventUseItem, - final BlockInteractData data, final BlockInteractConfig cc) { + final BlockInteractData data, final BlockInteractConfig cc, final IPlayerData pData) { + final boolean debug = pData.isDebugActive(CheckType.BLOCKINTERACT); if (event.isCancelled()) { // Just prevent using the block. event.setUseInteractedBlock(Result.DENY); - if (data.debug) { + if (debug) { genericDebug(player, block, face, event, "already cancelled: deny use block", previousLastTick, data, cc); } } @@ -284,7 +292,7 @@ public class BlockInteractListener extends CheckListener { || !InventoryUtil.isConsumable(Bridge1_9.getUsedItem(player, event)) ) { event.setUseItemInHand(Result.DENY); - if (data.debug) { + if (debug) { genericDebug(player, block, face, event, "deny item use", previousLastTick, data, cc); } } @@ -292,7 +300,7 @@ public class BlockInteractListener extends CheckListener { // Consumable and not prevented otherwise. // TODO: Ender pearl? event.setUseItemInHand(Result.ALLOW); - if (data.debug) { + if (debug) { genericDebug(player, block, face, event, "allow edible item use", previousLastTick, data, cc); } } @@ -303,7 +311,8 @@ public class BlockInteractListener extends CheckListener { public void onPlayerInteractMonitor(final PlayerInteractEvent event) { // Set event resolution. final Player player = event.getPlayer(); - final BlockInteractData data = BlockInteractData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final BlockInteractData data = pData.getGenericInstance(BlockInteractData.class); data.setPlayerInteractEventResolution(event); /* * TODO: BlockDamageEvent fires before BlockInteract/MONITOR level, @@ -332,14 +341,14 @@ public class BlockInteractListener extends CheckListener { final ItemStack stack = Bridge1_9.getUsedItem(player, event); if (stack != null && BridgeMisc.maybeElytraBoost(player, stack.getType())) { final int power = BridgeMisc.getFireworksPower(stack); - final MovingData mData = MovingData.getData(player); + final MovingData mData = pData.getGenericInstance(MovingData.class); final int ticks = Math.max((1 + power) * 20, 30); mData.fireworksBoostDuration = ticks; // Expiration tick: not general latency, rather a minimum margin for sudden congestion. mData.fireworksBoostTickExpire = TickTask.getTick() + ticks; // TODO: Invalidation mechanics: by tick/time well ? // TODO: Implement using it in CreativeFly. - if (data.debug) { + if (pData.isDebugActive(CheckType.MOVING)) { debug(player, "Elytra boost (power " + power + "): " + stack); } } @@ -348,13 +357,14 @@ public class BlockInteractListener extends CheckListener { private void checkEnderPearlRightClickBlock(final Player player, final Block block, final BlockFace face, final PlayerInteractEvent event, - final int previousLastTick, final BlockInteractData data) { + final int previousLastTick, final BlockInteractData data, + final IPlayerData pData) { if (block == null || !BlockProperties.isPassable(block.getType())) { - final CombinedConfig ccc = CombinedConfig.getConfig(player); + final CombinedConfig ccc = pData.getGenericInstance(CombinedConfig.class); if (ccc.enderPearlCheck && ccc.enderPearlPreventClickBlock) { event.setUseItemInHand(Result.DENY); - if (data.debug) { - final BlockInteractConfig cc = BlockInteractConfig.getConfig(player); + if (pData.isDebugActive(CheckType.BLOCKINTERACT)) { + final BlockInteractConfig cc = pData.getGenericInstance(BlockInteractConfig.class); genericDebug(player, block, face, event, "click block: deny use ender pearl", previousLastTick, data, cc); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/Visible.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/Visible.java index 6603af34..9d685dc4 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/Visible.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockinteract/Visible.java @@ -29,6 +29,7 @@ import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; import fr.neatmonster.nocheatplus.checks.net.FlyingQueueHandle; import fr.neatmonster.nocheatplus.checks.net.FlyingQueueLookBlockChecker; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.collision.InteractRayTracing; import fr.neatmonster.nocheatplus.utilities.location.TrigUtil; @@ -113,7 +114,8 @@ public class Visible extends Check { public boolean check(final Player player, final Location loc, final double eyeHeight, final Block block, final BlockFace face, final Action action, final FlyingQueueHandle flyingHandle, - final BlockInteractData data, final BlockInteractConfig cc) { + final BlockInteractData data, final BlockInteractConfig cc, + final IPlayerData pData) { // TODO: This check might make parts of interact/blockbreak/... + direction (+?) obsolete. // TODO: Might confine what to check for (left/right-click, target blocks depending on item in hand, container blocks). boolean collides; @@ -124,6 +126,8 @@ public class Visible extends Check { final double eyeY = loc.getY() + eyeHeight; final double eyeZ = loc.getZ(); + final boolean debug = pData.isDebugActive(type); + tags.clear(); if (TrigUtil.isSameBlock(blockX, blockY, blockZ, eyeX, eyeY, eyeZ)) { // Player is interacting with the block their head is in. @@ -137,7 +141,7 @@ public class Visible extends Check { blockCache.setAccess(loc.getWorld()); rayTracing.setBlockCache(blockCache); collides = !checker.checkFlyingQueue(eyeX, eyeY, eyeZ, loc.getYaw(), loc.getPitch(), - blockX, blockY, blockZ, flyingHandle, face, tags, data.debug, player); + blockX, blockY, blockZ, flyingHandle, face, tags, debug, player); checker.cleanup(); useLoc.setWorld(null); // Cleanup. @@ -161,7 +165,7 @@ public class Visible extends Check { else { data.visibleVL *= 0.99; data.addPassedCheck(this.type); - if (data.debug) { + if (debug) { debug(player, "pitch=" + loc.getPitch() + ",yaw=" + loc.getYaw() + " tags=" + StringUtil.join(tags, "+")); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/Against.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/Against.java index d2a9013a..beecb32d 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/Against.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/Against.java @@ -25,7 +25,7 @@ import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; import fr.neatmonster.nocheatplus.checks.blockinteract.BlockInteractData; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; /** * Check if the placing is legitimate in terms of surrounding materials. @@ -40,16 +40,16 @@ public class Against extends Check { public boolean check(final Player player, final Block block, final Material placedMat, final Block blockAgainst, final boolean isInteractBlock, - final BlockPlaceData data, final BlockPlaceConfig cc, final PlayerData pData) { + final BlockPlaceData data, final BlockPlaceConfig cc, final IPlayerData pData) { boolean violation = false; // TODO: Make more precise (workarounds like WATER_LILY, general points, such as action?). // Workaround for signs on cactus and similar. - final BlockInteractData bdata = BlockInteractData.getData(player); // TODO: pass as argument. + final BlockInteractData bdata = pData.getGenericInstance(BlockInteractData.class); // TODO: pass as argument. final Material againstType = blockAgainst.getType(); if (bdata.isConsumedCheck(this.type) && !bdata.isPassedCheck(this.type)) { // TODO: Awareness of repeated violation probably is to be implemented below somewhere. violation = true; - if (data.debug) { + if (pData.isDebugActive(type)) { debug(player, "Cancel due to block having been consumed by this check."); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/AutoSign.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/AutoSign.java index 75cd9257..4c6f70a2 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/AutoSign.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/AutoSign.java @@ -27,6 +27,7 @@ import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.TickTask; @@ -50,19 +51,20 @@ public class AutoSign extends Check { super(CheckType.BLOCKPLACE_AUTOSIGN); } - public boolean check(final Player player, final Block block, final String[] lines) { + public boolean check(final Player player, final Block block, final String[] lines, + final IPlayerData pData) { // TODO: Might want to reset time + hash ? final long time = System.currentTimeMillis(); tags.clear(); - final BlockPlaceData data = BlockPlaceData.getData(player); - final BlockPlaceConfig cc = BlockPlaceConfig.getConfig(player); + final BlockPlaceData data = pData.getGenericInstance(BlockPlaceData.class); + final BlockPlaceConfig cc = pData.getGenericInstance(BlockPlaceConfig.class); Material mat = block.getType(); if (mat == Material.SIGN_POST || mat == Material.WALL_SIGN) { mat = Material.SIGN; } if (data.autoSignPlacedHash != BlockPlaceListener.getBlockPlaceHash(block, mat)){ tags.add("block_mismatch"); - return handleViolation(player, maxEditTime, data); + return handleViolation(player, maxEditTime, data, cc); } if (time < data.autoSignPlacedTime){ data.autoSignPlacedTime = 0; @@ -80,7 +82,7 @@ public class AutoSign extends Check { if (expected > editTime){ tags.add("edit_time"); - return handleViolation(player, expected - editTime, data); + return handleViolation(player, expected - editTime, data, cc); } return false; } @@ -117,10 +119,12 @@ public class AutoSign extends Check { * @param data * @return */ - private boolean handleViolation(final Player player, final long violationTime, final BlockPlaceData data) { + private boolean handleViolation(final Player player, final long violationTime, + final BlockPlaceData data, final BlockPlaceConfig cc) { final double addedVL = 10.0 * Math.min(maxEditTime, violationTime) / maxEditTime; data.autoSignVL += addedVL; - final ViolationData vd = new ViolationData(this, player, data.autoSignVL, addedVL, BlockPlaceConfig.getConfig(player).autoSignActions); + final ViolationData vd = new ViolationData( + this, player, data.autoSignVL, addedVL, cc.autoSignActions); if (vd.needsParameters()){ vd.setParameter(ParameterName.TAGS, StringUtil.join(tags, "+")); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceConfig.java index 83224227..fcbdef76 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceConfig.java @@ -14,23 +14,17 @@ */ package fr.neatmonster.nocheatplus.checks.blockplace; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Set; import org.bukkit.Material; -import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.actions.ActionList; -import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckConfig; -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.permissions.Permissions; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Configurations specific for the block place checks. Every world gets one of these assigned to it, or if a world @@ -38,67 +32,23 @@ import fr.neatmonster.nocheatplus.permissions.Permissions; */ public class BlockPlaceConfig extends ACheckConfig { - /** The factory creating configurations. */ - public static final CheckConfigFactory factory = new CheckConfigFactory() { - @Override - public final ICheckConfig getConfig(final Player player) { - return BlockPlaceConfig.getConfig(player); - } - - @Override - public void removeAllConfigs() { - clear(); // Band-aid. - } - }; - - /** The map containing the configurations per world. */ - private static final Map worldsMap = new HashMap(); - - /** - * Clear all the configurations. - */ - public static void clear() { - worldsMap.clear(); - } - - /** - * Gets the configuration for a specified player. - * - * @param player - * the player - * @return the configuration - */ - public static BlockPlaceConfig getConfig(final Player player) { - if (!worldsMap.containsKey(player.getWorld().getName())) - worldsMap.put(player.getWorld().getName(), - new BlockPlaceConfig(ConfigManager.getConfigFile(player.getWorld().getName()))); - return worldsMap.get(player.getWorld().getName()); - } - - public final boolean againstCheck; public final ActionList againstActions; - public final boolean autoSignCheck; public final boolean autoSignSkipEmpty; public final ActionList autoSignActions; - public final boolean directionCheck; public final ActionList directionActions; - public final boolean fastPlaceCheck; public final int fastPlaceLimit; public final int fastPlaceShortTermTicks; public final int fastPlaceShortTermLimit; public final ActionList fastPlaceActions; - public final boolean noSwingCheck; public final Set noSwingExceptions = new HashSet(); public final ActionList noSwingActions; - public final boolean reachCheck; public final ActionList reachActions; - public final boolean speedCheck; public final long speedInterval; public final ActionList speedActions; @@ -111,34 +61,28 @@ public class BlockPlaceConfig extends ACheckConfig { * @param config * */ - public BlockPlaceConfig(final ConfigFile config) { - super(config, ConfPaths.BLOCKPLACE); + public BlockPlaceConfig(final IWorldData worldData) { + super(worldData); + final ConfigFile config = worldData.getRawConfiguration(); - againstCheck = config.getBoolean(ConfPaths.BLOCKPLACE_AGAINST_CHECK); againstActions = config.getOptimizedActionList(ConfPaths.BLOCKPLACE_AGAINST_ACTIONS, Permissions.BLOCKPLACE_AGAINST); - autoSignCheck = config.getBoolean(ConfPaths.BLOCKPLACE_AUTOSIGN_CHECK); autoSignSkipEmpty = config.getBoolean(ConfPaths.BLOCKPLACE_AUTOSIGN_SKIPEMPTY); autoSignActions = config.getOptimizedActionList(ConfPaths.BLOCKPLACE_AUTOSIGN_ACTIONS, Permissions.BLOCKPLACE_AUTOSIGN); - directionCheck = config.getBoolean(ConfPaths.BLOCKPLACE_DIRECTION_CHECK); directionActions = config.getOptimizedActionList(ConfPaths.BLOCKPLACE_DIRECTION_ACTIONS, Permissions.BLOCKPLACE_DIRECTION); - fastPlaceCheck = config.getBoolean(ConfPaths.BLOCKPLACE_FASTPLACE_CHECK); fastPlaceLimit = config.getInt(ConfPaths.BLOCKPLACE_FASTPLACE_LIMIT); fastPlaceShortTermTicks = config.getInt(ConfPaths.BLOCKPLACE_FASTPLACE_SHORTTERM_TICKS); fastPlaceShortTermLimit = config.getInt(ConfPaths.BLOCKPLACE_FASTPLACE_SHORTTERM_LIMIT); fastPlaceActions = config.getOptimizedActionList(ConfPaths.BLOCKPLACE_FASTPLACE_ACTIONS, Permissions.BLOCKPLACE_FASTPLACE); - noSwingCheck = config.getBoolean(ConfPaths.BLOCKPLACE_NOSWING_CHECK); config.readMaterialFromList(ConfPaths.BLOCKPLACE_NOSWING_EXCEPTIONS, noSwingExceptions); noSwingActions = config.getOptimizedActionList(ConfPaths.BLOCKPLACE_NOSWING_ACTIONS, Permissions.BLOCKPLACE_NOSWING); - reachCheck = config.getBoolean(ConfPaths.BLOCKPLACE_REACH_CHECK); reachActions = config.getOptimizedActionList(ConfPaths.BLOCKPLACE_REACH_ACTIONS, Permissions.BLOCKPLACE_REACH); - speedCheck = config.getBoolean(ConfPaths.BLOCKPLACE_SPEED_CHECK); speedInterval = config.getLong(ConfPaths.BLOCKPLACE_SPEED_INTERVAL); speedActions = config.getOptimizedActionList(ConfPaths.BLOCKPLACE_SPEED_ACTIONS, Permissions.BLOCKPLACE_SPEED); @@ -152,28 +96,4 @@ public class BlockPlaceConfig extends ACheckConfig { */ } - /* (non-Javadoc) - * @see fr.neatmonster.nocheatplus.checks.ICheckConfig#isEnabled(fr.neatmonster.nocheatplus.checks.CheckType) - */ - @Override - public final boolean isEnabled(final CheckType checkType) { - switch (checkType) { - case BLOCKPLACE_DIRECTION: - return directionCheck; - case BLOCKPLACE_FASTPLACE: - return fastPlaceCheck; - case BLOCKPLACE_NOSWING: - return noSwingCheck; - case BLOCKPLACE_REACH: - return reachCheck; - case BLOCKPLACE_SPEED: - return speedCheck; - case BLOCKPLACE_AGAINST: - return againstCheck; - case BLOCKPLACE_AUTOSIGN: - return autoSignCheck; - default: - return true; - } - } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceData.java index 9426abf0..de9f8771 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceData.java @@ -14,15 +14,7 @@ */ package fr.neatmonster.nocheatplus.checks.blockplace; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import org.bukkit.entity.Player; - import fr.neatmonster.nocheatplus.checks.access.ACheckData; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; /** @@ -30,53 +22,6 @@ import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; */ public class BlockPlaceData extends ACheckData { - /** The factory creating data. */ - public static final CheckDataFactory factory = new CheckDataFactory() { - @Override - public final ICheckData getData(final Player player) { - return BlockPlaceData.getData(player); - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return BlockPlaceData.playersMap.get(playerName); - } - - @Override - public ICheckData removeData(final String playerName) { - return BlockPlaceData.removeData(playerName); - } - - @Override - public void removeAllData() { - clear(); - } - }; - - /** The map containing the data per players. */ - private static final Map playersMap = new HashMap(); - - /** - * Gets the data of a specified player. - * - * @param player - * the player - * @return the data - */ - public static BlockPlaceData getData(final Player player) { - if (!playersMap.containsKey(player.getName())) - playersMap.put(player.getName(), new BlockPlaceData(BlockPlaceConfig.getConfig(player))); - return playersMap.get(player.getName()); - } - - public static ICheckData removeData(final String playerName) { - return playersMap.remove(playerName); - } - - public static void clear(){ - playersMap.clear(); - } - // Violation levels. public double againstVL = 0; public double autoSignVL = 0; @@ -106,8 +51,4 @@ public class BlockPlaceData extends ACheckData { public boolean speedLastRefused; public long speedLastTime; - public BlockPlaceData(final BlockPlaceConfig config) { - super (config); - } - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceListener.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceListener.java index b51ce93b..d620e046 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceListener.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/BlockPlaceListener.java @@ -49,7 +49,7 @@ import fr.neatmonster.nocheatplus.compat.Bridge1_9; import fr.neatmonster.nocheatplus.compat.BridgeMisc; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.InventoryUtil; import fr.neatmonster.nocheatplus.utilities.ReflectionUtil; @@ -153,14 +153,15 @@ public class BlockPlaceListener extends CheckListener { } boolean cancelled = false; - final PlayerData pData = DataManager.getPlayerData(player); // TODO: Use for data + config getting etc. - final BlockPlaceData data = BlockPlaceData.getData(player); - final BlockPlaceConfig cc = BlockPlaceConfig.getConfig(player); - final BlockInteractData bdata = BlockInteractData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); // TODO: Use for data + config getting etc. + final BlockPlaceData data = pData.getGenericInstance(BlockPlaceData.class); + final BlockPlaceConfig cc = pData.getGenericInstance(BlockPlaceConfig.class); + final BlockInteractData bdata = pData.getGenericInstance(BlockInteractData.class); final int tick = TickTask.getTick(); // isInteractBlock - the block placed against is the block last interacted with. final boolean isInteractBlock = !bdata.getLastIsCancelled() && bdata.matchesLastBlock(tick, blockAgainst); int skippedRedundantChecks = 0; + final boolean debug = pData.isDebugActive(CheckType.BLOCKPLACE); final boolean shouldSkipSome; if (blockMultiPlaceEvent != null && event.getClass() == blockMultiPlaceEvent) { @@ -169,7 +170,7 @@ public class BlockPlaceListener extends CheckListener { shouldSkipSome = true; } else { - if (data.debug) { + if (debug) { debug(player, "Block place " + event.getClass().getName() + " " + placedMat); } shouldSkipSome = false; @@ -187,31 +188,33 @@ public class BlockPlaceListener extends CheckListener { } // Don't run checks, if a set back is scheduled. - if (!cancelled && MovingUtil.hasScheduledPlayerSetBack(player)) { + if (!cancelled && pData.isPlayerSetBackScheduled()) { cancelled = true; } // Fast place check. - if (!cancelled && fastPlace.isEnabled(player)) { - if (fastPlace.check(player, block, tick, data, cc)) { + if (!cancelled && fastPlace.isEnabled(player, pData)) { + if (fastPlace.check(player, block, tick, data, cc, pData)) { cancelled = true; } else { // Feed the improbable. - Improbable.feed(player, 0.5f, System.currentTimeMillis()); + Improbable.feed(player, 0.5f, System.currentTimeMillis(), pData); } } // No swing check (player doesn't swing their arm when placing a lily pad). if (!cancelled && !cc.noSwingExceptions.contains(placedMat) - && noSwing.isEnabled(player) && noSwing.check(player, data, cc)) { + && noSwing.isEnabled(player, pData) && noSwing.check(player, data, cc)) { // Consider skipping all insta placables or using simplified version (true or true within time frame). cancelled = true; } final FlyingQueueHandle flyingHandle; - if (cc.reachCheck || cc.directionCheck) { - flyingHandle = new FlyingQueueHandle(player); + final boolean reachCheck = pData.isCheckActive(CheckType.BLOCKPLACE_REACH, player); + final boolean directionCheck = pData.isCheckActive(CheckType.BLOCKPLACE_DIRECTION, player); + if (reachCheck || directionCheck) { + flyingHandle = new FlyingQueueHandle(pData); final Location loc = player.getLocation(useLoc); final double eyeHeight = MovingUtil.getEyeHeight(player); // Reach check (distance). @@ -219,7 +222,7 @@ public class BlockPlaceListener extends CheckListener { if (isInteractBlock && bdata.isPassedCheck(CheckType.BLOCKINTERACT_REACH)) { skippedRedundantChecks ++; } - else if (reach.isEnabled(player) && reach.check(player, eyeHeight, block, data, cc)) { + else if (reachCheck && reach.check(player, eyeHeight, block, data, cc)) { cancelled = true; } } @@ -229,8 +232,8 @@ public class BlockPlaceListener extends CheckListener { if (isInteractBlock && bdata.isPassedCheck(CheckType.BLOCKINTERACT_DIRECTION)) { skippedRedundantChecks ++; } - else if (direction.isEnabled(player) && direction.check(player, loc, eyeHeight, block, - flyingHandle, data, cc)) { + else if (directionCheck && direction.check(player, loc, eyeHeight, block, + flyingHandle, data, cc, pData)) { cancelled = true; } } @@ -241,7 +244,7 @@ public class BlockPlaceListener extends CheckListener { } // Surrounding material. - if (!cancelled && against.isEnabled(player) && against.check(player, block, placedMat, blockAgainst, + if (!cancelled && against.isEnabled(player, pData) && against.check(player, block, placedMat, blockAgainst, isInteractBlock, data, cc, pData)) { cancelled = true; } @@ -252,8 +255,9 @@ public class BlockPlaceListener extends CheckListener { } else { // Debug log (only if not cancelled, to avoid spam). - if (data.debug) { - debugBlockPlace(player, placedMat, block, blockAgainst, skippedRedundantChecks, flyingHandle); + if (debug) { + debugBlockPlace(player, placedMat, block, blockAgainst, + skippedRedundantChecks, flyingHandle, pData); } } // Cleanup @@ -262,10 +266,12 @@ public class BlockPlaceListener extends CheckListener { private void debugBlockPlace(final Player player, final Material placedMat, final Block block, final Block blockAgainst, - final int skippedRedundantChecks, final FlyingQueueHandle flyingHandle) { + final int skippedRedundantChecks, final FlyingQueueHandle flyingHandle, + final IPlayerData pData) { debug(player, "Block place(" + placedMat + "): " + block.getX() + ", " + block.getY() + ", " + block.getZ()); - BlockInteractListener.debugBlockVSBlockInteract(player, checkType, blockAgainst, "onBlockPlace(blockAgainst)", - Action.RIGHT_CLICK_BLOCK); + BlockInteractListener.debugBlockVSBlockInteract(player, checkType, + blockAgainst, "onBlockPlace(blockAgainst)", Action.RIGHT_CLICK_BLOCK, + pData); if (skippedRedundantChecks > 0) { debug(player, "Skipped redundant checks: " + skippedRedundantChecks); } @@ -293,7 +299,8 @@ public class BlockPlaceListener extends CheckListener { // Somewhat defensive. return; } - if (autoSign.isEnabled(player) && autoSign.check(player, block, lines)) { + final IPlayerData pData = DataManager.getPlayerData(player); + if (autoSign.isEnabled(player, pData) && autoSign.check(player, block, lines, pData)) { event.setCancelled(true); } } @@ -309,7 +316,7 @@ public class BlockPlaceListener extends CheckListener { priority = EventPriority.MONITOR) public void onPlayerAnimation(final PlayerAnimationEvent event) { // Just set a flag to true when the arm was swung. - BlockPlaceData.getData(event.getPlayer()).noSwingArmSwung = true; + DataManager.getPlayerData(event.getPlayer()).getGenericInstance(BlockPlaceData.class).noSwingArmSwung = true; } /** @@ -334,11 +341,11 @@ public class BlockPlaceListener extends CheckListener { return; } - final BlockPlaceConfig cc = BlockPlaceConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final BlockPlaceConfig cc = pData.getGenericInstance(BlockPlaceConfig.class); final Material type = stack.getType(); if (InventoryUtil.isBoat(type)) { if (cc.preventBoatsAnywhere) { - final PlayerData pData = DataManager.getPlayerData(player); // TODO: Use for data + config getting etc. // TODO: Alter config (activation, allow on top of ground). // TODO: Version/plugin specific alteration for 'default'. checkBoatsAnywhere(player, event, cc, pData); @@ -346,7 +353,7 @@ public class BlockPlaceListener extends CheckListener { } else if (type == Material.MONSTER_EGG) { // Check blockplace.speed. - if (speed.isEnabled(player, cc) && speed.check(player, cc)) { + if (speed.isEnabled(player, pData) && speed.check(player, cc, pData)) { // If the check was positive, cancel the event. event.setCancelled(true); } @@ -354,7 +361,7 @@ public class BlockPlaceListener extends CheckListener { } private void checkBoatsAnywhere(final Player player, final PlayerInteractEvent event, - final BlockPlaceConfig cc, final PlayerData pData) { + final BlockPlaceConfig cc, final IPlayerData pData) { // Check boats-anywhere. final Block block = event.getClickedBlock(); final Material mat = block.getType(); @@ -426,20 +433,21 @@ public class BlockPlaceListener extends CheckListener { } // Do the actual check... - final BlockPlaceConfig cc = BlockPlaceConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final BlockPlaceConfig cc = pData.getGenericInstance(BlockPlaceConfig.class); boolean cancel = false; - if (speed.isEnabled(player)) { + if (speed.isEnabled(player, pData)) { final long now = System.currentTimeMillis(); final Location loc = player.getLocation(useLoc); - if (Combined.checkYawRate(player, loc.getYaw(), now, loc.getWorld().getName())) { + if (Combined.checkYawRate(player, loc.getYaw(), now, loc.getWorld().getName(), pData)) { // Yawrate (checked extra). cancel = true; } - if (speed.check(player, cc)) { + if (speed.check(player, cc, pData)) { // If the check was positive, cancel the event. cancel = true; } - else if (Improbable.check(player, 0.6f, now, "blockplace.speed")) { + else if (Improbable.check(player, 0.6f, now, "blockplace.speed", pData)) { // Combined fighting speed. cancel = true; } @@ -447,7 +455,7 @@ public class BlockPlaceListener extends CheckListener { // Ender pearl glitch (ab-) use. if (!cancel && type == EntityType.ENDER_PEARL) { - if (!CombinedConfig.getConfig(player).enderPearlCheck) { + if (!pData.getGenericInstance(CombinedConfig.class).enderPearlCheck) { // Do nothing ! // TODO: Might have further flags? } @@ -468,7 +476,9 @@ public class BlockPlaceListener extends CheckListener { final long flags = BlockProperties.F_CLIMBABLE | BlockProperties.F_LIQUID | BlockProperties.F_IGN_PASSABLE; if (!BlockProperties.isAir(mat) && (BlockProperties.getBlockFlags(mat) & flags) == 0 && !mcAccess.getHandle().hasGravity(mat)) { // Still fails on piston traps etc. - if (!BlockProperties.isPassable(player.getLocation(), projectile.getLocation()) && !BlockProperties.isOnGroundOrResetCond(player, player.getLocation(), MovingConfig.getConfig(player).yOnGround)) { + if (!BlockProperties.isPassable(player.getLocation(), projectile.getLocation()) + && !BlockProperties.isOnGroundOrResetCond(player, player.getLocation(), + pData.getGenericInstance(MovingConfig.class).yOnGround)) { cancel = true; } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/FastPlace.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/FastPlace.java index 2bdf2c15..321f5fb5 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/FastPlace.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/FastPlace.java @@ -19,6 +19,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.TickTask; /** @@ -44,9 +45,11 @@ public class FastPlace extends Check { * @return true, if successful */ public boolean check(final Player player, final Block block, final int tick, - final BlockPlaceData data, final BlockPlaceConfig cc) { + final BlockPlaceData data, final BlockPlaceConfig cc, + final IPlayerData pData) { data.fastPlaceBuckets.add(System.currentTimeMillis(), 1f); + final boolean lag = pData.getCurrentWorldData().shouldAdjustToLag(type); // Full period frequency. final float fullScore = data.fastPlaceBuckets.score(1f); @@ -59,7 +62,7 @@ public class FastPlace extends Check { } else if (tick - data.fastPlaceShortTermTick < cc.fastPlaceShortTermTicks){ // Account for server side lag. - if (!cc.lag || TickTask.getLag(50L * (tick - data.fastPlaceShortTermTick), true) < 1.2f){ + if (!lag || TickTask.getLag(50L * (tick - data.fastPlaceShortTermTick), true) < 1.2f){ // Within range, add. data.fastPlaceShortTermCount ++; } @@ -78,7 +81,7 @@ public class FastPlace extends Check { final float fullViolation; if (fullScore > cc.fastPlaceLimit) { // Account for server side lag. - if (cc.lag) { + if (lag) { fullViolation = fullScore / TickTask.getLag(data.fastPlaceBuckets.bucketDuration() * data.fastPlaceBuckets.numberOfBuckets(), true) - cc.fastPlaceLimit; } else{ diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/Speed.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/Speed.java index 31b7343d..c4b908bc 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/Speed.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/blockplace/Speed.java @@ -18,6 +18,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * This check verifies if the player isn't throwing items too quickly, like eggs or arrows. @@ -39,8 +40,9 @@ public class Speed extends Check { * @param cc * @return true, if successful */ - public boolean check(final Player player, final BlockPlaceConfig cc) { - final BlockPlaceData data = BlockPlaceData.getData(player); + public boolean check(final Player player, + final BlockPlaceConfig cc, final IPlayerData pData) { + final BlockPlaceData data = pData.getGenericInstance(BlockPlaceData.class); boolean cancel = false; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Captcha.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Captcha.java index 6b60cb19..6ded5874 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Captcha.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Captcha.java @@ -20,9 +20,8 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.ColorUtil; @@ -91,14 +90,15 @@ public class Captcha extends Check implements ICaptcha{ @Override public void resetCaptcha(Player player){ - ChatData data = ChatData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + ChatData data = pData.getGenericInstance(ChatData.class); synchronized (data) { - resetCaptcha(player, ChatConfig.getConfig(player), data, DataManager.getPlayerData(player)); + resetCaptcha(player, pData.getGenericInstance(ChatConfig.class), data, pData); } } @Override - public void resetCaptcha(Player player, ChatConfig cc, ChatData data, PlayerData pData){ + public void resetCaptcha(Player player, ChatConfig cc, ChatData data, IPlayerData pData){ data.captchTries = 0; if (shouldCheckCaptcha(player, cc, data, pData) || shouldStartCaptcha(player, cc, data, pData)){ @@ -113,12 +113,15 @@ public class Captcha extends Check implements ICaptcha{ } @Override - public boolean shouldStartCaptcha(Player player, ChatConfig cc, ChatData data, PlayerData pData) { - return cc.captchaCheck && !data.captchaStarted && !pData.hasPermission(Permissions.CHAT_CAPTCHA, player); + public boolean shouldStartCaptcha(Player player, ChatConfig cc, ChatData data, IPlayerData pData) { + // TODO: Only call if IWorldData.isCheckActive(CHAT_CAPTCHA) has returned true? + return !data.captchaStarted && pData.isCheckActive(CheckType.CHAT_CAPTCHA, player); } @Override - public boolean shouldCheckCaptcha(Player player, ChatConfig cc, ChatData data, PlayerData pData) { - return cc.captchaCheck && data.captchaStarted && !pData.hasPermission(Permissions.CHAT_CAPTCHA, player); + public boolean shouldCheckCaptcha(Player player, ChatConfig cc, ChatData data, IPlayerData pData) { + // TODO: Only call if IWorldData.isCheckActive(CHAT_CAPTCHA) has returned true? + return data.captchaStarted && pData.isCheckActive(CheckType.CHAT_CAPTCHA, player); } + } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatConfig.java index cc7243a8..59edd110 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatConfig.java @@ -14,23 +14,15 @@ */ package fr.neatmonster.nocheatplus.checks.chat; -import java.util.HashMap; -import java.util.Map; - -import org.bukkit.entity.Player; - import fr.neatmonster.nocheatplus.actions.ActionList; -import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckConfig; -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; import fr.neatmonster.nocheatplus.checks.chat.analysis.engine.EnginePlayerConfig; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; import fr.neatmonster.nocheatplus.utilities.ColorUtil; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Configurations specific for the "chat" checks. Every world gets one of these assigned to it, or if a world doesn't @@ -38,20 +30,8 @@ import fr.neatmonster.nocheatplus.utilities.ColorUtil; */ public class ChatConfig extends ACheckConfig { - /** The factory creating configurations. */ - public static final CheckConfigFactory factory = new CheckConfigFactory() { - @Override - public final ICheckConfig getConfig(final Player player) { - return ChatConfig.getConfig(player); - } - @Override - public void removeAllConfigs() { - clear(); // Band-aid. - } - }; - - private static RegisteredPermission[] preferKeepUpdatedPermissions = new RegisteredPermission[]{ + private static final RegisteredPermission[] preferKeepUpdatedPermissions = new RegisteredPermission[]{ // Only the permissions needed for async. checking. Permissions.CHAT_COLOR, Permissions.CHAT_TEXT, @@ -59,39 +39,10 @@ public class ChatConfig extends ACheckConfig { // TODO: COMMANDS, in case of handleascommand? }; - /** The map containing the configurations per world. */ - private static final Map worldsMap = new HashMap(); - public static RegisteredPermission[] getPreferKeepUpdatedPermissions() { return preferKeepUpdatedPermissions; } - /** - * Clear all the configurations. - */ - public static void clear() { - synchronized (worldsMap) { - worldsMap.clear(); - } - } - - /** - * Gets the configuration for a specified player. - * - * @param player - * the player - * @return the configuration - */ - public static ChatConfig getConfig(final Player player) { - synchronized (worldsMap) { - if (!worldsMap.containsKey(player.getWorld().getName())) - worldsMap.put(player.getWorld().getName(), - new ChatConfig(ConfigManager.getConfigFile(player.getWorld().getName()))); - return worldsMap.get(player.getWorld().getName()); - } - } - - public final boolean captchaCheck; public final boolean captchaSkipCommands; public final String captchaCharacters; public final int captchaLength; @@ -100,16 +51,14 @@ public class ChatConfig extends ACheckConfig { public final int captchaTries; public final ActionList captchaActions; - public final boolean colorCheck; public final ActionList colorActions; - public final boolean commandsCheck; public final double commandsLevel; public final int commandsShortTermTicks; public final double commandsShortTermLevel; public final ActionList commandsActions; - public final boolean textCheck; + // TODO: Sub check types ? public final boolean textGlobalCheck; public final boolean textPlayerCheck; public final EnginePlayerConfig textEnginePlayerConfig; @@ -147,7 +96,6 @@ public class ChatConfig extends ACheckConfig { public final String chatWarningMessage; public final long chatWarningTimeout; - public final boolean loginsCheck; public final boolean loginsPerWorldCount; public final int loginsSeconds; public final int loginsLimit; @@ -157,8 +105,6 @@ public class ChatConfig extends ACheckConfig { public final boolean consoleOnlyCheck; public final String consoleOnlyMessage; - - public final boolean relogCheck; public final String relogKickMessage; public final long relogTimeout; public final String relogWarningMessage; @@ -172,10 +118,10 @@ public class ChatConfig extends ACheckConfig { * @param config * the data */ - public ChatConfig(final ConfigFile config) { - super(config, ConfPaths.CHAT); + public ChatConfig(final IWorldData worldData) { + super(worldData); + final ConfigFile config = worldData.getRawConfiguration(); - captchaCheck = config.getBoolean(ConfPaths.CHAT_CAPTCHA_CHECK); captchaSkipCommands = config.getBoolean(ConfPaths.CHAT_CAPTCHA_SKIP_COMMANDS); captchaCharacters = config.getString(ConfPaths.CHAT_CAPTCHA_CHARACTERS); captchaLength = config.getInt(ConfPaths.CHAT_CAPTCHA_LENGTH); @@ -184,17 +130,13 @@ public class ChatConfig extends ACheckConfig { captchaTries = config.getInt(ConfPaths.CHAT_CAPTCHA_TRIES); captchaActions = config.getOptimizedActionList(ConfPaths.CHAT_CAPTCHA_ACTIONS, Permissions.CHAT_CAPTCHA); - colorCheck = config.getBoolean(ConfPaths.CHAT_COLOR_CHECK); colorActions = config.getOptimizedActionList(ConfPaths.CHAT_COLOR_ACTIONS, Permissions.CHAT_COLOR); - commandsCheck = config.getBoolean(ConfPaths.CHAT_COMMANDS_CHECK); commandsLevel = config.getDouble(ConfPaths.CHAT_COMMANDS_LEVEL); commandsShortTermTicks = config.getInt(ConfPaths.CHAT_COMMANDS_SHORTTERM_TICKS); commandsShortTermLevel = config.getDouble(ConfPaths.CHAT_COMMANDS_SHORTTERM_LEVEL);; commandsActions = config.getOptimizedActionList(ConfPaths.CHAT_COMMANDS_ACTIONS, Permissions.CHAT_COMMANDS); - - textCheck = config.getBoolean(ConfPaths.CHAT_TEXT_CHECK); textGlobalCheck = config.getBoolean(ConfPaths.CHAT_TEXT_GL_CHECK, true); textPlayerCheck = config.getBoolean(ConfPaths.CHAT_TEXT_PP_CHECK, true); textEnginePlayerConfig = new EnginePlayerConfig(config); @@ -231,14 +173,12 @@ public class ChatConfig extends ACheckConfig { chatWarningMessage = config.getString(ConfPaths.CHAT_WARNING_MESSAGE); chatWarningTimeout = config.getLong(ConfPaths.CHAT_WARNING_TIMEOUT) * 1000; - loginsCheck = config.getBoolean(ConfPaths.CHAT_LOGINS_CHECK); loginsPerWorldCount = config.getBoolean(ConfPaths.CHAT_LOGINS_PERWORLDCOUNT); loginsSeconds = config.getInt(ConfPaths.CHAT_LOGINS_SECONDS); loginsLimit = config.getInt(ConfPaths.CHAT_LOGINS_LIMIT); loginsKickMessage = config.getString(ConfPaths.CHAT_LOGINS_KICKMESSAGE); loginsStartupDelay = config.getInt(ConfPaths.CHAT_LOGINS_STARTUPDELAY) * 1000; - relogCheck = config.getBoolean(ConfPaths.CHAT_RELOG_CHECK); relogKickMessage = config.getString(ConfPaths.CHAT_RELOG_KICKMESSAGE); relogTimeout = config.getLong(ConfPaths.CHAT_RELOG_TIMEOUT); relogWarningMessage = config.getString(ConfPaths.CHAT_RELOG_WARNING_MESSAGE); @@ -251,26 +191,4 @@ public class ChatConfig extends ACheckConfig { } - /* (non-Javadoc) - * @see fr.neatmonster.nocheatplus.checks.ICheckConfig#isEnabled(fr.neatmonster.nocheatplus.checks.CheckType) - */ - @Override - public boolean isEnabled(final CheckType checkType) { - switch (checkType) { - case CHAT_COLOR: - return colorCheck; - case CHAT_TEXT: - return textCheck; - case CHAT_COMMANDS: - return commandsCheck; - case CHAT_CAPTCHA: - return captchaCheck; - case CHAT_RELOG: - return relogCheck; - case CHAT_LOGINS: - return loginsCheck; - default: - return true; - } - } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatData.java index 2d9799d5..b4facad6 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatData.java @@ -14,68 +14,13 @@ */ package fr.neatmonster.nocheatplus.checks.chat; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import org.bukkit.entity.Player; - import fr.neatmonster.nocheatplus.checks.access.AsyncCheckData; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; /** * Player specific data for the chat checks. */ -public class ChatData extends AsyncCheckData { - - /** The factory creating data. */ - public static final CheckDataFactory factory = new CheckDataFactory() { - @Override - public final ICheckData getData(final Player player) { - return ChatData.getData(player); - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return ChatData.playersMap.get(playerName); - } - - @Override - public ICheckData removeData(final String playerName) { - return ChatData.removeData(playerName); - } - - @Override - public void removeAllData() { - clear(); - } - }; - - /** The map containing the data per players. */ - private static final Map playersMap = new HashMap(); - - /** - * Gets the data of a specified player. - * - * @param player - * the player - * @return the data - */ - public static synchronized ChatData getData(final Player player) { - if (!playersMap.containsKey(player.getName())) - playersMap.put(player.getName(), new ChatData(ChatConfig.getConfig(player))); - return playersMap.get(player.getName()); - } - - public static synchronized ICheckData removeData(final String playerName) { - return playersMap.remove(playerName); - } - - public static synchronized void clear(){ - playersMap.clear(); - } +public class ChatData extends AsyncCheckData { // Violation levels. public double captchaVL; @@ -109,15 +54,6 @@ public class ChatData extends AsyncCheckData { public int relogWarnings; public long relogWarningTime; - /** - * Keep track of current world name, to be used for asynchronous world - * config getting. Set on join and world change, reset on leave. - */ - public String currentWorldName = null; - - public ChatData(final ChatConfig config) { - super(config); - } /** * Clear the data of the no pwnage check. diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java index e9d7c44c..8b65ee53 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java @@ -23,7 +23,6 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; @@ -42,7 +41,7 @@ import fr.neatmonster.nocheatplus.config.ConfigFile; import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.logging.Streams; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.SimpleCharPrefixTree; @@ -100,13 +99,6 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe CommandUtil.feedCommands(commandExclusions, config, ConfPaths.CHAT_COMMANDS_EXCLUSIONS, true); } - @EventHandler(priority=EventPriority.MONITOR) - public void onPlayerChangedWorld(final PlayerChangedWorldEvent event) { - final Player player = event.getPlayer(); - ChatData.getData(player).currentWorldName = player.getWorld().getName(); - - } - /** * We listen to PlayerChat events for obvious reasons. * @@ -121,11 +113,11 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe // Tell TickTask to update cached permissions. // (Might omit this if already cancelled.) - final PlayerData pData = DataManager.getPlayerData(player); - final ChatConfig cc = ChatConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final ChatConfig cc = pData.getGenericInstance(ChatConfig.class); // First the color check. - if (!alreadyCancelled && color.isEnabled(player)) { + if (!alreadyCancelled && color.isEnabled(player, pData)) { event.setMessage(color.check(player, event.getMessage(), false)); } @@ -148,11 +140,11 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe final Player player = event.getPlayer(); // Tell TickTask to update cached permissions. - final PlayerData pData = DataManager.getPlayerData(player); - final ChatConfig cc = ChatConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final ChatConfig cc = pData.getGenericInstance(ChatConfig.class); // Checks that replace parts of the message (color). - if (color.isEnabled(player)) { + if (color.isEnabled(player, pData)) { event.setMessage(color.check(player, event.getMessage(), true)); } @@ -198,15 +190,15 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe } else if (!commandExclusions.hasAnyPrefixWords(messageVars)) { // Treat as command. - if (commands.isEnabled(player) && commands.check(player, checkMessage, cc, pData, captcha)) { + if (commands.isEnabled(player, pData) && commands.check(player, checkMessage, cc, pData, captcha)) { event.setCancelled(true); } else { // TODO: Consider always checking these? // Note that this checks for prefixes, not prefix words. - final MovingConfig mcc = MovingConfig.getConfig(player); + final MovingConfig mcc = pData.getGenericInstance(MovingConfig.class); if (mcc.passableUntrackedCommandCheck && mcc.passableUntrackedCommandPrefixes.hasAnyPrefix(messageVars)) { - if (checkUntrackedLocation(player, message, mcc)) { + if (checkUntrackedLocation(player, message, mcc, pData)) { event.setCancelled(true); } } @@ -215,10 +207,11 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe } - private boolean checkUntrackedLocation(final Player player, final String message, final MovingConfig mcc) { + private boolean checkUntrackedLocation(final Player player, final String message, + final MovingConfig mcc, final IPlayerData pData) { final Location loc = player.getLocation(useLoc); boolean cancel = false; - if (MovingUtil.shouldCheckUntrackedLocation(player, loc)) { + if (MovingUtil.shouldCheckUntrackedLocation(player, loc, pData)) { final Location newTo = MovingUtil.checkUntrackedLocation(loc); if (newTo != null) { if (mcc.passableUntrackedCommandTryTeleport @@ -237,9 +230,9 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe } private boolean textChecks(final Player player, final String message, - final ChatConfig cc, final PlayerData pData, + final ChatConfig cc, final IPlayerData pData, final boolean isMainThread, final boolean alreadyCancelled) { - return text.isEnabled(player) && text.check(player, message, cc, pData, + return text.isEnabled(player, pData) && text.check(player, message, cc, pData, captcha, isMainThread, alreadyCancelled); } @@ -254,9 +247,9 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe public void onPlayerLogin(final PlayerLoginEvent event) { if (event.getResult() != Result.ALLOWED) return; final Player player = event.getPlayer(); - final PlayerData pData = DataManager.getPlayerData(player); - final ChatConfig cc = ChatConfig.getConfig(player); - final ChatData data = ChatData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final ChatConfig cc = pData.getGenericInstance(ChatConfig.class); + final ChatData data = pData.getGenericInstance(ChatData.class); // (No forced permission update, because the associated permissions are treated as hints rather.) @@ -265,10 +258,10 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe captcha.resetCaptcha(player, cc, data, pData); } // Fast relog check. - if (relog.isEnabled(player) && relog.unsafeLoginCheck(player, cc, data)) { + if (relog.isEnabled(player, pData) && relog.unsafeLoginCheck(player, cc, data,pData)) { event.disallow(Result.KICK_OTHER, cc.relogKickMessage); } - else if (logins.isEnabled(player) && logins.check(player, cc, data)) { + else if (logins.isEnabled(player, pData) && logins.check(player, cc, data)) { event.disallow(Result.KICK_OTHER, cc.loginsKickMessage); } } @@ -284,13 +277,17 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe @Override public void playerJoins(final Player player) { - final PlayerData pData = DataManager.getPlayerData(player); - final ChatConfig cc = ChatConfig.getConfig(player); - final ChatData data = ChatData.getData(player); - // Cross-check hack: ChatData holds the current world name (TBD: PlayerData.getWorldInfo() rather). - data.currentWorldName = player.getWorld().getName(); + final IPlayerData pData = DataManager.getPlayerData(player); + final ChatConfig cc = pData.getGenericInstance(ChatConfig.class); + final ChatData data = pData.getGenericInstance(ChatData.class); + /* + * TODO: The isEnabled check must be done with IWorldData (no locking). + * Specifically because enabling/disabling checks should be done in the + * primary thread, regardless of the capabilities of WorldDataManager + * implementation. + */ synchronized (data) { - if (captcha.isEnabled(player, cc, pData)) { + if (captcha.isEnabled(player, pData)) { if (captcha.shouldCheckCaptcha(player, cc, data, pData)) { // shouldCheckCaptcha: only if really enabled. // TODO: Later: add check for cc.captchaOnLogin or so (before shouldCheckCaptcha). @@ -303,7 +300,6 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe @Override public void playerLeaves(final Player player) { - ChatData.getData(player).currentWorldName = null; } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Color.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Color.java index 88546926..3640191d 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Color.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Color.java @@ -18,6 +18,8 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * The Color check verifies that no color codes are sent in players' messages. @@ -44,9 +46,10 @@ public class Color extends Check { */ public String check(final Player player, final String message, final boolean isMainThread) { - final ChatConfig cc = ChatConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final ChatConfig cc = pData.getGenericInstance(ChatConfig.class); + final ChatData data = pData.getGenericInstance(ChatData.class); - final ChatData data = ChatData.getData(player); // Keep related to ChatData used lock. synchronized (data) { // If the message contains colors... diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Commands.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Commands.java index b4da8b36..a9afa44d 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Commands.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Commands.java @@ -18,8 +18,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.players.PlayerData; -import fr.neatmonster.nocheatplus.utilities.CheckUtils; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.ColorUtil; import fr.neatmonster.nocheatplus.utilities.TickTask; @@ -34,16 +33,16 @@ public class Commands extends Check { } public boolean check(final Player player, final String message, - final ChatConfig cc, final PlayerData pData, + final ChatConfig cc, final IPlayerData pData, final ICaptcha captcha) { final long now = System.currentTimeMillis(); final int tick = TickTask.getTick(); - final ChatData data = ChatData.getData(player); + final ChatData data = pData.getGenericInstance(ChatData.class); final boolean captchaEnabled = !cc.captchaSkipCommands - && CheckUtils.isEnabled(CheckType.CHAT_CAPTCHA, player, cc, pData); + && pData.isCheckActive(CheckType.CHAT_CAPTCHA, player); if (captchaEnabled){ synchronized (data) { if (captcha.shouldCheckCaptcha(player, cc, data, pData)){ @@ -65,7 +64,8 @@ public class Commands extends Check { data.commandsShortTermWeight = 1.0; } else if (tick - data.commandsShortTermTick < cc.commandsShortTermTicks){ - if (!cc.lag || TickTask.getLag(50L * (tick - data.commandsShortTermTick), true) < 1.3f){ + if (!pData.getCurrentWorldData().shouldAdjustToLag(type) + || TickTask.getLag(50L * (tick - data.commandsShortTermTick), true) < 1.3f){ // Add up. data.commandsShortTermWeight += weight; } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ICaptcha.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ICaptcha.java index 7f84b530..6acff730 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ICaptcha.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/ICaptcha.java @@ -16,7 +16,7 @@ package fr.neatmonster.nocheatplus.checks.chat; import org.bukkit.entity.Player; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * Captcha related operations.
@@ -62,7 +62,7 @@ public interface ICaptcha { * @param pData * @return */ - public boolean shouldCheckCaptcha(Player player, ChatConfig cc, ChatData data, PlayerData pData); + public boolean shouldCheckCaptcha(Player player, ChatConfig cc, ChatData data, IPlayerData pData); /** * Check if captcha should be generated and send to the player. @@ -73,7 +73,7 @@ public interface ICaptcha { * @param pData * @return */ - public boolean shouldStartCaptcha(Player player, ChatConfig cc, ChatData data, PlayerData pData); + public boolean shouldStartCaptcha(Player player, ChatConfig cc, ChatData data, IPlayerData pData); /** * Just resets tries, generate new captcha if necessary. @@ -83,7 +83,7 @@ public interface ICaptcha { * @param data * @param pData */ - public void resetCaptcha(Player player, ChatConfig cc, ChatData data, PlayerData pData); + public void resetCaptcha(Player player, ChatConfig cc, ChatData data, IPlayerData pData); /** * Convenience method. Should synchronize over data of player (!). diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Relog.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Relog.java index 96e42e06..849bf2d6 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Relog.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Relog.java @@ -19,6 +19,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.combined.CombinedData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.ColorUtil; public class Relog extends Check { @@ -38,12 +39,13 @@ public class Relog extends Check { * the data * @return true, if successful */ - public boolean unsafeLoginCheck(final Player player, final ChatConfig cc, final ChatData data) { + public boolean unsafeLoginCheck(final Player player, + final ChatConfig cc, final ChatData data, final IPlayerData pData) { boolean cancel = false; final long now = System.currentTimeMillis(); - final CombinedData cData = CombinedData.getData(player); + final CombinedData cData = pData.getGenericInstance(CombinedData.class); // Enforce the player does not relog too fast. if (now - cData.lastLogoutTime < cc.relogTimeout) { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Text.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Text.java index 44d93d55..1ff38a5e 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Text.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Text.java @@ -32,7 +32,7 @@ import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI; import fr.neatmonster.nocheatplus.components.registry.feature.INotifyReload; import fr.neatmonster.nocheatplus.config.ConfigFile; import fr.neatmonster.nocheatplus.config.ConfigManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.ColorUtil; import fr.neatmonster.nocheatplus.utilities.StringUtil; @@ -69,9 +69,9 @@ public class Text extends Check implements INotifyReload { * @return */ public boolean check(final Player player, final String message, - final ChatConfig cc, final PlayerData pData, + final ChatConfig cc, final IPlayerData pData, final ICaptcha captcha, boolean isMainThread, final boolean alreadyCancelled) { - final ChatData data = ChatData.getData(player); + final ChatData data = pData.getGenericInstance(ChatData.class); synchronized (data) { return unsafeCheck(player, message, captcha, cc, data, pData, isMainThread, alreadyCancelled); @@ -110,7 +110,7 @@ public class Text extends Check implements INotifyReload { * @return */ private boolean unsafeCheck(final Player player, final String message, final ICaptcha captcha, - final ChatConfig cc, final ChatData data, final PlayerData pData, + final ChatConfig cc, final ChatData data, final IPlayerData pData, boolean isMainThread, final boolean alreadyCancelled) { // Test captcha. @@ -130,7 +130,7 @@ public class Text extends Check implements INotifyReload { boolean cancel = false; - boolean debug = data.debug; + final boolean debug = pData.isDebugActive(type); final List debugParts; if (debug) { @@ -180,7 +180,7 @@ public class Text extends Check implements INotifyReload { } } - final CombinedData cData = CombinedData.getData(player); + final CombinedData cData = pData.getGenericInstance(CombinedData.class); final long timeout = 8000; // TODO: maybe set dynamically in data. // Repetition of last message. if (cc.textMsgRepeatSelf != 0f && time - data.chatLastTime < timeout) { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/BedLeave.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/BedLeave.java index bff71539..15c57b36 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/BedLeave.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/BedLeave.java @@ -18,6 +18,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.IPlayerData; public class BedLeave extends Check { @@ -32,8 +33,8 @@ public class BedLeave extends Check { * the player * @return If to prevent action (use the set back location of survivalfly). */ - public boolean checkBed(final Player player) { - final CombinedData data = CombinedData.getData(player); + public boolean checkBed(final Player player, final IPlayerData pData) { + final CombinedData data = pData.getGenericInstance(CombinedData.class); boolean cancel = false; // Check if the player had been in bed at all. @@ -44,7 +45,8 @@ public class BedLeave extends Check { // TODO: add tag // And return if we need to do something or not. - if (executeActions(player, data.bedLeaveVL, 1D, CombinedConfig.getConfig(player).bedLeaveActions).willCancel()){ + if (executeActions(player, data.bedLeaveVL, 1D, + pData.getGenericInstance(CombinedConfig.class).bedLeaveActions).willCancel()){ cancel = true; } } else{ diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/Combined.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/Combined.java index 5a76b172..4cb66f30 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/Combined.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/Combined.java @@ -18,6 +18,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.TickTask; @@ -40,8 +41,9 @@ public class Combined { * @return */ public static final boolean checkYawRate(final Player player, final float yaw, final long now, - final String worldName) { - return checkYawRate(player, yaw, now, worldName, CombinedData.getData(player)); + final String worldName, final IPlayerData pData) { + return checkYawRate(player, yaw, now, worldName, + pData.getGenericInstance(CombinedData.class), pData); } /** @@ -52,8 +54,9 @@ public class Combined { * @param worldName */ public static final void feedYawRate(final Player player, final float yaw, final long now, - final String worldName) { - feedYawRate(player, yaw, now, worldName, CombinedData.getData(player)); + final String worldName, final IPlayerData pData) { + feedYawRate(player, yaw, now, worldName, + pData.getGenericInstance(CombinedData.class), pData); } /** @@ -68,10 +71,10 @@ public class Combined { * @return True, if the player was exempted from yawrate. False otherwise. */ public static final boolean feedYawRate(final Player player, float yaw, final long now, - final String worldName, final CombinedData data) { + final String worldName, final CombinedData data, final IPlayerData pData) { // Check for exemption (hack, sort of). if (NCPExemptionManager.isExempted(player, CheckType.COMBINED_YAWRATE)) { - resetYawRate(player, yaw, now, true); + resetYawRate(player, yaw, now, true, pData); return true; } @@ -145,13 +148,14 @@ public class Combined { * otherwise. */ public static final boolean checkYawRate(final Player player, final float yaw, final long now, - final String worldName, final CombinedData data) { + final String worldName, final CombinedData data, final IPlayerData pData) { - if (feedYawRate(player, yaw, now, worldName, data)) { + if (feedYawRate(player, yaw, now, worldName, data, pData)) { return false; } - final CombinedConfig cc = CombinedConfig.getConfig(player); + final CombinedConfig cc = pData.getGenericInstance(CombinedConfig.class); + final boolean lag = pData.getCurrentWorldData().shouldAdjustToLag(CheckType.COMBINED_IMPROBABLE); final float threshold = cc.yawRate; @@ -160,7 +164,7 @@ public class Combined { final float stViol; if (stScore > threshold) { // Account for server side lag. - if (!cc.lag || TickTask.getLag(data.yawFreq.bucketDuration(), true) < 1.2) { + if (!lag || TickTask.getLag(data.yawFreq.bucketDuration(), true) < 1.2) { stViol = stScore; } else { @@ -174,7 +178,7 @@ public class Combined { final float fullViol; if (fullScore > threshold) { // Account for server side lag. - if (cc.lag) { + if (lag) { fullViol = fullScore / TickTask.getLag(data.yawFreq.bucketDuration() * data.yawFreq.numberOfBuckets(), true); } else { @@ -194,7 +198,8 @@ public class Combined { Math.max(cc.yawRatePenaltyFactor * amount , cc.yawRatePenaltyMin), cc.yawRatePenaltyMax)); // TODO: balance (100 ... 200 ) ? - if (cc.yawRateImprobable && Improbable.check(player, amount / 100f, now, "combined.yawrate")) + if (cc.yawRateImprobable && Improbable.check(player, amount / 100f, now, "combined.yawrate", + pData)) cancel = true; } if (data.timeFreeze.isPenalty()) { @@ -210,14 +215,15 @@ public class Combined { * @param time * @param clear If to clear yaws. */ - public static final void resetYawRate(final Player player, float yaw, final long time, final boolean clear) { + public static final void resetYawRate(final Player player, float yaw, + final long time, final boolean clear, final IPlayerData pData) { if (yaw <= -360f) { yaw = -((-yaw) % 360f); } else if (yaw >= 360f) { yaw = yaw % 360f; } - final CombinedData data = CombinedData.getData(player); + final CombinedData data = pData.getGenericInstance(CombinedData.class); data.lastYaw = yaw; data.lastYawTime = time; // TODO: One might set to some past-time to allow any move at first. data.sumYaw = 0; @@ -235,12 +241,13 @@ public class Combined { * @param yawRateCheck If to actually check the yaw rate, or just feed. * @return */ - public static final boolean checkYawRate(final Player player, final float yaw, final long now, final String worldName, final boolean yawRateCheck) { + public static final boolean checkYawRate(final Player player, final float yaw, final long now, + final String worldName, final boolean yawRateCheck, final IPlayerData pData) { if (yawRateCheck) { - return checkYawRate(player, yaw, now, worldName); + return checkYawRate(player, yaw, now, worldName, pData); } else { - feedYawRate(player, yaw, now, worldName); + feedYawRate(player, yaw, now, worldName, pData); return false; } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedConfig.java index 0692ca56..e3fea2c1 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedConfig.java @@ -21,51 +21,20 @@ import java.util.Map; import java.util.Set; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import fr.neatmonster.nocheatplus.actions.ActionList; -import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckConfig; -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.logging.StaticLog; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.utilities.StringUtil; +import fr.neatmonster.nocheatplus.worlds.IWorldData; public class CombinedConfig extends ACheckConfig { - /** The factory creating configurations. */ - public static final CheckConfigFactory factory = new CheckConfigFactory() { - @Override - public final ICheckConfig getConfig(final Player player) { - return CombinedConfig.getConfig(player); - } - - @Override - public void removeAllConfigs() { - clear(); // Band-aid. - } - }; - - private static final Map worldsMap = new HashMap(); - - public static CombinedConfig getConfig(final Player player) { - final String worldName = player.getWorld().getName(); - CombinedConfig cc = worldsMap.get(worldName); - if (cc == null){ - cc = new CombinedConfig(ConfigManager.getConfigFile(worldName)); - worldsMap.put(worldName, cc); - } - return cc; - } - - // Bedleave check. - public final boolean bedLeaveCheck; public final ActionList bedLeaveActions; // Ender pearl @@ -74,7 +43,6 @@ public class CombinedConfig extends ACheckConfig { // Improbable check /** Do mind that this flag is not used by all components. */ - public final boolean improbableCheck; public final float improbableLevel; public final ActionList improbableActions; @@ -87,7 +55,6 @@ public class CombinedConfig extends ACheckConfig { public final boolean invulnerableTriggerAlways; public final boolean invulnerableTriggerFallDistance; - public final boolean munchHausenCheck; public final ActionList munchHausenActions; // Last yaw tracking @@ -97,16 +64,15 @@ public class CombinedConfig extends ACheckConfig { public final int yawRatePenaltyMin; public final int yawRatePenaltyMax; - public CombinedConfig(final ConfigFile config) { - super(config, ConfPaths.COMBINED); + public CombinedConfig(final IWorldData worldData) { + super(worldData); + final ConfigFile config = worldData.getRawConfiguration(); - bedLeaveCheck = config.getBoolean(ConfPaths.COMBINED_BEDLEAVE_CHECK); bedLeaveActions = config.getOptimizedActionList(ConfPaths.COMBINED_BEDLEAVE_ACTIONS, Permissions.COMBINED_BEDLEAVE); enderPearlCheck = config.getBoolean(ConfPaths.COMBINED_ENDERPEARL_CHECK); enderPearlPreventClickBlock = config.getBoolean(ConfPaths.COMBINED_ENDERPEARL_PREVENTCLICKBLOCK); - improbableCheck = config.getBoolean(ConfPaths.COMBINED_IMPROBABLE_CHECK); improbableLevel = (float) config.getDouble(ConfPaths.COMBINED_IMPROBABLE_LEVEL); improbableActions = config.getOptimizedActionList(ConfPaths.COMBINED_IMPROBABLE_ACTIONS, Permissions.COMBINED_IMPROBABLE); @@ -147,7 +113,6 @@ public class CombinedConfig extends ACheckConfig { invulnerableTriggerAlways = config.getBoolean(ConfPaths.COMBINED_INVULNERABLE_TRIGGERS_ALWAYS); invulnerableTriggerFallDistance = config.getBoolean(ConfPaths.COMBINED_INVULNERABLE_TRIGGERS_FALLDISTANCE); - munchHausenCheck = config.getBoolean(ConfPaths.COMBINED_MUNCHHAUSEN_CHECK); munchHausenActions = config.getOptimizedActionList(ConfPaths.COMBINED_MUNCHHAUSEN_ACTIONS, Permissions.COMBINED_MUNCHHAUSEN); yawRate = config.getInt(ConfPaths.COMBINED_YAWRATE_RATE); @@ -157,25 +122,4 @@ public class CombinedConfig extends ACheckConfig { yawRatePenaltyMax = config.getInt(ConfPaths.COMBINED_YAWRATE_PENALTY_MAX); } - @Override - public boolean isEnabled(final CheckType checkType) { - switch(checkType){ - case COMBINED_IMPROBABLE: - return improbableCheck; - case COMBINED_BEDLEAVE: - return bedLeaveCheck; - case COMBINED_MUNCHHAUSEN: - return munchHausenCheck; - case COMBINED_YAWRATE: - // Always on, depends on other checks. - return true; - default: - return false; - } - } - - public static void clear() { - worldsMap.clear(); - } - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java index ee27ee3c..e98047ce 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java @@ -14,65 +14,14 @@ */ package fr.neatmonster.nocheatplus.checks.combined; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import org.bukkit.entity.Player; - import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckData; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.checks.access.IRemoveSubCheckData; import fr.neatmonster.nocheatplus.utilities.PenaltyTime; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; public class CombinedData extends ACheckData implements IRemoveSubCheckData { - /** The factory creating data. */ - public static final CheckDataFactory factory = new CheckDataFactory() { - @Override - public final ICheckData getData(final Player player) { - return CombinedData.getData(player); - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return CombinedData.playersMap.get(playerName); - } - - @Override - public ICheckData removeData(final String playerName) { - return CombinedData.removeData(playerName); - } - - @Override - public void removeAllData() { - clear(); - } - }; - - private static final Map playersMap = new HashMap(); - - public static CombinedData getData(final Player player) { - final String playerName = player.getName(); - CombinedData data = playersMap.get(playerName); - if (data == null){ - data = new CombinedData(CombinedConfig.getConfig(player)); - playersMap.put(playerName, data); - } - return data; - } - - public static ICheckData removeData(final String playerName) { - return playersMap.remove(playerName); - } - - public static void clear(){ - playersMap.clear(); - } - // VLs public double bedLeaveVL = 0; public double improbableVL = 0; @@ -98,15 +47,12 @@ public class CombinedData extends ACheckData implements IRemoveSubCheckData { public final ActionFrequency improbableCount = new ActionFrequency(20, 3000); // General data + // TODO: -> PlayerData (-> OfflinePlayerData) public String lastWorld = ""; public long lastJoinTime; public long lastLogoutTime; public long lastMoveTime; - public CombinedData(final CombinedConfig config){ - super(config); - } - @Override public boolean removeSubCheckData(final CheckType checkType) { switch(checkType) { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java index a4920f26..2708e0f1 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java @@ -28,6 +28,8 @@ import org.bukkit.event.player.PlayerToggleSprintEvent; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.CheckListener; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.TickTask; @@ -65,10 +67,13 @@ public class CombinedListener extends CheckListener { // TODO: EventPriority final Player player = event.getPlayer(); - final CombinedData data = CombinedData.getData(player); - final CombinedConfig cc = CombinedConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final CombinedData data = pData.getGenericInstance(CombinedData.class); + final CombinedConfig cc = pData.getGenericInstance(CombinedConfig.class); - if (cc.invulnerableCheck && (cc.invulnerableTriggerAlways || cc.invulnerableTriggerFallDistance && player.getFallDistance() > 0)){ + if (cc.invulnerableCheck + && (cc.invulnerableTriggerAlways || cc.invulnerableTriggerFallDistance + && player.getFallDistance() > 0)){ // TODO: maybe make a heuristic for small fall distances with ground under feet (prevents future abuse with jumping) ? final int invulnerableTicks = mcAccess.getHandle().getInvulnerableTicks(player); if (invulnerableTicks == Integer.MAX_VALUE) { @@ -86,7 +91,8 @@ public class CombinedListener extends CheckListener { final Entity entity = event.getEntity(); if (!(entity instanceof Player)) return; final Player player = (Player) entity; - final CombinedConfig cc = CombinedConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final CombinedConfig cc = pData.getGenericInstance(CombinedConfig.class); if (!cc.invulnerableCheck) return; final DamageCause cause = event.getCause(); // Ignored causes. @@ -94,7 +100,7 @@ public class CombinedListener extends CheckListener { // Modified invulnerable ticks. Integer modifier = cc.invulnerableModifiers.get(cause); if (modifier == null) modifier = cc.invulnerableModifierDefault; - final CombinedData data = CombinedData.getData(player); + final CombinedData data = pData.getGenericInstance(CombinedData.class); // TODO: account for tick task reset ? [it should not though, due to data resetting too, but API would allow it] if (TickTask.getTick() >= data.invulnerableTick + modifier.intValue()) return; // Still invulnerable. diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/Improbable.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/Improbable.java index a50929e2..17123a8b 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/Improbable.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/Improbable.java @@ -21,6 +21,8 @@ import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; import fr.neatmonster.nocheatplus.components.registry.feature.IDisableListener; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.TickTask; /** @@ -41,8 +43,21 @@ public class Improbable extends Check implements IDisableListener{ * @param now * @return */ - public static final boolean check(final Player player, final float weight, final long now, final String tags){ - return instance.checkImprobable(player, weight, now, tags); + public static final boolean check(final Player player, final float weight, final long now, + final String tags, final IPlayerData pData){ + return instance.checkImprobable(player, weight, now, tags, pData); + } + + /** + * Feed the check but no violations processing (convenience method). + * @param player + * @param weight + * @param now + * @param pData + */ + public static final void feed(final Player player, final float weight, final long now, + final IPlayerData pData){ + pData.getGenericInstance(CombinedData.class).improbableCount.add(now, weight); } /** @@ -51,8 +66,8 @@ public class Improbable extends Check implements IDisableListener{ * @param weight * @param now */ - public static final void feed(final Player player, final float weight, final long now){ - CombinedData.getData(player).improbableCount.add(now, weight); + public static void feed(final Player player, final float weight, long now) { + feed(player, weight, now, DataManager.getPlayerData(player)); } //////////////////////////////////// @@ -64,16 +79,19 @@ public class Improbable extends Check implements IDisableListener{ instance = this; } - private boolean checkImprobable(final Player player, final float weight, final long now, final String tags) { - if (!isEnabled(player)) return false; - final CombinedData data = CombinedData.getData(player); - final CombinedConfig cc = CombinedConfig.getConfig(player); + private boolean checkImprobable(final Player player, final float weight, final long now, + final String tags, final IPlayerData pData) { + if (!pData.isCheckActive(type, player)) { + return false; + } + final CombinedData data = pData.getGenericInstance(CombinedData.class); + final CombinedConfig cc = pData.getGenericInstance(CombinedConfig.class); data.improbableCount.add(now, weight); final float shortTerm = data.improbableCount.bucketScore(0); double violation = 0; boolean violated = false; if (shortTerm * 0.8f > cc.improbableLevel / 20.0){ - final float lag = cc.lag ? TickTask.getLag(data.improbableCount.bucketDuration(), true) : 1f; + final float lag = pData.getCurrentWorldData().shouldAdjustToLag(type) ? TickTask.getLag(data.improbableCount.bucketDuration(), true) : 1f; if (shortTerm / lag > cc.improbableLevel / 20.0){ violation += shortTerm * 2d / lag; violated = true; @@ -81,7 +99,7 @@ public class Improbable extends Check implements IDisableListener{ } final double full = data.improbableCount.score(1.0f); if (full > cc.improbableLevel){ - final float lag = cc.lag ? TickTask.getLag(data.improbableCount.bucketDuration() * data.improbableCount.numberOfBuckets(), true) : 1f; + final float lag = pData.getCurrentWorldData().shouldAdjustToLag(type) ? TickTask.getLag(data.improbableCount.bucketDuration() * data.improbableCount.numberOfBuckets(), true) : 1f; if (full / lag > cc.improbableLevel){ violation += full / lag; violated = true; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/MunchHausen.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/MunchHausen.java index 67c224cb..4b78786c 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/MunchHausen.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/combined/MunchHausen.java @@ -20,6 +20,8 @@ import org.bukkit.event.player.PlayerFishEvent.State; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * Very, very important check. @@ -34,10 +36,12 @@ public class MunchHausen extends Check { public boolean checkFish(final Player player, final Entity caught, final State state) { if (caught == null || !(caught instanceof Player)) return false; final Player caughtPlayer = (Player) caught; - final CombinedData data = CombinedData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final CombinedData data = pData.getGenericInstance(CombinedData.class); if (player.equals(caughtPlayer)){ data.munchHausenVL += 1.0; - if (executeActions(player, data.munchHausenVL, 1.0, CombinedConfig.getConfig(player).munchHausenActions).willCancel()){ + if (executeActions(player, data.munchHausenVL, 1.0, + pData.getGenericInstance(CombinedConfig.class).munchHausenActions).willCancel()){ return true; } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Critical.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Critical.java index b4cc761e..8ea4d9af 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Critical.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Critical.java @@ -32,7 +32,7 @@ import fr.neatmonster.nocheatplus.checks.moving.model.LiftOffEnvelope; import fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveInfo; import fr.neatmonster.nocheatplus.checks.moving.util.AuxMoving; import fr.neatmonster.nocheatplus.checks.moving.util.MovingUtil; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; @@ -58,13 +58,14 @@ public class Critical extends Check { * @return true, if successful */ public boolean check(final Player player, final Location loc, - final FightData data, final FightConfig cc, final PlayerData pData) { + final FightData data, final FightConfig cc, + final IPlayerData pData) { boolean cancel = false; final double mcFallDistance = (double) player.getFallDistance(); - final MovingConfig mCc = MovingConfig.getConfig(player); + final MovingConfig mCc = pData.getGenericInstance(MovingConfig.class); - if (data.debug) { + if (pData.isDebugActive(type)) { debug(player, "y=" + loc.getY() + " mcfalldist=" + mcFallDistance); } @@ -72,13 +73,17 @@ public class Critical extends Check { // not in liquid, not in vehicle, and without blindness effect). if (mcFallDistance > 0.0 && !player.isInsideVehicle() && !player.hasPotionEffect(PotionEffectType.BLINDNESS)) { // Might be a violation. - final MovingData dataM = MovingData.getData(player); + final MovingData dataM = pData.getGenericInstance(MovingData.class); + /* + * TODO: NoFall data max y. (past moves too perhaps - low jump, + * number split moves without reason) + */ // TODO: Skip near the highest jump height (needs check if head collided with something solid, which also detects low jump). if (!dataM.isVelocityJumpPhase() && (dataM.sfLowJump && !dataM.sfNoLowJump && dataM.liftOffEnvelope == LiftOffEnvelope.NORMAL || mcFallDistance < cc.criticalFallDistance && !BlockProperties.isResetCond(player, loc, mCc.yOnGround))) { - final MovingConfig ccM = MovingConfig.getConfig(player); + final MovingConfig ccM = pData.getGenericInstance(MovingConfig.class); // TODO: Use past move tracking to check for SurvivalFly and the like? final PlayerMoveInfo moveInfo = auxMoving.usePlayerMoveInfo(); moveInfo.set(player, loc, null, ccM.yOnGround); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FastHeal.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FastHeal.java index 6bf9b2cc..e904ff90 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FastHeal.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FastHeal.java @@ -19,25 +19,27 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.TickTask; /** + * Legacy check (client side health regeneration). * - * @author mc_dev + * @author asofold * */ public class FastHeal extends Check { + public FastHeal(){ super(CheckType.FIGHT_FASTHEAL); } - public boolean check(final Player player){ + public boolean check(final Player player, final IPlayerData pData){ final long time = System.currentTimeMillis(); - final PlayerData pData = DataManager.getPlayerData(player); - final FightConfig cc = FightConfig.getConfig(player); - final FightData data = FightData.getData(player); + + final FightConfig cc = pData.getGenericInstance(FightConfig.class); + final FightData data = pData.getGenericInstance(FightData.class); + boolean cancel = false; if (time < data.fastHealRefTime || time - data.fastHealRefTime >= cc.fastHealInterval){ // Reset. @@ -63,7 +65,7 @@ public class FastHeal extends Check { } } - if (data.debug && pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)){ + if (pData.isDebugActive(type) && pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)){ player.sendMessage("Regain health(SATIATED): " + (time - data.fastHealRefTime) + " ms "+ "(buffer=" + data.fastHealBuffer + ")" +" , cancel=" + cancel); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java index 1d5ee40c..88f18c32 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java @@ -14,23 +14,17 @@ */ package fr.neatmonster.nocheatplus.checks.fight; -import java.util.HashMap; -import java.util.Map; - -import org.bukkit.entity.Player; - import fr.neatmonster.nocheatplus.actions.ActionList; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckConfig; -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; import fr.neatmonster.nocheatplus.compat.AlmostBoolean; import fr.neatmonster.nocheatplus.compat.versions.Bugs; import fr.neatmonster.nocheatplus.compat.versions.ServerVersion; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.permissions.Permissions; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Configurations specific for the "fight" checks. Every world gets one of these assigned to it, or if a world doesn't @@ -38,72 +32,28 @@ import fr.neatmonster.nocheatplus.permissions.Permissions; */ public class FightConfig extends ACheckConfig { - /** The factory creating configurations. */ - public static final CheckConfigFactory factory = new CheckConfigFactory() { - @Override - public final ICheckConfig getConfig(final Player player) { - return FightConfig.getConfig(player); - } - - @Override - public void removeAllConfigs() { - clear(); // Band-aid. - } - }; - - /** The map containing the configurations per world. */ - private static final Map worldsMap = new HashMap(); - - /** - * Clear all the configurations. - */ - public static void clear() { - worldsMap.clear(); - } - - /** - * Gets the configuration for a specified player. - * - * @param player - * the player - * @return the configuration - */ - public static FightConfig getConfig(final Player player) { - if (!worldsMap.containsKey(player.getWorld().getName())) - worldsMap.put(player.getWorld().getName(), - new FightConfig(ConfigManager.getConfigFile(player.getWorld().getName()))); - return worldsMap.get(player.getWorld().getName()); - } - - public final boolean angleCheck; public final double angleThreshold; public final ActionList angleActions; public final long toolChangeAttackPenalty; - public final boolean criticalCheck; public final double criticalFallDistance; public final ActionList criticalActions; - public final boolean directionCheck; public final boolean directionStrict; public final long directionPenalty; public final ActionList directionActions; - public final boolean fastHealCheck; public final long fastHealInterval; public final long fastHealBuffer; public final ActionList fastHealActions; - public final boolean godModeCheck; public final long godModeLagMinAge; public final long godModeLagMaxAge; public final ActionList godModeActions; - public final boolean noSwingCheck; public final ActionList noSwingActions; - public final boolean reachCheck; public final long reachPenalty; public final boolean reachPrecision; public final boolean reachReduce; @@ -113,10 +63,8 @@ public class FightConfig extends ACheckConfig { public final ActionList reachActions; - public final boolean selfHitCheck; public final ActionList selfHitActions; - public final boolean speedCheck; public final int speedLimit; public final int speedBuckets; public final long speedBucketDur; @@ -126,11 +74,9 @@ public class FightConfig extends ACheckConfig { public final int speedShortTermTicks; public final ActionList speedActions; - public final boolean wrongTurnEnabled; public final ActionList wrongTurnActions; // Special flags: - public final boolean yawRateCheck; public final boolean cancelDead; public final boolean knockBackVelocityPvP; @@ -143,94 +89,61 @@ public class FightConfig extends ACheckConfig { * @param data * the data */ - public FightConfig(final ConfigFile data) { - super(data, ConfPaths.FIGHT); - angleCheck = data.getBoolean(ConfPaths.FIGHT_ANGLE_CHECK); - angleThreshold = data.getDouble(ConfPaths.FIGHT_ANGLE_THRESHOLD); - angleActions = data.getOptimizedActionList(ConfPaths.FIGHT_ANGLE_ACTIONS, Permissions.FIGHT_ANGLE); + public FightConfig(final IWorldData worldData) { + super(worldData); + final ConfigFile config = worldData.getRawConfiguration(); + angleThreshold = config.getDouble(ConfPaths.FIGHT_ANGLE_THRESHOLD); + angleActions = config.getOptimizedActionList(ConfPaths.FIGHT_ANGLE_ACTIONS, Permissions.FIGHT_ANGLE); - toolChangeAttackPenalty = data.getLong(ConfPaths.FIGHT_TOOLCHANGEPENALTY); + toolChangeAttackPenalty = config.getLong(ConfPaths.FIGHT_TOOLCHANGEPENALTY); - criticalCheck = data.getBoolean(ConfPaths.FIGHT_CRITICAL_CHECK); - criticalFallDistance = data.getDouble(ConfPaths.FIGHT_CRITICAL_FALLDISTANCE); - criticalActions = data.getOptimizedActionList(ConfPaths.FIGHT_CRITICAL_ACTIONS, Permissions.FIGHT_CRITICAL); + criticalFallDistance = config.getDouble(ConfPaths.FIGHT_CRITICAL_FALLDISTANCE); + criticalActions = config.getOptimizedActionList(ConfPaths.FIGHT_CRITICAL_ACTIONS, Permissions.FIGHT_CRITICAL); - directionCheck = data.getBoolean(ConfPaths.FIGHT_DIRECTION_CHECK); - directionStrict = data.getBoolean(ConfPaths.FIGHT_DIRECTION_STRICT); - directionPenalty = data.getLong(ConfPaths.FIGHT_DIRECTION_PENALTY); - directionActions = data.getOptimizedActionList(ConfPaths.FIGHT_DIRECTION_ACTIONS, Permissions.FIGHT_DIRECTION); + directionStrict = config.getBoolean(ConfPaths.FIGHT_DIRECTION_STRICT); + directionPenalty = config.getLong(ConfPaths.FIGHT_DIRECTION_PENALTY); + directionActions = config.getOptimizedActionList(ConfPaths.FIGHT_DIRECTION_ACTIONS, Permissions.FIGHT_DIRECTION); - fastHealCheck = ServerVersion.compareMinecraftVersion("1.9") < 0 ? data.getBoolean(ConfPaths.FIGHT_FASTHEAL_CHECK) : false; - fastHealInterval = data.getLong(ConfPaths.FIGHT_FASTHEAL_INTERVAL); - fastHealBuffer = data.getLong(ConfPaths.FIGHT_FASTHEAL_BUFFER); - fastHealActions = data.getOptimizedActionList(ConfPaths.FIGHT_FASTHEAL_ACTIONS, Permissions.FIGHT_FASTHEAL); + if (ServerVersion.compareMinecraftVersion("1.9") >= 0) { + worldData.overrideCheckActivation(CheckType.FIGHT_FASTHEAL, + AlmostBoolean.NO, OverrideType.PERMANENT, + true); + } + fastHealInterval = config.getLong(ConfPaths.FIGHT_FASTHEAL_INTERVAL); + fastHealBuffer = config.getLong(ConfPaths.FIGHT_FASTHEAL_BUFFER); + fastHealActions = config.getOptimizedActionList(ConfPaths.FIGHT_FASTHEAL_ACTIONS, Permissions.FIGHT_FASTHEAL); - godModeCheck = data.getBoolean(ConfPaths.FIGHT_GODMODE_CHECK); - godModeLagMinAge = data.getLong(ConfPaths.FIGHT_GODMODE_LAGMINAGE); - godModeLagMaxAge = data.getLong(ConfPaths.FIGHT_GODMODE_LAGMAXAGE); - godModeActions = data.getOptimizedActionList(ConfPaths.FIGHT_GODMODE_ACTIONS, Permissions.FIGHT_GODMODE); + godModeLagMinAge = config.getLong(ConfPaths.FIGHT_GODMODE_LAGMINAGE); + godModeLagMaxAge = config.getLong(ConfPaths.FIGHT_GODMODE_LAGMAXAGE); + godModeActions = config.getOptimizedActionList(ConfPaths.FIGHT_GODMODE_ACTIONS, Permissions.FIGHT_GODMODE); - noSwingCheck = data.getBoolean(ConfPaths.FIGHT_NOSWING_CHECK); - noSwingActions = data.getOptimizedActionList(ConfPaths.FIGHT_NOSWING_ACTIONS, Permissions.FIGHT_NOSWING); + noSwingActions = config.getOptimizedActionList(ConfPaths.FIGHT_NOSWING_ACTIONS, Permissions.FIGHT_NOSWING); - reachCheck = data.getBoolean(ConfPaths.FIGHT_REACH_CHECK); - reachSurvivalDistance = data.getDouble(ConfPaths.FIGHT_REACH_SURVIVALDISTANCE, 3.5, 6.0, 4.4); - reachPenalty = data.getLong(ConfPaths.FIGHT_REACH_PENALTY); - reachPrecision = data.getBoolean(ConfPaths.FIGHT_REACH_PRECISION); - reachReduce = data.getBoolean(ConfPaths.FIGHT_REACH_REDUCE); - reachReduceDistance = data.getDouble(ConfPaths.FIGHT_REACH_REDUCEDISTANCE, 0, reachSurvivalDistance, 0.9); - reachReduceStep = data.getDouble(ConfPaths.FIGHT_REACH_REDUCESTEP, 0, reachReduceDistance, 0.15); - reachActions = data.getOptimizedActionList(ConfPaths.FIGHT_REACH_ACTIONS, Permissions.FIGHT_REACH); + reachSurvivalDistance = config.getDouble(ConfPaths.FIGHT_REACH_SURVIVALDISTANCE, 3.5, 6.0, 4.4); + reachPenalty = config.getLong(ConfPaths.FIGHT_REACH_PENALTY); + reachPrecision = config.getBoolean(ConfPaths.FIGHT_REACH_PRECISION); + reachReduce = config.getBoolean(ConfPaths.FIGHT_REACH_REDUCE); + reachReduceDistance = config.getDouble(ConfPaths.FIGHT_REACH_REDUCEDISTANCE, 0, reachSurvivalDistance, 0.9); + reachReduceStep = config.getDouble(ConfPaths.FIGHT_REACH_REDUCESTEP, 0, reachReduceDistance, 0.15); + reachActions = config.getOptimizedActionList(ConfPaths.FIGHT_REACH_ACTIONS, Permissions.FIGHT_REACH); - selfHitCheck = data.getBoolean(ConfPaths.FIGHT_SELFHIT_CHECK); - selfHitActions = data.getOptimizedActionList(ConfPaths.FIGHT_SELFHIT_ACTIONS, Permissions.FIGHT_SELFHIT); + selfHitActions = config.getOptimizedActionList(ConfPaths.FIGHT_SELFHIT_ACTIONS, Permissions.FIGHT_SELFHIT); - speedCheck = data.getBoolean(ConfPaths.FIGHT_SPEED_CHECK); - speedLimit = data.getInt(ConfPaths.FIGHT_SPEED_LIMIT); - speedBuckets = data.getInt(ConfPaths.FIGHT_SPEED_BUCKETS_N, 6); - speedBucketDur = data.getLong(ConfPaths.FIGHT_SPEED_BUCKETS_DUR, 333); - speedBucketFactor = (float) data.getDouble(ConfPaths.FIGHT_SPEED_BUCKETS_FACTOR, 1f); - speedShortTermLimit = data.getInt(ConfPaths.FIGHT_SPEED_SHORTTERM_LIMIT); - speedShortTermTicks = data.getInt(ConfPaths.FIGHT_SPEED_SHORTTERM_TICKS); - speedActions = data.getOptimizedActionList(ConfPaths.FIGHT_SPEED_ACTIONS, Permissions.FIGHT_SPEED); + speedLimit = config.getInt(ConfPaths.FIGHT_SPEED_LIMIT); + speedBuckets = config.getInt(ConfPaths.FIGHT_SPEED_BUCKETS_N, 6); + speedBucketDur = config.getLong(ConfPaths.FIGHT_SPEED_BUCKETS_DUR, 333); + speedBucketFactor = (float) config.getDouble(ConfPaths.FIGHT_SPEED_BUCKETS_FACTOR, 1f); + speedShortTermLimit = config.getInt(ConfPaths.FIGHT_SPEED_SHORTTERM_LIMIT); + speedShortTermTicks = config.getInt(ConfPaths.FIGHT_SPEED_SHORTTERM_TICKS); + speedActions = config.getOptimizedActionList(ConfPaths.FIGHT_SPEED_ACTIONS, Permissions.FIGHT_SPEED); - wrongTurnEnabled = data.getBoolean(ConfPaths.FIGHT_WRONGTURN_CHECK); - wrongTurnActions = data.getOptimizedActionList(ConfPaths.FIGHT_WRONGTURN_ACTIONS, + wrongTurnActions = config.getOptimizedActionList(ConfPaths.FIGHT_WRONGTURN_ACTIONS, CheckType.FIGHT_WRONGTURN.getPermission()); - yawRateCheck = data.getBoolean(ConfPaths.FIGHT_YAWRATE_CHECK, true); - cancelDead = data.getBoolean(ConfPaths.FIGHT_CANCELDEAD); - AlmostBoolean ref = data.getAlmostBoolean(ConfPaths.FIGHT_PVP_KNOCKBACKVELOCITY, AlmostBoolean.MAYBE); + cancelDead = config.getBoolean(ConfPaths.FIGHT_CANCELDEAD); + AlmostBoolean ref = config.getAlmostBoolean(ConfPaths.FIGHT_PVP_KNOCKBACKVELOCITY, AlmostBoolean.MAYBE); knockBackVelocityPvP = ref == AlmostBoolean.MAYBE ? Bugs.shouldPvpKnockBackVelocity() : ref.decide(); } - /* (non-Javadoc) - * @see fr.neatmonster.nocheatplus.checks.ICheckConfig#isEnabled(fr.neatmonster.nocheatplus.checks.CheckType) - */ - @Override - public final boolean isEnabled(final CheckType checkType) { - switch (checkType) { - case FIGHT_ANGLE: - return angleCheck; - case FIGHT_CRITICAL: - return criticalCheck; - case FIGHT_DIRECTION: - return directionCheck; - case FIGHT_GODMODE: - return godModeCheck; - case FIGHT_NOSWING: - return noSwingCheck; - case FIGHT_REACH: - return reachCheck; - case FIGHT_SPEED: - return speedCheck; - case FIGHT_SELFHIT: - return selfHitCheck; - case FIGHT_FASTHEAL: - return fastHealCheck; - default: - return true; - } - } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightData.java index 3556dd70..77c7d58e 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightData.java @@ -14,21 +14,11 @@ */ package fr.neatmonster.nocheatplus.checks.fight; -import java.util.Collection; -import java.util.HashMap; import java.util.LinkedList; -import java.util.Map; -import java.util.UUID; - -import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckData; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.checks.access.IRemoveSubCheckData; -import fr.neatmonster.nocheatplus.checks.access.SubCheckDataFactory; -import fr.neatmonster.nocheatplus.utilities.CheckTypeUtil; import fr.neatmonster.nocheatplus.utilities.PenaltyTime; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; @@ -37,112 +27,6 @@ import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; */ public class FightData extends ACheckData implements IRemoveSubCheckData { - public static class FightDataFactory implements CheckDataFactory { - - protected FightDataFactory() { - // Discourage creation here. - }; - - @Override - public final ICheckData getData(final Player player) { - return FightData.getData(player); - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return FightData.playersMap.get(playerName); - } - - @Override - public ICheckData removeData(final String playerName) { - return FightData.removeData(playerName); - } - - @Override - public void removeAllData() { - clear(); - } - - } - - - /** The factory for general fight data. */ - public static final CheckDataFactory factory = new FightDataFactory(); - - /** SelfHit factory */ - public static final CheckDataFactory selfHitDataFactory = new SubCheckDataFactory(CheckType.FIGHT, factory) { - - @Override - protected FightData getData(String playerName) { - return playersMap.get(playerName); - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return playersMap.get(playerName); - } - - @Override - protected Collection getPresentData() { - return playersMap.keySet(); - } - - @Override - protected boolean hasData(String playerName) { - return playersMap.containsKey(playerName); - } - - @Override - protected boolean removeFromData(String playerName, FightData data) { - if (data.selfHitVL.score(1f) > 0f) { - data.selfHitVL.clear(System.currentTimeMillis()); - return true; - } - else { - return false; - } - } - - }; - - - public static CheckDataFactory getCheckDataFactory(CheckType checkType) { - if (checkType != CheckType.FIGHT && !CheckTypeUtil.isAncestor(CheckType.FIGHT, checkType)) { - throw new IllegalArgumentException("Can only return a CheckDataFactory for the check group FIGHT."); - } - switch(checkType) { - // Note that CheckType does need adaption for new entries (!). - case FIGHT_SELFHIT: - return selfHitDataFactory; - default: - return factory; - } - } - - /** The map containing the data per players. */ - protected static final Map playersMap = new HashMap(); // Not sure about visibility (selfhit). - - /** - * Gets the data of a specified player. - * - * @param player - * the player - * @return the data - */ - public static FightData getData(final Player player) { - if (!playersMap.containsKey(player.getName())) - playersMap.put(player.getName(), new FightData(FightConfig.getConfig(player))); - return playersMap.get(player.getName()); - } - - public static ICheckData removeData(final String playerName) { - return playersMap.remove(playerName); - } - - public static void clear(){ - playersMap.clear(); - } - // Violation levels. public double angleVL; public double criticalVL; @@ -225,7 +109,6 @@ public class FightData extends ACheckData implements IRemoveSubCheckData { public FightData(final FightConfig config){ - super(config); speedBuckets = new ActionFrequency(config.speedBuckets, config.speedBucketDur); // Start with full fast-heal buffer. fastHealBuffer = config.fastHealBuffer; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightListener.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightListener.java index 8f5f98b8..fca8a880 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightListener.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/FightListener.java @@ -59,7 +59,7 @@ import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHand import fr.neatmonster.nocheatplus.components.registry.feature.JoinLeaveListener; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.build.BuildParameters; @@ -139,18 +139,19 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ */ private boolean handleNormalDamage(final Player player, final boolean attackerIsFake, final Entity damaged, final boolean damagedIsFake, - final double originalDamage, final double finalDamage, final int tick, final FightData data) { + final double originalDamage, final double finalDamage, + final int tick, final FightData data, final IPlayerData pData) { - final PlayerData pData = DataManager.getPlayerData(player); - final FightConfig cc = FightConfig.getConfig(player); + final FightConfig cc = pData.getGenericInstance(FightConfig.class); // Hotfix attempt for enchanted books. // TODO: maybe a generalized version for the future... // Illegal enchantments hotfix check. - if (Items.checkIllegalEnchantmentsAllHands(player)) { + if (Items.checkIllegalEnchantmentsAllHands(player, pData)) { return true; } + final boolean debug = pData.isDebugActive(checkType); boolean cancelled = false; final String worldName = player.getWorld().getName(); @@ -181,9 +182,11 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ else { tickAge = tick - data.lastAttackTick; // TODO: Maybe use 3d distance if dy(normalized) is too big. - targetMove = TrigUtil.distance(data.lastAttackedX, data.lastAttackedZ, damagedLoc.getX(), damagedLoc.getZ()); + targetMove = TrigUtil.distance(data.lastAttackedX, data.lastAttackedZ, + damagedLoc.getX(), damagedLoc.getZ()); msAge = (long) (50f * TickTask.getLag(50L * tickAge, true) * (float) tickAge); - normalizedMove = msAge == 0 ? targetMove : targetMove * Math.min(20.0, 1000.0 / (double) msAge); + normalizedMove = msAge == 0 ? targetMove + : targetMove * Math.min(20.0, 1000.0 / (double) msAge); } // TODO: calculate factor for dists: ticks * 50 * lag @@ -199,18 +202,23 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ // damagedPlayer.getLocation(useLoc2); // } // Log. - if (data.debug && DataManager.getPlayerData(damagedPlayer).hasPermission( + if (debug && DataManager.getPlayerData(damagedPlayer).hasPermission( Permissions.ADMINISTRATION_DEBUG, damagedPlayer)) { damagedPlayer.sendMessage("Attacked by " + player.getName() + ": inv=" + mcAccess.getHandle().getInvulnerableTicks(damagedPlayer) + " ndt=" + damagedPlayer.getNoDamageTicks()); } // Check for self hit exploits (mind that projectiles are excluded from this.) - if (selfHit.isEnabled(player) && selfHit.check(player, damagedPlayer, data, cc)) { + if (selfHit.isEnabled(player, pData) && selfHit.check(player, damagedPlayer, data, cc)) { cancelled = true; } // Get+update the damaged players. // TODO: Problem with NPCs: data stays (not a big problem). // (This is done even if the event has already been cancelled, to keep track, if the player is on a horse.) - damagedTrace = MovingData.getData(damagedPlayer).updateTrace(damagedPlayer, damagedLoc, tick, damagedIsFake ? null : mcAccess.getHandle()); + damagedTrace = DataManager.getPlayerData(damagedPlayer).getGenericInstance( + MovingData.class + ).updateTrace( + damagedPlayer, damagedLoc, tick, + damagedIsFake ? null : mcAccess.getHandle() + ); } else { damagedPlayer = null; // TODO: This is a temporary workaround. @@ -222,7 +230,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ } // Log generic properties of this attack. - if (data.debug) { + if (debug) { debug(player, "Attacks " + (damagedPlayer == null ? ("entity " + damaged.getType()) : ("player" + damagedPlayer.getName())) + " damage=" + (finalDamage == originalDamage ? finalDamage : (originalDamage + "/" + finalDamage))); } @@ -246,7 +254,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ if (tick == data.sweepTick && locHashCode == data.sweepLocationHashCode) { // TODO: Might limit the amount of 'too far off' sweep hits, possibly silent cancel for low frequency. // Could further guard by checking equality of loc to last location. - if (data.debug) { + if (debug) { debug(player, "(Assume sweep attack follow up damage.)"); } return cancelled; @@ -273,23 +281,25 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ // TODO: Add as real check. // TODO: Add something on packet level already. - if (wrongTurn.isEnabled(player, cc, pData) && wrongTurn.check(damagedPlayer, loc, data, cc)) { + if (pData.isCheckActive(CheckType.FIGHT_WRONGTURN, damagedPlayer) + && wrongTurn.check(damagedPlayer, loc, data, cc)) { cancelled = true; } // Run through the main checks. - if (!cancelled && speed.isEnabled(player)) { - if (speed.check(player, now)) { + if (!cancelled && speed.isEnabled(player, pData)) { + if (speed.check(player, now, data, cc, pData)) { cancelled = true; // Still feed the improbable. if (data.speedVL > 50) { - Improbable.check(player, 2f, now, "fight.speed"); + Improbable.check(player, 2f, now, "fight.speed", pData); } else { Improbable.feed(player, 2f, now); } } - else if (normalizedMove > 2.0 && Improbable.check(player, 1f, now, "fight.speed")) { + else if (normalizedMove > 2.0 && Improbable.check(player, 1f, now, + "fight.speed", pData)) { // Feed improbable in case of ok-moves too. // TODO: consider only feeding if attacking with higher average speed (!) cancelled = true; @@ -297,12 +307,12 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ } // TODO: Consider to always check improbable (first?). At least if config.always or speed or net.attackfrequency are enabled. - if (!cancelled && critical.isEnabled(player) && critical.check(player, loc, data, cc, pData)) { + if (!cancelled && critical.isEnabled(player, pData) && critical.check(player, loc, data, cc, pData)) { // TODO: Check config for settings. cancelled = true; } - if (!cancelled && noSwing.isEnabled(player) && noSwing.check(player, data, cc)) { + if (!cancelled && noSwing.isEnabled(player, pData) && noSwing.check(player, data, cc)) { cancelled = true; } @@ -313,13 +323,14 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ } if (!cancelled) { - final boolean reachEnabled = reach.isEnabled(player); - final boolean directionEnabled = direction.isEnabled(player); + final boolean reachEnabled = reach.isEnabled(player, pData); + final boolean directionEnabled = direction.isEnabled(player, pData); if (reachEnabled || directionEnabled) { if (damagedTrace != null) { // Checks that use the LocationTrace instance of the attacked entity/player. cancelled = locationTraceChecks(player, loc, data, cc, pData, - damaged, damagedIsFake, damagedLoc, damagedTrace, tick, now, reachEnabled, directionEnabled); + damaged, damagedIsFake, damagedLoc, damagedTrace, tick, now, debug, + reachEnabled, directionEnabled); } else { // Still use the classic methods for non-players. maybe[] @@ -337,18 +348,19 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ // Check angle with allowed window. // TODO: Actual angle needs to be related to the best matching trace element(s) (loop checks). - if (angle.isEnabled(player)) { + if (angle.isEnabled(player, pData)) { // TODO: Revise, use own trace. // The "fast turning" checks are checked in any case because they accumulate data. // Improbable yaw changing: Moving events might be missing up to a ten degrees change. - if (Combined.checkYawRate(player, loc.getYaw(), now, worldName, cc.yawRateCheck)) { + if (Combined.checkYawRate(player, loc.getYaw(), now, worldName, + pData.isCheckActive(CheckType.COMBINED_YAWRATE, player), pData)) { // (Check or just feed). // TODO: Work into this somehow attacking the same aim and/or similar aim position (not cancel then). cancelled = true; } // Angle check. if (angle.check(player, loc, damaged, worldChanged, data, cc)) { - if (!cancelled && data.debug) { + if (!cancelled && debug) { debug(player, "FIGHT_ANGLE cancel without yawrate cancel."); } cancelled = true; @@ -370,14 +382,14 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ // TODO: Confine further with simple pre-conditions. // TODO: Evaluate if moving traces can help here. if (!cancelled && TrigUtil.distance(loc.getX(), loc.getZ(), damagedLoc.getX(), damagedLoc.getZ()) < 4.5) { - final MovingData mData = MovingData.getData(player); + final MovingData mData = pData.getGenericInstance(MovingData.class); // Check if fly checks is an issue at all, re-check "real sprinting". final PlayerMoveData lastMove = mData.playerMoves.getFirstPastMove(); if (lastMove.valid && mData.liftOffEnvelope == LiftOffEnvelope.NORMAL) { final double hDist = TrigUtil.xzDistance(loc, lastMove.from); if (hDist >= 0.23) { // TODO: Might need to check hDist relative to speed / modifiers. - final MovingConfig mCc = MovingConfig.getConfig(player); + final MovingConfig mCc = pData.getGenericInstance(MovingConfig.class); final PlayerMoveInfo moveInfo = auxMoving.usePlayerMoveInfo(); moveInfo.set(player, loc, null, mCc.yOnGround); if (now <= mData.timeSprinting + mCc.sprintingGrace @@ -385,7 +397,8 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ // Judge as "lost sprint" problem. // TODO: What would mData.lostSprintCount > 0 mean here? mData.lostSprintCount = 7; - if ((data.debug || mCc.debug) && BuildParameters.debugLevel > 0) { + if ((debug || pData.isDebugActive(CheckType.MOVING)) + && BuildParameters.debugLevel > 0) { debug(player, "lostsprint: hDist to last from: " + hDist + " | targetdist=" + TrigUtil.distance(loc.getX(), loc.getZ(), damagedLoc.getX(), damagedLoc.getZ()) + " | sprinting=" + player.isSprinting() + " | food=" + player.getFoodLevel() +" | hbuf=" + mData.sfHorizontalBuffer); } } @@ -398,7 +411,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ // (Cancel after sprinting hacks, because of potential fp). if (!cancelled && data.attackPenalty.isPenalty(now)) { cancelled = true; - if (data.debug) { + if (debug) { debug(player, "~ attack penalty."); } } @@ -426,10 +439,11 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ * @return If to cancel (true) or not (false). */ private boolean locationTraceChecks(final Player player, final Location loc, - final FightData data, final FightConfig cc, final PlayerData pData, + final FightData data, final FightConfig cc, final IPlayerData pData, final Entity damaged, final boolean damagedIsFake, final Location damagedLoc, LocationTrace damagedTrace, - final long tick, final long now, final boolean reachEnabled, final boolean directionEnabled) { + final long tick, final long now, final boolean debug, + final boolean reachEnabled, final boolean directionEnabled) { // TODO: Order / splitting off generic stuff. /* * TODO: Abstract: interface with common setup/loop/post routine, only @@ -501,7 +515,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ } } // TODO: Log exact state, probably record min/max latency (individually). - if (data.debug && latencyEstimate >= 0) { + if (debug && latencyEstimate >= 0) { debug(player, "Latency estimate: " + latencyEstimate + " ms."); // FCFS rather, at present. } return cancelled; @@ -518,33 +532,44 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ final Entity damaged = event.getEntity(); final Player damagedPlayer = damaged instanceof Player ? (Player) damaged : null; - final FightData damagedData = damagedPlayer == null ? null : FightData.getData(damagedPlayer); + final FightData damagedData; final boolean damagedIsDead = damaged.isDead(); final boolean damagedIsFake = !crossPlugin.getHandle().isNativeEntity(damaged); - if (damagedPlayer != null && !damagedIsDead) { - // God mode check. - // (Do not test the savage.) - if (godMode.isEnabled(damagedPlayer) - && godMode.check(damagedPlayer, damagedIsFake, BridgeHealth.getDamage(event), damagedData)) { - // It requested to "cancel" the players invulnerability, so set their noDamageTicks to 0. - damagedPlayer.setNoDamageTicks(0); - } - // Adjust buffer for fast heal checks. - if (BridgeHealth.getHealth(damagedPlayer) >= BridgeHealth.getMaxHealth(damagedPlayer)) { - // TODO: Might use the same FightData instance for GodMode. - if (damagedData.fastHealBuffer < 0) { - // Reduce negative buffer with each full health. - damagedData.fastHealBuffer /= 2; + if (damagedPlayer != null) { + final IPlayerData damagedPData = DataManager.getPlayerData(damagedPlayer); + damagedData = damagedPData.getGenericInstance(FightData.class); + if (!damagedIsDead) { + // God mode check. + // (Do not test the savage.) + if (damagedPData.isCheckActive(CheckType.FIGHT_GODMODE, damagedPlayer) + && godMode.check(damagedPlayer, damagedIsFake, + BridgeHealth.getDamage(event), damagedData, damagedPData)) { + // It requested to "cancel" the players invulnerability, so set their noDamageTicks to 0. + damagedPlayer.setNoDamageTicks(0); } - // Set reference time. - damagedData.fastHealRefTime = System.currentTimeMillis(); + // Adjust buffer for fast heal checks. + if (BridgeHealth.getHealth(damagedPlayer) >= BridgeHealth.getMaxHealth(damagedPlayer)) { + // TODO: Might use the same FightData instance for GodMode. + if (damagedData.fastHealBuffer < 0) { + // Reduce negative buffer with each full health. + damagedData.fastHealBuffer /= 2; + } + // Set reference time. + damagedData.fastHealRefTime = System.currentTimeMillis(); + } + // TODO: TEST: Check unused velocity for the damaged player. (Needs more efficient pre condition checks.) + } - // TODO: TEST: Check unused velocity for the damaged player. (Needs more efficient pre condition checks.) - if (damagedData.debug) { + if (damagedPData.isDebugActive(checkType)) { // TODO: Pass result to further checks for reference? - UnusedVelocity.checkUnusedVelocity(damagedPlayer, CheckType.FIGHT); + UnusedVelocity.checkUnusedVelocity(damagedPlayer, CheckType.FIGHT, damagedPData); } } + else { + damagedData = null; + } + + // Attacking entities. if (event instanceof EntityDamageByEntityEvent) { onEntityDamageByEntity(damaged, damagedPlayer, damagedIsDead, damagedIsFake, @@ -591,14 +616,16 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ } } final FightData attackerData; + final IPlayerData attackerPData = attacker == null ? null : DataManager.getPlayerData(attacker); if (attacker != null) { - attackerData = FightData.getData(attacker); + + attackerData = attackerPData.getGenericInstance(FightData.class); // TODO: TEST: Check unused velocity for the attacker. (Needs more efficient pre condition checks.) - if (attackerData.debug) { + if (attackerPData.isDebugActive(checkType)) { // TODO: Pass result to further checks for reference? // TODO: attackerData.debug flag. // TODO: Fake players likely have unused velocity, just clear unused? - UnusedVelocity.checkUnusedVelocity(attacker, CheckType.FIGHT); + UnusedVelocity.checkUnusedVelocity(attacker, CheckType.FIGHT, attackerPData); } // Workaround for subsequent melee damage eventsfor explosions. TODO: Legacy or not, need a KB. if (damageCause == DamageCause.BLOCK_EXPLOSION || damageCause == DamageCause.ENTITY_EXPLOSION) { @@ -621,7 +648,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ } // Prevent attacking if a set back is scheduled. else if (MovingUtil.hasScheduledPlayerSetBack(player)) { - if (attackerData.debug) { + if (attackerPData.isDebugActive(checkType)) { // Use fight data flag for efficiency. debug(attacker, "Prevent melee attack, due to a scheduled set back."); } @@ -631,7 +658,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ else if (handleNormalDamage(player, !crossPlugin.getHandle().isNativePlayer(player), damaged, damagedIsFake, BridgeHealth.getOriginalDamage(event), BridgeHealth.getFinalDamage(event), - tick, attackerData)) { + tick, attackerData, attackerPData)) { event.setCancelled(true); } } @@ -643,7 +670,8 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ final Entity damaged = event.getEntity(); if (damaged instanceof Player) { final Player damagedPlayer = (Player) damaged; - final FightData damagedData = FightData.getData(damagedPlayer); + final IPlayerData damagedPData = DataManager.getPlayerData(damagedPlayer); + final FightData damagedData = damagedPData.getGenericInstance(FightData.class); final int ndt = damagedPlayer.getNoDamageTicks(); if (damagedData.lastDamageTick == TickTask.getTick() && damagedData.lastNoDamageTicks != ndt) { // Plugin compatibility thing. @@ -654,9 +682,11 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ case ENTITY_ATTACK: if (event instanceof EntityDamageByEntityEvent) { final Entity entity = ((EntityDamageByEntityEvent) event).getDamager(); - if ((entity instanceof Player) && !damagedPlayer.isInsideVehicle() && FightConfig.getConfig(damagedPlayer).knockBackVelocityPvP) { + if ((entity instanceof Player) && !damagedPlayer.isInsideVehicle() + && damagedPData.getGenericInstance(FightConfig.class).knockBackVelocityPvP) { // TODO: Use the velocity event that is sent anyway and replace x/z if 0 (queue max. values). - applyKnockBack((Player) entity, damagedPlayer, damagedData); + applyKnockBack((Player) entity, damagedPlayer, + damagedData, damagedPData); } } default: @@ -671,17 +701,18 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ * @param damagedPlayer * @param damagedData */ - private void applyKnockBack(final Player attacker, final Player damagedPlayer, final FightData damagedData) { + private void applyKnockBack(final Player attacker, final Player damagedPlayer, + final FightData damagedData, final IPlayerData pData) { final double level = getKnockBackLevel(attacker); - final MovingData mdata = MovingData.getData(damagedPlayer); - final MovingConfig mcc = MovingConfig.getConfig(damagedPlayer); + final MovingData mdata = pData.getGenericInstance(MovingData.class); + final MovingConfig mcc = pData.getGenericInstance(MovingConfig.class); // TODO: How is the direction really calculated? // Aim at sqrt(vx * vx + vz * vz, 2), not the exact direction. final double vx = level / Math.sqrt(8.0); final double vz = vx; final double vy = 0.462; // TODO: (0.365) Needs other workarounds, to allow more when moving off ground (vel + GRAVITY_MAX or max jump gain + little?). useLoc1.setWorld(null); // Cleanup. - if (damagedData.debug || mdata.debug) { + if (pData.isDebugActive(checkType) || pData.isDebugActive(CheckType.MOVING)) { debug(damagedPlayer, "Received knockback level: " + level); } mdata.addVelocity(damagedPlayer, mcc, vx, vy, vz, VelocityFlags.ORIGIN_PVP); @@ -742,7 +773,8 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ * TODO: First one always fails: Packet inversion on 1.12.2? This could * be moved to packet level (register either). */ - FightData.getData(event.getPlayer()).noSwingArmSwung = true; + DataManager.getGenericInstance(event.getPlayer(), + FightData.class).noSwingArmSwung = true; } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) @@ -763,7 +795,9 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ return; } // TODO: EATING reason / peaceful difficulty / regen potion - byCaptain SpigotMC - if (fastHeal.isEnabled(player) && fastHeal.check(player)) { + final IPlayerData pData = DataManager.getPlayerData(player); + if (pData.isCheckActive(CheckType.FIGHT_FASTHEAL, player) + && fastHeal.check(player, pData)) { // TODO: Can clients force events with 0-re-gain ? event.setCancelled(true); } @@ -776,7 +810,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ return; } final Player player = (Player) entity; - final FightData data = FightData.getData(player); + final FightData data = DataManager.getGenericInstance(player, FightData.class); // Adjust god mode data: // Remember the time. data.regainHealthTime = System.currentTimeMillis(); @@ -792,21 +826,23 @@ public class FightListener extends CheckListener implements JoinLeaveListener{ @Override public void playerLeaves(final Player player) { - final FightData data = FightData.getData(player); + final FightData data = DataManager.getGenericInstance(player, FightData.class); data.angleHits.clear(); } @EventHandler(priority = EventPriority.MONITOR) public void onPlayerChangedWorld(final PlayerChangedWorldEvent event) { - FightData.getData(event.getPlayer()).onWorldChange(); + DataManager.getGenericInstance(event.getPlayer(), + FightData.class).onWorldChange(); } @EventHandler(ignoreCancelled = false, priority = EventPriority.MONITOR) public void onItemHeld(final PlayerItemHeldEvent event) { final Player player = event.getPlayer(); - final long penalty = FightConfig.getConfig(player).toolChangeAttackPenalty; + final IPlayerData pData = DataManager.getPlayerData(player); + final long penalty = pData.getGenericInstance(FightConfig.class).toolChangeAttackPenalty; if (penalty > 0 ) { - FightData.getData(player).attackPenalty.applyPenalty(penalty); + pData.getGenericInstance(FightData.class).attackPenalty.applyPenalty(penalty); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/GodMode.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/GodMode.java index 569115dd..10c66909 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/GodMode.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/GodMode.java @@ -24,6 +24,7 @@ import fr.neatmonster.nocheatplus.checks.net.NetData; import fr.neatmonster.nocheatplus.compat.BridgeHealth; import fr.neatmonster.nocheatplus.compat.IBridgeCrossPlugin; import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.TickTask; @@ -47,7 +48,8 @@ public class GodMode extends Check { * @param damage * @return */ - public boolean check(final Player player, final boolean playerIsFake, final double damage, final FightData data){ + public boolean check(final Player player, final boolean playerIsFake, + final double damage, final FightData data, final IPlayerData pData){ final int tick = TickTask.getTick(); final int noDamageTicks = Math.max(0, player.getNoDamageTicks()); @@ -145,16 +147,16 @@ public class GodMode extends Check { } } - final FightConfig cc = FightConfig.getConfig(player); + final FightConfig cc = pData.getGenericInstance(FightConfig.class); // Check for client side lag. final long now = System.currentTimeMillis(); final long maxAge = cc.godModeLagMaxAge; long keepAlive = Long.MIN_VALUE; if (NCPAPIProvider.getNoCheatPlusAPI().hasFeatureTag("checks", "KeepAliveFrequency")) { - keepAlive = ((NetData) (CheckType.NET_KEEPALIVEFREQUENCY.getDataFactory().getData(player))).lastKeepAliveTime; + keepAlive = pData.getGenericInstance(NetData.class).lastKeepAliveTime; } - keepAlive = Math.max(keepAlive, CheckUtils.guessKeepAliveTime(player, now, maxAge)); + keepAlive = Math.max(keepAlive, CheckUtils.guessKeepAliveTime(player, now, maxAge, pData)); if (keepAlive != Double.MIN_VALUE && now - keepAlive > cc.godModeLagMinAge && now - keepAlive < maxAge){ // Assume lag. @@ -169,7 +171,8 @@ public class GodMode extends Check { if (data.godModeAcc > 2){ // TODO: To match with old checks vls / actions, either change actions or apply a factor. data.godModeVL += delta; - if (executeActions(player, data.godModeVL, delta, FightConfig.getConfig(player).godModeActions).willCancel()){ + if (executeActions(player, data.godModeVL, delta, + pData.getGenericInstance(FightConfig.class).godModeActions).willCancel()){ cancel = true; } else { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Reach.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Reach.java index 2b6220e8..55b29b7b 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Reach.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Reach.java @@ -29,7 +29,7 @@ import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.combined.Improbable; import fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace.ITraceEntry; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.location.TrigUtil; @@ -71,7 +71,7 @@ public class Reach extends Check { */ public boolean check(final Player player, final Location pLoc, final Entity damaged, final boolean damagedIsFake, final Location dRef, - final FightData data, final FightConfig cc, final PlayerData pData) { + final FightData data, final FightConfig cc, final IPlayerData pData) { boolean cancel = false; // The maximum distance allowed to interact with an entity in survival mode. @@ -114,7 +114,8 @@ public class Reach extends Check { // Execute whatever actions are associated with this check and the violation level and find out if we should // cancel the event. cancel = executeActions(player, data.reachVL, violation, cc.reachActions).willCancel(); - if (Improbable.check(player, (float) violation / 2f, System.currentTimeMillis(), "fight.reach")){ + if (Improbable.check(player, (float) violation / 2f, System.currentTimeMillis(), + "fight.reach", pData)){ cancel = true; } if (cancel && cc.reachPenalty > 0){ @@ -146,7 +147,7 @@ public class Reach extends Check { data.reachMod = Math.min(1.0, data.reachMod + DYNAMIC_STEP); } - if (data.debug && pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)){ + if (pData.isDebugActive(type) && pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)){ player.sendMessage("NC+: Attack/reach " + damaged.getType()+ " height="+ StringUtil.fdec3.format(height) + " dist=" + StringUtil.fdec3.format(lenpRel) +" @" + StringUtil.fdec3.format(reachMod)); } @@ -163,7 +164,9 @@ public class Reach extends Check { * @param cc * @return */ - public ReachContext getContext(final Player player, final Location pLoc, final Entity damaged, final Location damagedLoc, final FightData data, final FightConfig cc) { + public ReachContext getContext(final Player player, final Location pLoc, + final Entity damaged, final Location damagedLoc, + final FightData data, final FightConfig cc) { final ReachContext context = new ReachContext(); context.distanceLimit = player.getGameMode() == GameMode.CREATIVE ? CREATIVE_DISTANCE : cc.reachSurvivalDistance + getDistMod(damaged); context.distanceMin = (context.distanceLimit - cc.reachReduceDistance) / context.distanceLimit; @@ -234,7 +237,7 @@ public class Reach extends Check { */ public boolean loopFinish(final Player player, final Location pLoc, final Entity damaged, final ReachContext context, final ITraceEntry traceEntry, final boolean forceViolation, - final FightData data, final FightConfig cc, final PlayerData pData) { + final FightData data, final FightConfig cc, final IPlayerData pData) { final double lenpRel = forceViolation && context.minViolation != Double.MAX_VALUE ? context.minViolation : context.minResult; if (lenpRel == Double.MAX_VALUE) { return false; @@ -251,7 +254,8 @@ public class Reach extends Check { // Execute whatever actions are associated with this check and the violation level and find out if we should // cancel the event. cancel = executeActions(player, data.reachVL, violation, cc.reachActions).willCancel(); - if (Improbable.check(player, (float) violation / 2f, System.currentTimeMillis(), "fight.reach")){ + if (Improbable.check(player, (float) violation / 2f, System.currentTimeMillis(), + "fight.reach", pData)){ cancel = true; } if (cancel && cc.reachPenalty > 0){ @@ -284,7 +288,7 @@ public class Reach extends Check { data.reachMod = Math.min(1.0, data.reachMod + DYNAMIC_STEP); } - if (data.debug && pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)){ + if (pData.isDebugActive(type) && pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)){ // TODO: Height: remember successful ITraceEntry player.sendMessage("NC+: Attack/reach " + damaged.getType()+ (traceEntry == null ? "" : (" height=" + traceEntry.getBoxMarginVertical())) + " dist=" + StringUtil.fdec3.format(lenpRel) +" @" + StringUtil.fdec3.format(data.reachMod)); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Speed.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Speed.java index 6ffaecfb..70e1e662 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Speed.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/Speed.java @@ -20,6 +20,7 @@ import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.TickTask; /** @@ -42,10 +43,11 @@ public class Speed extends Check { * @param now * @return true, if successful */ - public boolean check(final Player player, final long now) { - final FightConfig cc = FightConfig.getConfig(player); - final FightData data = FightData.getData(player); + public boolean check(final Player player, final long now, + final FightData data, final FightConfig cc, + final IPlayerData pData) { + final boolean lag = pData.getCurrentWorldData().shouldAdjustToLag(type); boolean cancel = false; // Add to frequency. @@ -53,7 +55,7 @@ public class Speed extends Check { // Medium term (normalized to one second), account for server side lag. final long fullTime = cc.speedBucketDur * cc.speedBuckets; - final float fullLag = cc.lag ? TickTask.getLag(fullTime, true) : 1f; + final float fullLag = lag ? TickTask.getLag(fullTime, true) : 1f; final float total = data.speedBuckets.score(cc.speedBucketFactor) * 1000f / (fullLag * fullTime); // Short term. @@ -65,7 +67,7 @@ public class Speed extends Check { } else if (tick - data.speedShortTermTick < cc.speedShortTermTicks){ // Account for server side lag. - if (!cc.lag || TickTask.getLag(50L * (tick - data.speedShortTermTick), true) < 1.5f){ + if (!lag || TickTask.getLag(50L * (tick - data.speedShortTermTick), true) < 1.5f){ // Within range, add. data.speedShortTermCount ++; } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/WrongTurn.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/WrongTurn.java index 21d7d099..9ea80f2e 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/WrongTurn.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/fight/WrongTurn.java @@ -1,3 +1,17 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package fr.neatmonster.nocheatplus.checks.fight; import org.bukkit.Location; @@ -18,7 +32,8 @@ public class WrongTurn extends Check { super(CheckType.FIGHT_WRONGTURN); } - public boolean check (final Player player, final Location loc, final FightData data, final FightConfig cc) { + public boolean check (final Player player, final Location loc, + final FightData data, final FightConfig cc) { final float pitch = loc.getPitch(); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/generic/block/AbstractBlockDirectionCheck.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/generic/block/AbstractBlockDirectionCheck.java index 07184d29..f82487b5 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/generic/block/AbstractBlockDirectionCheck.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/generic/block/AbstractBlockDirectionCheck.java @@ -26,6 +26,7 @@ import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.checks.net.FlyingQueueHandle; import fr.neatmonster.nocheatplus.checks.net.FlyingQueueLookBlockChecker; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.collision.CollideRayVsAABB; import fr.neatmonster.nocheatplus.utilities.collision.ICollideRayVsAABB; import fr.neatmonster.nocheatplus.utilities.location.LocUtil; @@ -128,7 +129,8 @@ public abstract class AbstractBlockDirectionCheck worldsMap = new HashMap(); - - /** - * Clear all the configurations. - */ - public static void clear() { - worldsMap.clear(); - } - - /** - * Gets the configuration for a specified player. - * - * @param player - * the player - * @return the configuration - */ - public static InventoryConfig getConfig(final Player player) { - return getConfig(player.getWorld()); - } - - public static InventoryConfig getConfig(final World world) { - return getWorldConfig(world.getName()); - } - - public static final InventoryConfig getWorldConfig(final String worldName) { - InventoryConfig cc = worldsMap.get(worldName); - if (cc == null) { - cc = new InventoryConfig(ConfigManager.getConfigFile(worldName)); - worldsMap.put(worldName, cc); - } - return cc; - } - - public final boolean dropCheck; public final int dropLimit; public final long dropTimeFrame; public final ActionList dropActions; - public final boolean fastClickCheck; public final boolean fastClickSpareCreative; public final boolean fastClickTweaks1_5; public final float fastClickShortTermLimit; public final float fastClickNormalLimit; public final ActionList fastClickActions; - public final boolean fastConsumeCheck; public final long fastConsumeDuration; public final boolean fastConsumeWhitelist; public final Set fastConsumeItems = new HashSet(); public final ActionList fastConsumeActions; - public final boolean gutenbergCheck; public final ActionList gutenbergActions; - public final boolean instantBowCheck; public final boolean instantBowStrict; public final long instantBowDelay; public final boolean instantBowImprobableFeedOnly; public final float instantBowImprobableWeight; public final ActionList instantBowActions; - public final boolean instantEatCheck; public final ActionList instantEatActions; - public final boolean itemsCheck; - - public final boolean openCheck; public final boolean openClose; public final boolean openCancelOther; @@ -133,77 +70,38 @@ public class InventoryConfig extends ACheckConfig { * @param data * the data */ - public InventoryConfig(final ConfigFile data) { - super(data, ConfPaths.INVENTORY); - dropCheck = data.getBoolean(ConfPaths.INVENTORY_DROP_CHECK); + public InventoryConfig(final WorldData worldData) { + super(worldData); + final ConfigFile data = worldData.getRawConfiguration(); dropLimit = data.getInt(ConfPaths.INVENTORY_DROP_LIMIT); dropTimeFrame = data.getLong(ConfPaths.INVENTORY_DROP_TIMEFRAME); dropActions = data.getOptimizedActionList(ConfPaths.INVENTORY_DROP_ACTIONS, Permissions.INVENTORY_DROP); - fastClickCheck = data.getBoolean(ConfPaths.INVENTORY_FASTCLICK_CHECK); fastClickSpareCreative = data.getBoolean(ConfPaths.INVENTORY_FASTCLICK_SPARECREATIVE); fastClickTweaks1_5 = data.getBoolean(ConfPaths.INVENTORY_FASTCLICK_TWEAKS1_5); fastClickShortTermLimit = (float) data.getDouble(ConfPaths.INVENTORY_FASTCLICK_LIMIT_SHORTTERM); fastClickNormalLimit = (float) data.getDouble(ConfPaths.INVENTORY_FASTCLICK_LIMIT_NORMAL); fastClickActions = data.getOptimizedActionList(ConfPaths.INVENTORY_FASTCLICK_ACTIONS, Permissions.INVENTORY_FASTCLICK); - fastConsumeCheck = data.getBoolean(ConfPaths.INVENTORY_FASTCONSUME_CHECK); fastConsumeDuration = (long) (1000.0 * data.getDouble(ConfPaths.INVENTORY_FASTCONSUME_DURATION)); fastConsumeWhitelist = data.getBoolean(ConfPaths.INVENTORY_FASTCONSUME_WHITELIST); data.readMaterialFromList(ConfPaths.INVENTORY_FASTCONSUME_ITEMS, fastConsumeItems); fastConsumeActions = data.getOptimizedActionList(ConfPaths.INVENTORY_FASTCONSUME_ACTIONS, Permissions.INVENTORY_FASTCONSUME); - gutenbergCheck = data.getBoolean(ConfPaths.INVENTORY_GUTENBERG_CHECK); gutenbergActions = data.getOptimizedActionList(ConfPaths.INVENTORY_GUTENBERG_ACTIONS, Permissions.INVENTORY_GUTENBERG); - instantBowCheck = data.getBoolean(ConfPaths.INVENTORY_INSTANTBOW_CHECK); instantBowStrict = data.getBoolean(ConfPaths.INVENTORY_INSTANTBOW_STRICT); instantBowDelay = data.getInt(ConfPaths.INVENTORY_INSTANTBOW_DELAY); instantBowImprobableFeedOnly = data.getBoolean(ConfPaths.INVENTORY_INSTANTBOW_IMPROBABLE_FEEDONLY); instantBowImprobableWeight = (float) data.getDouble(ConfPaths.INVENTORY_INSTANTBOW_IMPROBABLE_WEIGHT); instantBowActions = data.getOptimizedActionList(ConfPaths.INVENTORY_INSTANTBOW_ACTIONS, Permissions.INVENTORY_INSTANTBOW); - instantEatCheck = data.getBoolean(ConfPaths.INVENTORY_INSTANTEAT_CHECK); instantEatActions = data.getOptimizedActionList(ConfPaths.INVENTORY_INSTANTEAT_ACTIONS, Permissions.INVENTORY_INSTANTEAT); - itemsCheck = data.getBoolean(ConfPaths.INVENTORY_ITEMS_CHECK); - - openCheck = data.getBoolean(ConfPaths.INVENTORY_OPEN_CHECK); openClose = data.getBoolean(ConfPaths.INVENTORY_OPEN_CLOSE); openCancelOther = data.getBoolean(ConfPaths.INVENTORY_OPEN_CANCELOTHER); hotFixFallingBlockEndPortalActive = data.getBoolean(ConfPaths.INVENTORY_HOTFIX_DUPE_FALLINGBLOCKENDPORTAL); } - /* - * (non-Javadoc) - * - * @see - * fr.neatmonster.nocheatplus.checks.ICheckConfig#isEnabled(fr.neatmonster - * .nocheatplus.checks.CheckType) - */ - @Override - public final boolean isEnabled(final CheckType checkType) { - switch (checkType) { - case INVENTORY_FASTCLICK: - return fastClickCheck; - case INVENTORY_ITEMS: - return itemsCheck; - case INVENTORY_OPEN: - return openCheck; - case INVENTORY_DROP: - return dropCheck; - case INVENTORY_INSTANTBOW: - return instantBowCheck; - case INVENTORY_INSTANTEAT: - return instantEatCheck; - case INVENTORY_FASTCONSUME: - return fastConsumeCheck; - case INVENTORY_GUTENBERG: - return gutenbergCheck; - default: - return true; - } - } - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java index 1a4b8212..fab8d995 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java @@ -14,16 +14,9 @@ */ package fr.neatmonster.nocheatplus.checks.inventory; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - import org.bukkit.Material; -import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.access.ACheckData; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; /** @@ -31,53 +24,6 @@ import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; */ public class InventoryData extends ACheckData { - /** The factory creating data. */ - public static final CheckDataFactory factory = new CheckDataFactory() { - @Override - public final ICheckData getData(final Player player) { - return InventoryData.getData(player); - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return InventoryData.playersMap.get(playerName); - } - - @Override - public ICheckData removeData(final String playerName) { - return InventoryData.removeData(playerName); - } - - @Override - public void removeAllData() { - clear(); - } - }; - - /** The map containing the data per players. */ - private static final Map playersMap = new HashMap(); - - /** - * Gets the data of a specified player. - * - * @param player - * the player - * @return the data - */ - public static InventoryData getData(final Player player) { - if (!playersMap.containsKey(player.getName())) - playersMap.put(player.getName(), new InventoryData(InventoryConfig.getConfig(player))); - return playersMap.get(player.getName()); - } - - public static ICheckData removeData(final String playerName) { - return playersMap.remove(playerName); - } - - public static void clear(){ - playersMap.clear(); - } - // Violation levels. public double dropVL; public double fastClickVL; @@ -107,8 +53,4 @@ public class InventoryData extends ACheckData { public Material instantEatFood; public long instantEatInteract; - public InventoryData(final InventoryConfig config) { - super(config); - } - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java index f0b13432..52ca7bb8 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java @@ -56,7 +56,7 @@ import fr.neatmonster.nocheatplus.components.entity.IEntityAccessVehicle; import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle; import fr.neatmonster.nocheatplus.components.registry.feature.JoinLeaveListener; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.InventoryUtil; @@ -110,14 +110,16 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen // Only if a player shot the arrow. if (event.getEntity() instanceof Player) { final Player player = (Player) event.getEntity(); - if (instantBow.isEnabled(player)) { + final IPlayerData pData = DataManager.getPlayerData(player); + if (instantBow.isEnabled(player, pData)) { final long now = System.currentTimeMillis(); final Location loc = player.getLocation(useLoc); - if (Combined.checkYawRate(player, loc.getYaw(), now, loc.getWorld().getName())) { + if (Combined.checkYawRate(player, loc.getYaw(), now, + loc.getWorld().getName(), pData)) { // No else if with this, could be cancelled due to other checks feeding, does not have actions. event.setCancelled(true); } - final InventoryConfig cc = InventoryConfig.getConfig(player); + final InventoryConfig cc = pData.getGenericInstance(InventoryConfig.class); // Still check instantBow, whatever yawrate says. if (instantBow.check(player, event.getForce(), now)) { // The check requested the event to be cancelled. @@ -127,7 +129,8 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen if (cc.instantBowImprobableFeedOnly) { Improbable.feed(player, cc.instantBowImprobableWeight, now); } - else if (Improbable.check(player, cc.instantBowImprobableWeight, now, "inventory.instantbow")) { + else if (Improbable.check(player, cc.instantBowImprobableWeight, + now, "inventory.instantbow", pData)) { // Combined fighting speed (Else if: Matter of taste, preventing extreme cascading and actions spam). event.setCancelled(true); } @@ -150,7 +153,9 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen // Only if a player ate food. if (event.getEntity() instanceof Player) { final Player player = (Player) event.getEntity(); - if (instantEat.isEnabled(player) && instantEat.check(player, event.getFoodLevel())) { + final IPlayerData pData = DataManager.getPlayerData(player); + if (instantEat.isEnabled(player, pData) + && instantEat.check(player, event.getFoodLevel())) { event.setCancelled(true); } else if (player.isDead() && BridgeHealth.getHealth(player) <= 0.0) { @@ -179,9 +184,10 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen return; } final Player player = (Player) entity; - final InventoryData data = InventoryData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final InventoryData data = pData.getGenericInstance(InventoryData.class); final int slot = event.getSlot(); - if (data.debug) { + if (pData.isDebugActive(checkType)) { outputDebugInventoryClick(player, slot, event, data); } if (slot == InventoryView.OUTSIDE || slot < 0) { @@ -194,14 +200,14 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen boolean cancel = false; // Illegal enchantment checks. try{ - if (!cancel && Items.checkIllegalEnchantments(player, clicked)) { + if (!cancel && Items.checkIllegalEnchantments(player, clicked, pData)) { cancel = true; counters.addPrimaryThread(idIllegalItem, 1); } } catch(final ArrayIndexOutOfBoundsException e) {} // Hotfix (CB) try{ - if (!cancel && Items.checkIllegalEnchantments(player, cursor)) { + if (!cancel && Items.checkIllegalEnchantments(player, cursor, pData)) { cancel = true; counters.addPrimaryThread(idIllegalItem, 1); } @@ -209,10 +215,9 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen catch(final ArrayIndexOutOfBoundsException e) {} // Hotfix (CB) // Fast inventory manipulation check. - if (fastClick.isEnabled(player)) { - final InventoryConfig cc = InventoryConfig.getConfig(player); + if (fastClick.isEnabled(player, pData)) { + final InventoryConfig cc = pData.getGenericInstance(InventoryConfig.class); if (player.getGameMode() != GameMode.CREATIVE || !cc.fastClickSpareCreative) { - final PlayerData pData = DataManager.getPlayerData(player); if (fastClick.check(player, now, event.getView(), slot, cursor, clicked, event.isShiftClick(), data, cc, pData)) { @@ -301,20 +306,21 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen public void onPlayerDropItem(final PlayerDropItemEvent event) { final Player player = event.getPlayer(); + final IPlayerData pData = DataManager.getPlayerData(player); // Illegal enchantments hotfix check. final Item item = event.getItemDrop(); if (item != null) { // No cancel here. - Items.checkIllegalEnchantments(player, item.getItemStack()); + Items.checkIllegalEnchantments(player, item.getItemStack(), pData); } // If the player died, all their items are dropped so ignore them. if (event.getPlayer().isDead()) return; - if (drop.isEnabled(event.getPlayer())) { - if (drop.check(event.getPlayer())) { + if (pData.isCheckActive(CheckType.INVENTORY_DROP, player)) { + if (drop.check(player)) { // TODO: Is the following command still correct? If so, adapt actions. /* * Cancelling drop events is not save (in certain circumstances @@ -341,7 +347,8 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen return; final Player player = event.getPlayer(); - final InventoryData data = InventoryData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final InventoryData data = pData.getGenericInstance(InventoryData.class); boolean resetAll = false; @@ -366,7 +373,7 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen } else resetAll = true; // Illegal enchantments hotfix check. - if (Items.checkIllegalEnchantments(player, item)) { + if (Items.checkIllegalEnchantments(player, item, pData)) { event.setCancelled(true); counters.addPrimaryThread(idIllegalItem, 1); } @@ -377,7 +384,8 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen if (resetAll) { // Nothing that we are interested in, reset data. - if (data.debug && data.instantEatFood != null) { + if (pData.isDebugActive(CheckType.INVENTORY_INSTANTEAT) + && data.instantEatFood != null) { debug(player, "PlayerInteractEvent, reset fastconsume (legacy: instanteat)."); } data.instantBowInteract = 0; @@ -407,7 +415,7 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen Entity entity = event.getRightClicked(); if (stack != null && stack.getType() == Material.MONSTER_EGG && (entity == null || entity instanceof LivingEntity || entity instanceof ComplexEntityPart) - && items.isEnabled(player)) { + && items.isEnabled(player, DataManager.getPlayerData(player))) { event.setCancelled(true); counters.addPrimaryThread(idEggOnEntity, 1); return; @@ -428,8 +436,9 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen @EventHandler(priority = EventPriority.MONITOR) public void onItemHeldChange(final PlayerItemHeldEvent event) { final Player player = event.getPlayer(); - final InventoryData data = InventoryData.getData(player); - if (data.debug && data.instantEatFood != null) { + final IPlayerData pData = DataManager.getPlayerData(player); + final InventoryData data = pData.getGenericInstance(InventoryData.class); + if (pData.isDebugActive(checkType) && data.instantEatFood != null) { debug(player, "PlayerItemHeldEvent, reset fastconsume (legacy: instanteat)."); } data.instantBowInteract = 0; @@ -438,8 +447,8 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen // Illegal enchantments hotfix check. final PlayerInventory inv = player.getInventory(); - Items.checkIllegalEnchantments(player, inv.getItem(event.getNewSlot())); - Items.checkIllegalEnchantments(player, inv.getItem(event.getPreviousSlot())); + Items.checkIllegalEnchantments(player, inv.getItem(event.getNewSlot()), pData); + Items.checkIllegalEnchantments(player, inv.getItem(event.getPreviousSlot()), pData); } @EventHandler(priority = EventPriority.MONITOR) diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Items.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Items.java index 18e0ca5c..cc9150ee 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Items.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Items.java @@ -25,6 +25,7 @@ import org.bukkit.inventory.ItemStack; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.compat.Bridge1_9; +import fr.neatmonster.nocheatplus.players.IPlayerData; public class Items extends Check{ @@ -42,12 +43,14 @@ public class Items extends Check{ * @param player * @return True if the check is failed. */ - public static final boolean checkIllegalEnchantmentsAllHands(final Player player) { + public static final boolean checkIllegalEnchantmentsAllHands(final Player player, + final IPlayerData pData) { boolean result = false; - if (checkIllegalEnchantments(player, Bridge1_9.getItemInMainHand(player))) { + if (checkIllegalEnchantments(player, Bridge1_9.getItemInMainHand(player), pData)) { result = true; } - if (Bridge1_9.hasGetItemInOffHand() && checkIllegalEnchantments(player, Bridge1_9.getItemInOffHand(player))) { + if (Bridge1_9.hasGetItemInOffHand() + && checkIllegalEnchantments(player, Bridge1_9.getItemInOffHand(player), pData)) { result = true; } return result; @@ -61,7 +64,8 @@ public class Items extends Check{ * @param stack * @return True if the check is failed. */ - public static final boolean checkIllegalEnchantments(final Player player, final ItemStack stack){ + public static final boolean checkIllegalEnchantments(final Player player, + final ItemStack stack, final IPlayerData pData){ if (stack == null) { return false; } @@ -70,7 +74,7 @@ public class Items extends Check{ // TODO: Make stuff configurable. if (type == Material.WRITTEN_BOOK){ final Map enchantments = stack.getEnchantments(); - if (enchantments != null && !enchantments.isEmpty() && instance.isEnabled(player)){ + if (enchantments != null && !enchantments.isEmpty() && pData.isCheckActive(instance.type, player)){ // TODO: differentiate sub checks maybe or add extra permissions, later. for (final Enchantment ench : new HashSet(enchantments.keySet())){ stack.removeEnchantment(ench); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Open.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Open.java index 5322433a..c5dbd918 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Open.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/Open.java @@ -24,6 +24,8 @@ import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.components.registry.event.IHandle; import fr.neatmonster.nocheatplus.components.registry.feature.IDisableListener; import fr.neatmonster.nocheatplus.hooks.ExemptionSettings; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.InventoryUtil; /** @@ -74,7 +76,8 @@ public class Open extends Check implements IDisableListener{ || !InventoryUtil.hasInventoryOpen(player)) { return false; } - final InventoryConfig cc = InventoryConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final InventoryConfig cc = pData.getGenericInstance(InventoryConfig.class); if (cc.openClose) { final UUID id = player.getUniqueId(); if (this.nestedPlayer == null || !id.equals(this.nestedPlayer)) { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingConfig.java index 2ad9e015..981905f4 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingConfig.java @@ -29,8 +29,6 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.actions.ActionList; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckConfig; -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; import fr.neatmonster.nocheatplus.checks.moving.magic.Magic; import fr.neatmonster.nocheatplus.checks.moving.model.ModelFlying; import fr.neatmonster.nocheatplus.checks.moving.player.PlayerSetBackMethod; @@ -40,13 +38,14 @@ import fr.neatmonster.nocheatplus.compat.AlmostBoolean; import fr.neatmonster.nocheatplus.compat.Bridge1_9; import fr.neatmonster.nocheatplus.compat.versions.Bugs; import fr.neatmonster.nocheatplus.compat.versions.ServerVersion; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.utilities.ColorUtil; import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.SimpleCharPrefixTree; import fr.neatmonster.nocheatplus.utilities.location.PlayerLocation; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Configurations specific for the moving checks. Every world gets one of these @@ -54,59 +53,6 @@ import fr.neatmonster.nocheatplus.utilities.location.PlayerLocation; */ public class MovingConfig extends ACheckConfig { - /** The factory creating configurations. */ - public static final CheckConfigFactory factory = new CheckConfigFactory() { - @Override - public final ICheckConfig getConfig(final Player player) { - return MovingConfig.getConfig(player); - } - - @Override - public void removeAllConfigs() { - clear(); // Band-aid. - } - }; - - /** The map containing the configurations per world. */ - private static final Map worldsMap = new HashMap(); - - /** - * Clear all the configurations. - */ - public static void clear() { - worldsMap.clear(); - } - - /** - * Gets the configuration for a specified player .
- * NOTE: Currently only per-world configs are implemented. This method might - * or might not get removed some day. - * - * @param player - * the player - * @return the configuration - */ - public static MovingConfig getConfig(final Player player) { - return getConfig(player.getWorld().getName()); - } - - /** - * Get a per-world config. - * - * @param worldName - * Exact case world name. - * @return - */ - public static MovingConfig getConfig(final String worldName) { - final MovingConfig cc = worldsMap.get(worldName); - if (cc != null){ - return cc; - } - final MovingConfig ccNew = new MovingConfig(ConfigManager.getConfigFile(worldName)); - worldsMap.put(worldName, ccNew); - return ccNew; - } - // Model flying ids. public static final String ID_JETPACK_ELYTRA = "jetpack.elytra"; public static final String ID_POTION_LEVITATION = "potion.levitation"; @@ -116,13 +62,11 @@ public class MovingConfig extends ACheckConfig { public final boolean ignoreCreative; public final boolean ignoreAllowFlight; - public final boolean creativeFlyCheck; private final Map flyingModelGameMode = new HashMap(); private final ModelFlying flyingModelElytra; private final ModelFlying flyingModelLevitation; public final ActionList creativeFlyActions; - public final boolean morePacketsCheck; /** Assumed number of packets per second under ideal conditions. */ public final float morePacketsEPSIdeal; /** The maximum number of packets per second that we accept. */ @@ -134,7 +78,6 @@ public class MovingConfig extends ACheckConfig { public final int morePacketsSetBackAge; public final ActionList morePacketsActions; - public final boolean noFallCheck; /** * Deal damage instead of Minecraft, whenever a player is judged to be on * ground. @@ -154,7 +97,6 @@ public class MovingConfig extends ACheckConfig { public final boolean noFallAntiCriticals; public final ActionList noFallActions; - public final boolean passableCheck; // TODO: passableAccuracy: also use if not using ray-tracing public final ActionList passableActions; public final boolean passableUntrackedTeleportCheck; @@ -162,7 +104,6 @@ public class MovingConfig extends ACheckConfig { public final boolean passableUntrackedCommandTryTeleport; public final SimpleCharPrefixTree passableUntrackedCommandPrefixes = new SimpleCharPrefixTree(); - public final boolean survivalFlyCheck; public final int survivalFlyBlockingSpeed; public final int survivalFlySneakingSpeed; public final int survivalFlySpeedingSpeed; @@ -184,7 +125,7 @@ public class MovingConfig extends ACheckConfig { public final long survivalFlyVLFreeze; public final ActionList survivalFlyActions; - public final boolean sfHoverCheck; + public final boolean sfHoverCheck; // TODO: Sub check ? public final int sfHoverTicks; public final int sfHoverLoginTicks; public final boolean sfHoverFallDamage; @@ -230,10 +171,8 @@ public class MovingConfig extends ACheckConfig { public final Set ignoredVehicles = new HashSet(); - public final boolean vehicleMorePacketsCheck; public final ActionList vehicleMorePacketsActions; - public final boolean vehicleEnvelopeActive; public final HashMap vehicleEnvelopeHorizontalSpeedCap = new HashMap(); public final ActionList vehicleEnvelopeActions; @@ -251,13 +190,13 @@ public class MovingConfig extends ACheckConfig { * @param config * the data */ - public MovingConfig(final ConfigFile config) { - super(config, ConfPaths.MOVING); + public MovingConfig(final IWorldData worldData) { + super(worldData); + final ConfigFile config = worldData.getRawConfiguration(); ignoreCreative = config.getBoolean(ConfPaths.MOVING_CREATIVEFLY_IGNORECREATIVE); ignoreAllowFlight = config.getBoolean(ConfPaths.MOVING_CREATIVEFLY_IGNOREALLOWFLIGHT); - creativeFlyCheck = config.getBoolean(ConfPaths.MOVING_CREATIVEFLY_CHECK); final ModelFlying defaultModel = new ModelFlying("gamemode.creative", config, ConfPaths.MOVING_CREATIVEFLY_MODEL + "creative.", new ModelFlying().lock()); for (final GameMode gameMode : GameMode.values()) { @@ -273,7 +212,6 @@ public class MovingConfig extends ACheckConfig { creativeFlyActions = config.getOptimizedActionList(ConfPaths.MOVING_CREATIVEFLY_ACTIONS, Permissions.MOVING_CREATIVEFLY); - morePacketsCheck = config.getBoolean(ConfPaths.MOVING_MOREPACKETS_CHECK); morePacketsEPSIdeal = config.getInt(ConfPaths.MOVING_MOREPACKETS_EPSIDEAL); morePacketsEPSMax = Math.max(morePacketsEPSIdeal, config.getInt(ConfPaths.MOVING_MOREPACKETS_EPSMAX)); morePacketsEPSBuckets = 2 * Math.max(1, Math.min(60, config.getInt(ConfPaths.MOVING_MOREPACKETS_SECONDS))); @@ -283,7 +221,6 @@ public class MovingConfig extends ACheckConfig { morePacketsSetBackAge = config.getInt(ConfPaths.MOVING_MOREPACKETS_SETBACKAGE); morePacketsActions = config.getOptimizedActionList(ConfPaths.MOVING_MOREPACKETS_ACTIONS, Permissions.MOVING_MOREPACKETS); - noFallCheck = config.getBoolean(ConfPaths.MOVING_NOFALL_CHECK); noFallDealDamage = config.getBoolean(ConfPaths.MOVING_NOFALL_DEALDAMAGE); noFallSkipAllowFlight = config.getBoolean(ConfPaths.MOVING_NOFALL_SKIPALLOWFLIGHT); noFallViolationReset = config.getBoolean(ConfPaths.MOVING_NOFALL_RESETONVL); @@ -292,14 +229,12 @@ public class MovingConfig extends ACheckConfig { noFallAntiCriticals = config.getBoolean(ConfPaths.MOVING_NOFALL_ANTICRITICALS); noFallActions = config.getOptimizedActionList(ConfPaths.MOVING_NOFALL_ACTIONS, Permissions.MOVING_NOFALL); - passableCheck = config.getBoolean(ConfPaths.MOVING_PASSABLE_CHECK); passableActions = config.getOptimizedActionList(ConfPaths.MOVING_PASSABLE_ACTIONS, Permissions.MOVING_PASSABLE); passableUntrackedTeleportCheck = config.getBoolean(ConfPaths.MOVING_PASSABLE_UNTRACKED_TELEPORT_ACTIVE); passableUntrackedCommandCheck = config.getBoolean(ConfPaths.MOVING_PASSABLE_UNTRACKED_CMD_ACTIVE); passableUntrackedCommandTryTeleport = config.getBoolean(ConfPaths.MOVING_PASSABLE_UNTRACKED_CMD_TRYTELEPORT); CommandUtil.feedCommands(passableUntrackedCommandPrefixes, config, ConfPaths.MOVING_PASSABLE_UNTRACKED_CMD_PREFIXES, true); - survivalFlyCheck = config.getBoolean(ConfPaths.MOVING_SURVIVALFLY_CHECK); // Default values are specified here because this settings aren't showed by default into the configuration file. survivalFlyBlockingSpeed = config.getInt(ConfPaths.MOVING_SURVIVALFLY_BLOCKINGSPEED, 100); survivalFlySneakingSpeed = config.getInt(ConfPaths.MOVING_SURVIVALFLY_SNEAKINGSPEED, 100); @@ -389,10 +324,12 @@ public class MovingConfig extends ACheckConfig { vehicleEnforceLocation = ref.decideOptimistically(); // Currently rather enabled. vehiclePreventDestroyOwn = config.getBoolean(ConfPaths.MOVING_VEHICLE_PREVENTDESTROYOWN); scheduleVehicleSetBacks = config.getAlmostBoolean(ConfPaths.MOVING_VEHICLE_SCHEDULESETBACKS, AlmostBoolean.MAYBE).decide(); - vehicleMorePacketsCheck = config.getBoolean(ConfPaths.MOVING_VEHICLE_MOREPACKETS_CHECK); vehicleMorePacketsActions = config.getOptimizedActionList(ConfPaths.MOVING_VEHICLE_MOREPACKETS_ACTIONS, Permissions.MOVING_MOREPACKETS); ref = config.getAlmostBoolean(ConfPaths.MOVING_VEHICLE_ENVELOPE_ACTIVE, AlmostBoolean.MAYBE); - vehicleEnvelopeActive = ref == AlmostBoolean.MAYBE ? ServerVersion.compareMinecraftVersion("1.9") >= 0 : ref.decide(); + if (ServerVersion.compareMinecraftVersion("1.9") < 0) { + worldData.overrideCheckActivation(CheckType.MOVING_VEHICLE_ENVELOPE, + AlmostBoolean.NO, OverrideType.PERMANENT, true); + } config.readDoubleValuesForEntityTypes(ConfPaths.MOVING_VEHICLE_ENVELOPE_HSPEEDCAP, vehicleEnvelopeHorizontalSpeedCap, 4.0, true); vehicleEnvelopeActions = config.getOptimizedActionList(ConfPaths.MOVING_VEHICLE_ENVELOPE_ACTIONS, Permissions.MOVING_VEHICLE_ENVELOPE); // Ignored vehicle types (ignore mostly, no checks run). @@ -420,44 +357,6 @@ public class MovingConfig extends ACheckConfig { msgKickIllegalVehicleMove = ColorUtil.replaceColors(config.getString(ConfPaths.MOVING_MESSAGE_ILLEGALVEHICLEMOVE)); } - /* (non-Javadoc) - * @see fr.neatmonster.nocheatplus.checks.ICheckConfig#isEnabled(fr.neatmonster.nocheatplus.checks.CheckType) - */ - @Override - public final boolean isEnabled(final CheckType checkType) { - switch (checkType) { - case MOVING_NOFALL: - return noFallCheck; - case MOVING_SURVIVALFLY: - return survivalFlyCheck; - case MOVING_PASSABLE: - return passableCheck; - case MOVING_MOREPACKETS: - return morePacketsCheck; - case MOVING_VEHICLE_MOREPACKETS: - return vehicleMorePacketsCheck; - case MOVING_VEHICLE_ENVELOPE: - return vehicleEnvelopeActive; - case MOVING_CREATIVEFLY: - return creativeFlyCheck; - default: - return true; - } - } - - /** - * Fetches data and config for sub checks (potentially redundant fetching). - * - * @param player - * @param fromLocation - * @return - * @deprecated Having a from location but no config/data ... - */ - @Deprecated - public ModelFlying getModelFlying(final Player player, final PlayerLocation fromLocation) { - return getModelFlying(player, fromLocation, MovingData.getData(player), MovingConfig.getConfig(player)); - } - public ModelFlying getModelFlying(final Player player, final PlayerLocation fromLocation, final MovingData data, final MovingConfig cc) { final GameMode gameMode = player.getGameMode(); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingData.java index 9975846d..e779d76a 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingData.java @@ -15,21 +15,15 @@ package fr.neatmonster.nocheatplus.checks.moving; import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import java.util.concurrent.Callable; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckData; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.checks.access.IRemoveSubCheckData; import fr.neatmonster.nocheatplus.checks.moving.location.setback.DefaultSetBackStorage; import fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace; @@ -47,10 +41,10 @@ import fr.neatmonster.nocheatplus.checks.moving.velocity.SimpleEntry; import fr.neatmonster.nocheatplus.checks.moving.velocity.VelocityFlags; import fr.neatmonster.nocheatplus.checks.workaround.WRPT; import fr.neatmonster.nocheatplus.compat.blocks.changetracker.BlockChangeReference; -import fr.neatmonster.nocheatplus.components.data.ICanHandleTimeRunningBackwards; import fr.neatmonster.nocheatplus.components.entity.IEntityAccessDimensions; import fr.neatmonster.nocheatplus.components.location.IGetPosition; import fr.neatmonster.nocheatplus.components.location.IPositionWithLook; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionAccumulator; @@ -66,84 +60,31 @@ import fr.neatmonster.nocheatplus.workaround.IWorkaroundRegistry.WorkaroundSet; */ public class MovingData extends ACheckData implements IRemoveSubCheckData { - public static final class MovingDataFactory implements CheckDataFactory, ICanHandleTimeRunningBackwards { - @Override - public final ICheckData getData(final Player player) { - return MovingData.getData(player); - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return MovingData.playersMap.get(playerName); - } - - @Override - public ICheckData removeData(final String playerName) { - return MovingData.removeData(playerName); - } - - @Override - public void removeAllData() { - MovingData.clear(); - } - - @Override - public void handleTimeRanBackwards() { - for (final MovingData data : playersMap.values()) { - data.handleTimeRanBackwards(); - } - } - } - - /** The factory creating data. */ - public static final CheckDataFactory factory = new MovingDataFactory(); - - private static Map playersMap = new HashMap(); - /** The map containing the data per players. */ - - /** - * Gets the data of a specified player. - * final CheckDataFactory factory = new CheckDataFactory( - * @param player - * the player - * @return the data + /* + * TODO: Handle world unload and other by registration (PlayerDataManager) - + * might just implement the interfaces and auto-handle at registration. */ - public static MovingData getData(final Player player) { - // Note that the trace might be null after just calling this. - MovingData data = playersMap.get(player.getName()); - if (data == null) { - data = new MovingData(MovingConfig.getConfig(player)); - playersMap.put(player.getName(), data); - } - return data; - } - public static ICheckData removeData(final String playerName) { - return playersMap.remove(playerName); - } - - public static void clear() { - playersMap.clear(); - } - - /** - * Clear data related to the given world. - * @param world The world that gets unloaded. - */ - public static void onWorldUnload(final World world) { - final String worldName = world.getName(); - for (final MovingData data : playersMap.values()) { - data.onWorldUnload(worldName); - } - } - - public static void onReload() { - final MovingConfig globalCc = MovingConfig.getConfig((String) null); - final int tick = TickTask.getTick(); - for (final MovingData data : playersMap.values()) { - data.adjustOnReload(globalCc, tick); - } - } + // /** + // * Clear data related to the given world. + // * @param world The world that gets unloaded. + // */ + // public static void onWorldUnload(final World world) { + // // TODO: Register with check (interfaces or just an event listener). + // final String worldName = world.getName(); + // for (final MovingData data : playersMap.values()) { + // data.onWorldUnload(worldName); + // } + // } + // + // public static void onReload() { + // // TODO: Register with check (interfaces or just an event listener). + // final MovingConfig globalCc = MovingConfig.getConfig((String) null); + // final int tick = TickTask.getTick(); + // for (final MovingData data : playersMap.values()) { + // data.adjustOnReload(globalCc, tick); + // } + // } // Check specific. @@ -365,8 +306,10 @@ public class MovingData extends ACheckData implements IRemoveSubCheckData { /** Task id of the vehicle set back task. */ public int vehicleSetBackTaskId = -1; - public MovingData(final MovingConfig config) { - super(config); + private final IPlayerData pData; + + public MovingData(final MovingConfig config, final IPlayerData pData) { + this.pData = pData; morePacketsFreq = new ActionFrequency(config.morePacketsEPSBuckets, 500); morePacketsBurstFreq = new ActionFrequency(12, 5000); @@ -675,7 +618,7 @@ public class MovingData extends ACheckData implements IRemoveSubCheckData { * @param amount */ public void reducePlayerMorePacketsData(final float amount) { - CheckUtils.reduce(System.currentTimeMillis(), amount, morePacketsFreq, morePacketsBurstFreq); + ActionFrequency.reduce(System.currentTimeMillis(), amount, morePacketsFreq, morePacketsBurstFreq); } public void clearVehicleMorePacketsData() { @@ -916,12 +859,11 @@ public class MovingData extends ACheckData implements IRemoveSubCheckData { */ public void addVelocity(final Player player, final MovingConfig cc, final double vx, final double vy, final double vz, final long flags) { - final int tick = TickTask.getTick(); // TODO: Slightly odd to call this each time, might switch to a counter-strategy (move - remove). removeInvalidVelocity(tick - cc.velocityActivationTicks); - if (debug) { + if (pData.isDebugActive(CheckType.MOVING)) { CheckUtils.debug(player, CheckType.MOVING, "New velocity: " + vx + ", " + vy + ", " + vz); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java index 218aece7..82410076 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java @@ -81,7 +81,6 @@ import fr.neatmonster.nocheatplus.checks.moving.vehicle.VehicleChecks; import fr.neatmonster.nocheatplus.checks.moving.velocity.AccountEntry; import fr.neatmonster.nocheatplus.checks.moving.velocity.SimpleEntry; import fr.neatmonster.nocheatplus.checks.moving.velocity.VelocityFlags; -import fr.neatmonster.nocheatplus.checks.net.NetConfig; import fr.neatmonster.nocheatplus.checks.net.NetData; import fr.neatmonster.nocheatplus.compat.Bridge1_9; import fr.neatmonster.nocheatplus.compat.BridgeEnchant; @@ -102,13 +101,11 @@ import fr.neatmonster.nocheatplus.components.registry.feature.JoinLeaveListener; import fr.neatmonster.nocheatplus.components.registry.feature.TickListener; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigManager; -import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager; import fr.neatmonster.nocheatplus.logging.StaticLog; import fr.neatmonster.nocheatplus.logging.Streams; import fr.neatmonster.nocheatplus.logging.debug.DebugUtil; -import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.PotionUtil; @@ -238,11 +235,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo if (isGliding && !Bridge1_9.isGlidingWithElytra(player)) { // Includes check for elytra item. final PlayerMoveInfo info = aux.usePlayerMoveInfo(); info.set(player, player.getLocation(info.useLoc), null, 0.001); // Only restrict very near ground. - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); final boolean res = !MovingUtil.canLiftOffWithElytra(player, info.from, data); info.cleanup(); aux.returnPlayerMoveInfo(info); - if (res && data.debug) { + if (res && pData.isDebugActive(checkType)) { debug(player, "Prevent toggle glide on."); } return res; @@ -259,7 +257,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @EventHandler( priority = EventPriority.MONITOR) public void onPlayerBedEnter(final PlayerBedEnterEvent event) { - CombinedData.getData(event.getPlayer()).wasInBed = true; + DataManager.getGenericInstance(event.getPlayer(), CombinedData.class).wasInBed = true; } /** @@ -272,13 +270,14 @@ public class MovingListener extends CheckListener implements TickListener, IRemo priority = EventPriority.MONITOR) public void onPlayerBedLeave(final PlayerBedLeaveEvent event) { final Player player = event.getPlayer(); - if (bedLeave.isEnabled(player) && bedLeave.checkBed(player)) { - final MovingConfig cc = MovingConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + if (pData.isCheckActive(bedLeave.getType(), player) + && bedLeave.checkBed(player, pData)) { + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); // Check if the player has to be reset. // To "cancel" the event, we teleport the player. final Location loc = player.getLocation(useLoc); - final PlayerData pData = DataManager.getPlayerData(player); - final MovingData data = MovingData.getData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); Location target = null; final PlayerMoveInfo moveInfo = aux.usePlayerMoveInfo(); moveInfo.set(player, loc, null, cc.yOnGround); @@ -291,13 +290,13 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // TODO: Add something to guess the best set back location (possibly data.guessSetBack(Location)). target = LocUtil.clone(loc); } - if (sfCheck && cc.sfSetBackPolicyFallDamage && noFall.isEnabled(player, cc)) { + if (sfCheck && cc.sfSetBackPolicyFallDamage && noFall.isEnabled(player, pData)) { // Check if to deal damage. double y = loc.getY(); if (data.hasSetBack()) { y = Math.min(y, data.getSetBackY()); } - noFall.checkDamage(player, data, y); + noFall.checkDamage(player, y, data, pData); } // Cleanup useLoc.setWorld(null); @@ -308,7 +307,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } else { // Reset bed ... - CombinedData.getData(player).wasInBed = false; + pData.getGenericInstance(CombinedData.class).wasInBed = false; } } @@ -324,14 +323,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo public void onPlayerChangedWorld(final PlayerChangedWorldEvent event) { // Maybe this helps with people teleporting through Multiverse portals having problems? final Player player = event.getPlayer(); - final MovingData data = MovingData.getData(player); - final MovingConfig cc = MovingConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); data.clearMostMovingCheckData(); // TODO: Might omit this if neither check is activated. final Location loc = player.getLocation(useLoc); data.setSetBack(loc); if (cc.loadChunksOnWorldChange) { - MovingUtil.ensureChunksLoaded(player, loc, "world change", data, cc); + MovingUtil.ensureChunksLoaded(player, loc, "world change", data, cc, pData); } aux.resetPositionsAndMediumProperties(player, loc, data, cc); data.resetTrace(player, loc, TickTask.getTick(), mcAccess.getHandle(), cc); @@ -351,8 +351,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @EventHandler( ignoreCancelled = true, priority = EventPriority.MONITOR) public void onPlayerGameModeChange(final PlayerGameModeChangeEvent event) { - if (event.getPlayer().getGameMode() == GameMode.CREATIVE || event.getNewGameMode() == GameMode.CREATIVE) { - final MovingData data = MovingData.getData(event.getPlayer()); + final Player player = event.getPlayer(); + if (player.getGameMode() == GameMode.CREATIVE || event.getNewGameMode() == GameMode.CREATIVE) { + final MovingData data = DataManager.getGenericInstance(player, MovingData.class); data.clearFlyData(); data.clearPlayerMorePacketsData(); // TODO: Set new set back if any fly check is activated. @@ -375,8 +376,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Store the event for monitor level checks. processingEvents.put(player.getName(), event); - final MovingConfig cc = MovingConfig.getConfig(player); - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); + final MovingData data = pData.getGenericInstance(MovingData.class); data.increasePlayerMoveCount(); /* @@ -402,7 +404,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo final String token; if (player.isInsideVehicle()) { // No full processing for players in vehicles. - newTo = vehicleChecks.onPlayerMoveVehicle(player, from, to, data); + newTo = vehicleChecks.onPlayerMoveVehicle(player, from, to, data, pData); earlyReturn = true; token = "vehicle"; } @@ -426,7 +428,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo token = "worldchange"; } else if (data.hasTeleported()) { - earlyReturn = handleTeleportedOnMove(player, event, data, cc); + earlyReturn = handleTeleportedOnMove(player, event, data, cc, pData); token = "awaitsetback"; } else { @@ -434,11 +436,13 @@ public class MovingListener extends CheckListener implements TickListener, IRemo token = null; } + final boolean debug = pData.isDebugActive(checkType); + // TODO: Might log base parts here (+extras). if (earlyReturn) { // TODO: Remove player from enforceLocation ? // TODO: Log "early return: " + tags. - if (data.debug) { + if (debug) { debug(player, "Early return" + (token == null ? "" : (" (" + token + ")")) + " on PlayerMoveEvent: from: " + from + " , to: " + to); } if (newTo != null) { @@ -450,7 +454,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo newTo.setPitch(LocUtil.correctPitch(newTo.getPitch())); } // Set. - prepareSetBack(player, event, newTo, data, cc); // Logs set back details. + prepareSetBack(player, event, newTo, data, cc, pData); // Logs set back details. } data.joinOrRespawn = false; return; @@ -462,7 +466,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo final Location loc = player.getLocation(moveInfo.useLoc); final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove(); if (cc.loadChunksOnMove) { - MovingUtil.ensureChunksLoaded(player, from, to, lastMove, "move", data, cc); + MovingUtil.ensureChunksLoaded(player, from, to, lastMove, "move", cc, pData); } // TODO: On pistons pulling the player back: -1.15 yDistance for split move 1 (untracked position > 0.5 yDistance!). if ( @@ -478,25 +482,31 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Fire move from -> to // (Special case: Location has not been updated last moving event.) moveInfo.set(player, from, to, cc.yOnGround); - checkPlayerMove(player, from, to, 0, moveInfo, data, cc, event); + checkPlayerMove(player, from, to, 0, moveInfo, debug, + data, cc, pData, event); } else { // Split into two moves. // 1. Process from -> loc. - if (data.debug) { + if (debug) { debug(player, "Split move 1 (from -> loc):"); } moveInfo.set(player, from, loc, cc.yOnGround); - if (!checkPlayerMove(player, from, loc, 1, moveInfo, data, cc, event) && processingEvents.containsKey(player.getName())) { + if (!checkPlayerMove(player, from, loc, 1, moveInfo, debug, + data, cc, pData, event) && processingEvents.containsKey(player.getName())) { // Between -> set data accordingly (compare: onPlayerMoveMonitor). - onMoveMonitorNotCancelled(player, from, loc, System.currentTimeMillis(), TickTask.getTick(), CombinedData.getData(player), data, cc); + onMoveMonitorNotCancelled(player, from, loc, + System.currentTimeMillis(), TickTask.getTick(), + pData.getGenericInstance(CombinedData.class), + data, cc, pData); data.joinOrRespawn = false; // 2. Process loc -> to. - if (data.debug) { + if (debug) { debug(player, "Split move 2 (loc -> to):"); } moveInfo.set(player, loc, to, cc.yOnGround); - checkPlayerMove(player, loc, to, 2, moveInfo, data, cc, event); + checkPlayerMove(player, loc, to, 2, moveInfo, debug, + data, cc, pData, event); } } // Cleanup. @@ -515,14 +525,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @return */ private boolean handleTeleportedOnMove(final Player player, final PlayerMoveEvent event, - final MovingData data, final MovingConfig cc) { + final MovingData data, final MovingConfig cc, final IPlayerData pData) { // This could also happen with a packet based set back such as with cancelling move events. + final boolean debug = pData.isDebugActive(checkType); if (data.isTeleportedPosition(event.getFrom())) { // Treat as ACK (!). // Adjust. - confirmSetBack(player, false, data, cc); + confirmSetBack(player, false, data, cc, pData); // Log. - if (data.debug) { + if (debug) { debug(player, "Implicitly confirm set back with the start point of a move."); } return false; @@ -531,14 +542,14 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // A set back has been scheduled, but the player is moving randomly. // TODO: Instead alter the move from location and let it get through? +- when event.setCancelled(true); - if (data.debug) { + if (debug) { debug(player, "Cancel move, due to a scheduled teleport (set back)."); } return true; } else { // Left-over (Demand: schedule or teleport before moving events arrive). - if (data.debug) { + if (debug) { debug(player, "Invalidate left-over teleported (set back) location: " + data.getTeleported()); } data.resetTeleported(); @@ -562,7 +573,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @return If cancelled/done, i.e. not to process further split moves. */ private boolean checkPlayerMove(final Player player, final Location from, final Location to, - final int multiMoveCount, final PlayerMoveInfo moveInfo, final MovingData data, final MovingConfig cc, + final int multiMoveCount, final PlayerMoveInfo moveInfo, final boolean debug, + final MovingData data, final MovingConfig cc, final IPlayerData pData, final PlayerMoveEvent event) { Location newTo = null; @@ -573,7 +585,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // TODO: Data resetting above ? data.resetTeleported(); // Debug. - if (data.debug) { + if (debug) { outputMoveDebug(player, moveInfo.from, moveInfo.to, Math.max(cc.noFallyOnGround, cc.yOnGround), mcAccess.getHandle()); } // Check for illegal move and bounding box etc. @@ -583,7 +595,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo return true; } - final PlayerData pData = DataManager.getPlayerData(player); final String playerName = player.getName(); // TODO: Could switch to UUID here (needs more changes). // Check for location consistency. @@ -630,7 +641,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // HOT FIX - for VehicleLeaveEvent missing. if (data.wasInVehicle) { - vehicleChecks.onVehicleLeaveMiss(player, data, cc); + vehicleChecks.onVehicleLeaveMiss(player, data, cc, pData); } // Set some data for this move. @@ -665,9 +676,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo checkSf = true; data.adjustWalkSpeed(player.getWalkSpeed(), tick, cc.speedGrace); } - else if (cc.creativeFlyCheck - && !NCPExemptionManager.isExempted(player, CheckType.MOVING_CREATIVEFLY) - && !pData.hasPermission(Permissions.MOVING_CREATIVEFLY, player)) { + else if (pData.isDebugActive(CheckType.MOVING_CREATIVEFLY)) { checkCf = true; checkSf = false; prepareCreativeFlyCheck(player, from, to, moveInfo, thisMove, multiMoveCount, tick, data, cc); @@ -685,10 +694,13 @@ public class MovingListener extends CheckListener implements TickListener, IRemo final boolean useBlockChangeTracker; final double previousSetBackY; + final boolean checkPassable = pData.isCheckActive(CheckType.MOVING_PASSABLE, player); + + if (checkSf || checkCf) { previousSetBackY = data.hasSetBack() ? data.getSetBackY() : Double.NEGATIVE_INFINITY; // Ensure we have a set back set. - MovingUtil.checkSetBack(player, pFrom, data, this); + MovingUtil.checkSetBack(player, pFrom, data, pData, this); // Check for special cross world teleportation issues with the end. if (data.crossWorldFrom != null) { @@ -715,7 +727,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } useBlockChangeTracker = newTo == null - && cc.trackBlockMove && (cc.passableCheck || checkSf || checkCf) + && cc.trackBlockMove && (checkPassable || checkSf || checkCf) && blockChangeTracker.hasActivityShuffled(from.getWorld().getUID(), pFrom, pTo, 1.5625); // Check jumping on things like slime blocks. @@ -729,7 +741,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Common pre-conditions. // TODO: Check if really leads to calling the method for pistons (checkBounceEnvelope vs. push). if (!survivalFly.isReallySneaking(player) - && checkBounceEnvelope(player, pFrom, pTo, data, cc)) { + && checkBounceEnvelope(player, pFrom, pTo, data, cc, pData)) { // TODO: Check other side conditions (fluids, web, max. distance to the block top (!)) // Classic static bounce. if ((BlockProperties.getBlockFlags(pTo.getTypeIdBelow()) @@ -762,7 +774,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo && thisMove.yDistance <= 1.515 // TODO: MAGIC ) { verticalBounce = checkPastStateBounceAscend(player, pFrom, pTo, - thisMove, lastMove, tick, data, cc); + thisMove, lastMove, tick, debug, data, cc); if (verticalBounce != BounceType.NO_BOUNCE) { checkNf = false; } @@ -779,11 +791,10 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Check passable first to prevent set back override. // TODO: Redesign to set set backs later (queue + invalidate). boolean mightSkipNoFall = false; // If to skip nofall check (mainly on violation of other checks). - if (newTo == null && cc.passableCheck && player.getGameMode() != BridgeMisc.GAME_MODE_SPECTATOR - && !NCPExemptionManager.isExempted(player, CheckType.MOVING_PASSABLE) - && !pData.hasPermission(Permissions.MOVING_PASSABLE, player)) { + if (newTo == null && checkPassable + && player.getGameMode() != BridgeMisc.GAME_MODE_SPECTATOR ) { // Passable is checked first to get the original set back locations from the other checks, if needed. - newTo = passable.check(player, pFrom, pTo, data, cc, tick, useBlockChangeTracker); + newTo = passable.check(player, pFrom, pTo, data, cc, pData, tick, useBlockChangeTracker); if (newTo != null) { // Check if to skip the nofall check. mightSkipNoFall = true; @@ -800,7 +811,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Hack: Add velocity for transitions between creativefly and survivalfly. if (lastMove.toIsValid && lastMove.flyCheck == CheckType.MOVING_CREATIVEFLY) { - workaroundFlyNoFlyTransition(player, tick, data); + workaroundFlyNoFlyTransition(player, tick, debug, data); } // Actual check. @@ -812,7 +823,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } // Only check NoFall, if not already vetoed. if (checkNf) { - checkNf = noFall.isEnabled(player, cc); + checkNf = noFall.isEnabled(player, pData); } if (newTo == null) { // Hover. @@ -829,7 +840,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } // NoFall. if (checkNf) { - noFall.check(player, pFrom, pTo, previousSetBackY, data, cc); + noFall.check(player, pFrom, pTo, previousSetBackY, data, cc, pData); } } else { @@ -846,7 +857,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } if (!mightSkipNoFall && (!pTo.isResetCond() || !pFrom.isResetCond())) { // (Don't deal damage where no fall damage is possible.) - noFall.checkDamage(player, data, Math.min(from.getY(), to.getY())); + noFall.checkDamage(player, + Math.min(from.getY(), to.getY()), data, pData); } } } @@ -855,7 +867,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // CreativeFly if (newTo == null) { thisMove.flyCheck = CheckType.MOVING_CREATIVEFLY; - newTo = creativeFly.check(player, pFrom, pTo, data, cc, time, tick, useBlockChangeTracker); + newTo = creativeFly.check(player, pFrom, pTo, + data, cc, pData, time, tick, useBlockChangeTracker); } data.sfHoverTicks = -1; data.sfLowJump = false; @@ -866,15 +879,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } // Morepackets. - if (cc.morePacketsCheck && (newTo == null || data.isMorePacketsSetBackOldest()) - && !NCPExemptionManager.isExempted(player, CheckType.MOVING_MOREPACKETS) - && !pData.hasPermission(Permissions.MOVING_MOREPACKETS, player)) { + if (pData.isCheckActive(CheckType.MOVING_MOREPACKETS, player) + && (newTo == null || data.isMorePacketsSetBackOldest())) { /* (Always check morepackets, if there is a chance that setting/overriding newTo is appropriate, to avoid packet speeding using micro-violations.) */ - final Location mpNewTo = morePackets.check(player, pFrom, pTo, newTo == null, data, cc); + final Location mpNewTo = morePackets.check(player, pFrom, pTo, + newTo == null, data, cc, pData); if (mpNewTo != null) { // Only override set back, if the morepackets set back location is older/-est. - if (newTo != null && data.debug) { + if (newTo != null && debug) { debug(player, "Override set back by the older morepackets set back."); } newTo = mpNewTo; @@ -896,7 +909,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Update BlockChangeTracker if (useBlockChangeTracker && data.blockChangeRef.firstSpanEntry != null) { - if (data.debug) { + if (debug) { debug(player, "BlockChangeReference: " + data.blockChangeRef.firstSpanEntry.tick + " .. " + data.blockChangeRef.lastSpanEntry.tick + " / " + tick); } data.blockChangeRef.updateFinal(pTo); @@ -906,13 +919,14 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Allowed move. if (data.hasTeleported()) { data.resetTeleported(); - if (data.debug) { + if (debug) { debug(player, "Ignore hook-induced set-back: actions not set to cancel."); } } // Bounce effects. if (verticalBounce != BounceType.NO_BOUNCE) { - processBounce(player, pFrom.getY(), pTo.getY(), verticalBounce, tick, data, cc); + processBounce(player, pFrom.getY(), pTo.getY(), + verticalBounce, tick, debug, data, cc, pData); } // Finished move processing. if (processingEvents.containsKey(playerName)) { @@ -930,12 +944,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } else { if (data.hasTeleported()) { - if (data.debug) { + if (debug) { debug(player, "The set back has been overridden from (" + newTo + ") to: " + data.getTeleported()); } newTo = data.getTeleported(); } - if (data.debug) { // TODO: Remove, if not relevant (doesn't look like it was :p). + if (debug) { // TODO: Remove, if not relevant (doesn't look like it was :p). if (verticalBounce != BounceType.NO_BOUNCE) { debug(player, "Bounce effect not processed: " + verticalBounce); } @@ -944,7 +958,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } } // Set back handling. - prepareSetBack(player, event, newTo, data, cc); + prepareSetBack(player, event, newTo, data, cc, pData); // Prevent freezing (e.g. ascending with gliding set in water, but moving normally). if ((thisMove.flyCheck == CheckType.MOVING_SURVIVALFLY || thisMove.flyCheck == CheckType.MOVING_CREATIVEFLY @@ -1031,7 +1045,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo private BounceType checkPastStateBounceAscend( final Player player, final PlayerLocation from, final PlayerLocation to, final PlayerMoveData thisMove, final PlayerMoveData lastMove, final int tick, - final MovingData data, final MovingConfig cc) { + final boolean debug, final MovingData data, final MovingConfig cc) { // TODO: More preconditions. // TODO: Nail down to more precise side conditions for larger jumps, if possible. @@ -1052,7 +1066,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo data.blockChangeRef, Direction.Y_POS, Math.min(.415, thisMove.yDistance), BlockProperties.F_BOUNCE25) ) { - if (data.debug) { + if (debug) { debug(player, "Direct block push with bounce (" + (entryBelowY_POS == null ? "off_center)." : "center).")); } amount = Math.min( @@ -1079,7 +1093,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo if (entry2BelowY_POS != null // TODO: Does off center push exist with this very case? ) { - if (data.debug) { + if (debug) { debug(player, "Foot position block push with bounce (" + (entry2BelowY_POS == null ? "off_center)." : "center).")); } amount = Math.min(Math.max(0.505, 1.0 + (double) from.getBlockY() - from.getY() + 1.515), @@ -1117,7 +1131,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo //if (thisMove.yDistance > 0.42) { // data.setFrictionJumpPhase(); //} - if (data.debug) { + if (debug) { debug(player, "checkPastStateBounceAscend: set velocity: " + vel); } // TODO: Exact type to return. @@ -1139,7 +1153,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @return */ private boolean checkBounceEnvelope(final Player player, final PlayerLocation from, final PlayerLocation to, - final MovingData data, final MovingConfig cc) { + final MovingData data, final MovingConfig cc, final IPlayerData pData) { return // 0: Normal envelope (forestall NoFall). ( @@ -1148,7 +1162,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // 1: With carpet. || BlockProperties.isCarpet(to.getTypeId()) && to.getY() - to.getBlockY() <= 0.9 ) - && MovingUtil.getRealisticFallDistance(player, from.getY(), to.getY(), data) > 1.0 + && MovingUtil.getRealisticFallDistance(player, from.getY(), to.getY(), data, pData) > 1.0 // 0: Within wobble-distance. || to.getY() - to.getBlockY() < 0.286 && to.getY() - from.getY() > -0.5 && to.getY() - from.getY() < -Magic.GRAVITY_MIN @@ -1292,7 +1306,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @param tick * @param data */ - private void workaroundFlyNoFlyTransition(final Player player, final int tick, final MovingData data) { + private void workaroundFlyNoFlyTransition(final Player player, final int tick, + final boolean debug, final MovingData data) { final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove(); final double amount = guessFlyNoFlyVelocity(player, data.playerMoves.getCurrentMove(), lastMove, data); data.clearActiveHorVel(); // Clear active velocity due to adding actual speed here. @@ -1304,7 +1319,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // TODO: Later (e.g. 1.9) check for the ModelFlying, if fall damage is intended. data.clearNoFallData(); player.setFallDistance(0f); // TODO: Might do without this in case of elytra, needs ensure NoFall doesn't kill the player (...). - if (data.debug) { + if (debug) { debug(player, "Fly-nofly transition: Add velocity."); } } @@ -1338,9 +1353,10 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @param cc */ private void processBounce(final Player player,final double fromY, final double toY, - final BounceType bounceType, final int tick, final MovingData data, final MovingConfig cc) { + final BounceType bounceType, final int tick, final boolean debug, + final MovingData data, final MovingConfig cc, final IPlayerData pData) { // Prepare velocity. - final double fallDistance = MovingUtil.getRealisticFallDistance(player, fromY, toY, data); + final double fallDistance = MovingUtil.getRealisticFallDistance(player, fromY, toY, data, pData); final double base = Math.sqrt(fallDistance) / 3.3; double effect = Math.min(Magic.BOUNCE_VERTICAL_MAX_DIST, base + Math.min(base / 10.0, Magic.GRAVITY_MAX)); // Ancient Greek technology with gravity added. final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove(); @@ -1349,7 +1365,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo final double max_gain = Math.abs(lastMove.yDistance < 0.0 ? Math.min(lastMove.yDistance, toY - fromY) : (toY - fromY)) - Magic.GRAVITY_SPAN; if (max_gain < effect) { effect = max_gain; - if (data.debug) { + if (debug) { debug(player, "Cap bounce effect by recent y-distances."); } } @@ -1363,7 +1379,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo */ } // (Actually observed max. is near 3.5.) TODO: Why 3.14 then? - if (data.debug) { + if (debug) { debug(player, "Set bounce effect (dY=" + fallDistance + " / " + bounceType + "): " + effect); } data.noFallSkipAirCheck = true; @@ -1383,7 +1399,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @param data * @param cc */ - private void prepareSetBack(final Player player, final PlayerMoveEvent event, final Location newTo, final MovingData data, final MovingConfig cc) { + private void prepareSetBack(final Player player, + final PlayerMoveEvent event, final Location newTo, + final MovingData data, final MovingConfig cc, final IPlayerData pData) { // Illegal Yaw/Pitch. if (LocUtil.needsYawCorrection(newTo.getYaw())) { newTo.setYaw(LocUtil.correctYaw(newTo.getYaw())); @@ -1408,7 +1426,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // TODO: enforcelocation? // Debug. - if (data.debug) { + if (pData.isDebugActive(checkType)) { debug(player, "Prepare set back to: " + newTo.getWorld().getName() + "/" + LocUtil.simpleFormatPosition(newTo) + " (" + method.getId() + ")"); } @@ -1436,24 +1454,27 @@ public class MovingListener extends CheckListener implements TickListener, IRemo if (player.isDead() || player.isSleeping()) { return; } + final IPlayerData pData = DataManager.getPlayerData(event.getPlayer()); // Feed combined check. - final CombinedData data = CombinedData.getData(player); + final CombinedData data = pData.getGenericInstance(CombinedData.class); data.lastMoveTime = now; // TODO: Move to MovingData ? final Location from = event.getFrom(); // Feed yawrate and reset moving data positions if necessary. - final MovingData mData = MovingData.getData(player); + final MovingData mData = pData.getGenericInstance(MovingData.class); final int tick = TickTask.getTick(); - final MovingConfig mCc = MovingConfig.getConfig(player); + final MovingConfig mCc = pData.getGenericInstance(MovingConfig.class); if (!event.isCancelled()) { final Location pLoc = player.getLocation(useLoc); - onMoveMonitorNotCancelled(player, TrigUtil.isSamePosAndLook(pLoc, from) ? from : pLoc, event.getTo(), now, tick, data, mData, mCc); + onMoveMonitorNotCancelled(player, + TrigUtil.isSamePosAndLook(pLoc, from) ? from + : pLoc, event.getTo(), now, tick, data, mData, mCc, pData); useLoc.setWorld(null); } else { - onCancelledMove(player, from, tick, now, mData, mCc, data); + onCancelledMove(player, from, tick, now, mData, mCc, data, pData); } } @@ -1470,7 +1491,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @param data */ private void onCancelledMove(final Player player, final Location from, final int tick, final long now, - final MovingData mData, final MovingConfig mCc, final CombinedData data) { + final MovingData mData, final MovingConfig mCc, final CombinedData data, + final IPlayerData pData) { + final boolean debug = pData.isDebugActive(checkType); // Detect our own set back, choice of reference location. if (mData.hasTeleported()) { final Location ref = mData.getTeleported(); @@ -1483,13 +1506,13 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } if (method.shouldSchedule()) { // Schedule the teleport, because it might be faster than the next incoming packet. - final PlayerData pd = DataManager.getPlayerData(player); + final IPlayerData pd = DataManager.getPlayerData(player); if (pd.isPlayerSetBackScheduled()) { debug(player, "Teleport (set back) already scheduled to: " + ref); } - else if (mData.debug) { + else if (debug) { pd.requestPlayerSetBack(); - if (mData.debug) { + if (debug) { debug(player, "Schedule teleport (set back) to: " + ref); } } @@ -1498,15 +1521,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } // Assume the implicit teleport to the from-location (no Bukkit event fires). - Combined.resetYawRate(player, from.getYaw(), now, false); // Not reset frequency, but do set yaw. + Combined.resetYawRate(player, from.getYaw(), now, false, pData); // Not reset frequency, but do set yaw. aux.resetPositionsAndMediumProperties(player, from, mData, mCc); // TODO: Should probably leave this to the teleport event! mData.resetTrace(player, from, tick, mcAccess.getHandle(), mCc); // Expect a teleport to the from location (packet balance, no Bukkit event will fire). - if (((NetConfig) CheckType.NET_FLYINGFREQUENCY.getConfigFactory().getConfig(player)).flyingFrequencyActive) { - ((NetData) CheckType.NET_FLYINGFREQUENCY.getDataFactory().getData(player)).teleportQueue.onTeleportEvent(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch()); + if (pData.isCheckActive(CheckType.NET_FLYINGFREQUENCY, player)) { // TODO: A summary method. + pData.getGenericInstance(NetData.class).teleportQueue.onTeleportEvent(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch()); } } @@ -1520,9 +1543,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @param data * @param mData */ - private void onMoveMonitorNotCancelled(final Player player, final Location from, final Location to, final long now, final long tick, final CombinedData data, final MovingData mData, final MovingConfig mCc) { + private void onMoveMonitorNotCancelled(final Player player, + final Location from, final Location to, + final long now, final long tick, final CombinedData data, + final MovingData mData, final MovingConfig mCc, final IPlayerData pData) { final String toWorldName = to.getWorld().getName(); - Combined.feedYawRate(player, to.getYaw(), now, toWorldName, data); + Combined.feedYawRate(player, to.getYaw(), now, toWorldName, data, pData); // TODO: maybe even not count vehicles at all ? if (player.isInsideVehicle()) { // TODO: refine (!). @@ -1539,7 +1565,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo else { // TODO: Detect differing location (a teleport event would follow). final PlayerMoveData lastMove = mData.playerMoves.getFirstPastMove(); - if (!lastMove.toIsValid || !TrigUtil.isSamePos(to, lastMove.to.getX(), lastMove.to.getY(), lastMove.to.getZ())) { + if (!lastMove.toIsValid || !TrigUtil.isSamePos(to, + lastMove.to.getX(), lastMove.to.getY(), lastMove.to.getZ())) { // Something odd happened, e.g. a set back. aux.resetPositionsAndMediumProperties(player, to, mData, mCc); } @@ -1548,31 +1575,32 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } mData.updateTrace(player, to, tick, mcAccess.getHandle()); if (mData.hasTeleported()) { - onPlayerMoveMonitorNotCancelledHasTeleported(player, to, mData); + onPlayerMoveMonitorNotCancelledHasTeleported(player, to, + mData, pData, pData.isDebugActive(checkType)); } } } private void onPlayerMoveMonitorNotCancelledHasTeleported(final Player player, final Location to, - final MovingData mData) { + final MovingData mData, final IPlayerData pData, final boolean debug) { if (mData.isTeleportedPosition(to)) { // Skip resetting, especially if legacy setTo is enabled. // TODO: Might skip this condition, if legacy setTo is not enabled. - if (mData.debug) { + if (debug) { debug(player, "Event not cancelled, with teleported (set back) set, assume legacy behavior."); } return; } - else if (DataManager.getPlayerData(player).isPlayerSetBackScheduled()) { + else if (pData.isPlayerSetBackScheduled()) { // Skip, because the scheduled teleport has been overridden. // TODO: Only do this, if cancel is set, because it is not an un-cancel otherwise. - if (mData.debug) { + if (debug) { debug(player, "Event not cancelled, despite a set back has been scheduled. Cancel set back."); } mData.resetTeleported(); // (PlayerTickListener will notice it's not set.) } else { - if (mData.debug) { + if (debug) { debug(player, "Inconsistent state (move MONITOR): teleported has been set, but no set back is scheduled. Ignore set back."); } mData.resetTeleported(); @@ -1582,8 +1610,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerPortalLowest(final PlayerPortalEvent event) { final Player player = event.getPlayer(); + final IPlayerData pData = DataManager.getPlayerData(event.getPlayer()); if (MovingUtil.hasScheduledPlayerSetBack(player)) { - if (MovingData.getData(player).debug) { + if (pData.isDebugActive(checkType)) { debug(player, "[PORTAL] Prevent use, due to a scheduled set back."); } event.setCancelled(true); @@ -1599,8 +1628,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onPlayerPortal(final PlayerPortalEvent event) { final Location to = event.getTo(); - final MovingData data = MovingData.getData(event.getPlayer()); - if (data.debug) { + final IPlayerData pData = DataManager.getPlayerData(event.getPlayer()); + final MovingData data = pData.getGenericInstance(MovingData.class); + if (pData.isDebugActive(checkType)) { debug(event.getPlayer(), "[PORTAL] to=" + to); } if (to != null) { @@ -1617,11 +1647,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @EventHandler(priority = EventPriority.MONITOR) public void onPlayerDeath(final PlayerDeathEvent event) { final Player player = event.getEntity(); - final MovingData data = MovingData.getData(player); - //final MovingConfig cc = MovingConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); + //final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); data.clearMostMovingCheckData(); data.setSetBack(player.getLocation(useLoc)); // TODO: Monitor this change (!). - if (data.debug) { + if (pData.isDebugActive(checkType)) { // Log location. debug(player, "Death: " + player.getLocation(useLoc)); } @@ -1652,12 +1683,14 @@ public class MovingListener extends CheckListener implements TickListener, IRemo default: return; } - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final boolean debug = pData.isDebugActive(checkType); + final MovingData data = pData.getGenericInstance(MovingData.class); final Location to = event.getTo(); if (to == null) { // Better cancel this one. if (!event.isCancelled()) { - if (data.debug) { + if (debug) { debugTeleportMessage(player, event, "Cancel event, that has no target location (to) set."); } event.setCancelled(true); @@ -1672,7 +1705,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } else { // TODO: Configurable ? - if (data.debug) { + if (debug) { debugTeleportMessage(player, event, "Prevent teleport, due to a scheduled set back: ", to); } event.setCancelled(true); @@ -1681,11 +1714,11 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } // Run checks. - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); boolean cancel = false; // Ender pearl into blocks. if (cause == TeleportCause.ENDER_PEARL) { - if (CombinedConfig.getConfig(player).enderPearlCheck && !BlockProperties.isPassable(to)) { // || !BlockProperties.isOnGroundOrResetCond(player, to, 1.0)) { + if (pData.getGenericInstance(CombinedConfig.class).enderPearlCheck && !BlockProperties.isPassable(to)) { // || !BlockProperties.isOnGroundOrResetCond(player, to, 1.0)) { // Not check on-ground: Check the second throw. // TODO: Bounding box check or onGround as replacement? cancel = true; @@ -1696,14 +1729,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Attempt to prevent teleporting to players inside of blocks at untracked coordinates. if (cc.passableUntrackedTeleportCheck) { if (cc.loadChunksOnTeleport) { - MovingUtil.ensureChunksLoaded(player, to, "teleport", data, cc); + MovingUtil.ensureChunksLoaded(player, to, "teleport", data, cc, pData); } - if (cc.passableUntrackedTeleportCheck && MovingUtil.shouldCheckUntrackedLocation(player, to)) { + if (cc.passableUntrackedTeleportCheck && MovingUtil.shouldCheckUntrackedLocation( + player, to, pData)) { final Location newTo = MovingUtil.checkUntrackedLocation(to); if (newTo != null) { // Adjust the teleport to go to the last tracked to-location of the other player. event.setTo(newTo); - // TODO: Consider console, consider data.debug. + // TODO: Consider console, consider debug. NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.TRACE_FILE, player.getName() + " correct untracked teleport destination (" + to + " corrected to " + newTo + ")."); } } @@ -1716,7 +1750,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // NCP actively prevents this teleport. event.setCancelled(true); // Log. - if (data.debug) { + if (debug) { debug(player, "TP " + cause + " (cancel): " + to); } } @@ -1742,17 +1776,18 @@ public class MovingListener extends CheckListener implements TickListener, IRemo */ private void checkUndoCancelledSetBack(final PlayerTeleportEvent event) { final Player player = event.getPlayer(); - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); // Revert cancel on set back (only precise match). if (data.hasTeleported()) { // Teleport by NCP. // TODO: What if not scheduled. - undoCancelledSetBack(player, event, data); + undoCancelledSetBack(player, event, data, pData); } } private final void undoCancelledSetBack(final Player player, final PlayerTeleportEvent event, - final MovingData data) { + final MovingData data, final IPlayerData pData) { // Prevent cheaters getting rid of flying data (morepackets, other). // TODO: even more strict enforcing ? event.setCancelled(false); // TODO: Does this make sense? Have it configurable rather? @@ -1767,7 +1802,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo */ event.setFrom(teleported); } - if (data.debug) { + if (pData.isDebugActive(checkType)) { NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning( Streams.TRACE_FILE, player.getName() + " TP " + event.getCause() + " (revert cancel on set back): " + event.getTo()); @@ -1783,7 +1818,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo public void onPlayerTeleportMonitor(final PlayerTeleportEvent event) { // Evaluate result and adjust data. final Player player = event.getPlayer(); - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); // Invalidate first-move thing. // TODO: Might conflict with 'moved wrongly' on join. @@ -1792,17 +1828,18 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Special cases. final Location to = event.getTo(); if (event.isCancelled()) { - onPlayerTeleportMonitorCancelled(player, event, to, data); + onPlayerTeleportMonitorCancelled(player, event, to, data, pData); return; } else if (to == null) { // Weird event. - onPlayerTeleportMonitorNullTarget(player, event, to, data); + onPlayerTeleportMonitorNullTarget(player, event, to, data, pData); return; } - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); // Detect our own player set backs. - if (data.hasTeleported() && onPlayerTeleportMonitorHasTeleported(player, event, to, data, cc)) { + if (data.hasTeleported() && onPlayerTeleportMonitorHasTeleported(player, + event, to, data, cc, pData)) { return; } @@ -1828,7 +1865,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo data.setSetBack(to); data.sfHoverTicks = -1; // Important against concurrent modification exception. if (cc.loadChunksOnTeleport) { - MovingUtil.ensureChunksLoaded(player, to, "teleport", data, cc); + MovingUtil.ensureChunksLoaded(player, to, "teleport", data, cc, pData); } aux.resetPositionsAndMediumProperties(player, to, data, cc); // TODO: Decide to remove the LiftOffEnvelope thing completely. @@ -1839,7 +1876,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // } // Reset stuff. - Combined.resetYawRate(player, to.getYaw(), System.currentTimeMillis(), true); // TODO: Not sure. + Combined.resetYawRate(player, to.getYaw(), System.currentTimeMillis(), true, pData); // TODO: Not sure. data.resetTeleported(); if (!skipExtras) { @@ -1882,7 +1919,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } // Log. - if (data.debug) { + if (pData.isDebugActive(checkType)) { debugTeleportMessage(player, event, "(normal)", to); } } @@ -1898,15 +1935,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * otherwise. */ private boolean onPlayerTeleportMonitorHasTeleported(final Player player, final PlayerTeleportEvent event, - final Location to, final MovingData data, final MovingConfig cc) { + final Location to, final MovingData data, final MovingConfig cc, final IPlayerData pData) { if (data.isTeleportedPosition(to)) { // Set back. - confirmSetBack(player, true, data, cc); + confirmSetBack(player, true, data, cc, pData); // Reset some more data. // TODO: Some more? data.reducePlayerMorePacketsData(1); // Log. - if (data.debug) { + if (pData.isDebugActive(checkType)) { debugTeleportMessage(player, event, "(set back)", to); } return true; @@ -1936,22 +1973,24 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @param cc */ private void confirmSetBack(final Player player, final boolean fakeNews, final MovingData data, - final MovingConfig cc) { + final MovingConfig cc, final IPlayerData pData) { final Location teleported = data.getTeleported(); final PlayerMoveInfo moveInfo = aux.usePlayerMoveInfo(); moveInfo.set(player, teleported, null, cc.yOnGround); if (cc.loadChunksOnTeleport) { - MovingUtil.ensureChunksLoaded(player, teleported, "teleport", data, cc); + MovingUtil.ensureChunksLoaded(player, teleported, + "teleport", data, cc, pData); } data.onSetBack(moveInfo.from); aux.returnPlayerMoveInfo(moveInfo); // Reset stuff. - Combined.resetYawRate(player, teleported.getYaw(), System.currentTimeMillis(), true); // TODO: Not sure. + Combined.resetYawRate(player, teleported.getYaw(), + System.currentTimeMillis(), true, pData); // TODO: Not sure. data.resetTeleported(); } private void onPlayerTeleportMonitorCancelled(final Player player, final PlayerTeleportEvent event, - final Location to, final MovingData data) { + final Location to, final MovingData data, final IPlayerData pData) { if (data.isTeleported(to)) { // (Only precise match.) // TODO: Schedule a teleport to set back with PlayerData (+ failure count)? @@ -1961,29 +2000,31 @@ public class MovingListener extends CheckListener implements TickListener, IRemo + " TP " + event.getCause() + " (set back was prevented): " + to); } else { - if (data.debug) { + if (pData.isDebugActive(checkType)) { debugTeleportMessage(player, event, to); } } data.resetTeleported(); } - private void onPlayerTeleportMonitorNullTarget(final Player player, final PlayerTeleportEvent event, - final Location to, final MovingData data) { - if (data.debug) { + private void onPlayerTeleportMonitorNullTarget(final Player player, + final PlayerTeleportEvent event, final Location to, + final MovingData data, final IPlayerData pData) { + final boolean debug = pData.isDebugActive(checkType); + if (debug) { debugTeleportMessage(player, event, "No target location (to) set."); } if (data.hasTeleported()) { if (DataManager.getPlayerData(player).isPlayerSetBackScheduled()) { // Assume set back event following later. event.setCancelled(true); - if (data.debug) { + if (debug) { debugTeleportMessage(player, event, "Cancel, due to a scheduled set back."); } } else { data.resetTeleported(); - if (data.debug) { + if (debug) { debugTeleportMessage(player, event, "Skip set back, not being scheduled."); } } @@ -2032,7 +2073,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onPlayerVelocity(final PlayerVelocityEvent event) { final Player player = event.getPlayer(); - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); // Ignore players who are in vehicles. if (player.isInsideVehicle()) { data.removeAllVelocity(); @@ -2040,7 +2082,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } // Process velocity. final Vector velocity = event.getVelocity(); - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); data.addVelocity(player, cc, velocity.getX(), velocity.getY(), velocity.getZ()); } @@ -2057,14 +2099,14 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } private void checkFallDamageEvent(final Player player, final EntityDamageEvent event) { - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); if (player.isInsideVehicle()) { // Ignore vehicles (noFallFallDistance will be inaccurate anyway). data.clearNoFallData(); return; } - final PlayerData pData = DataManager.getPlayerData(player); - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); final PlayerMoveInfo moveInfo = aux.usePlayerMoveInfo(); final double yOnGround = Math.max(cc.noFallyOnGround, cc.yOnGround); final Location loc = player.getLocation(useLoc); @@ -2072,17 +2114,18 @@ public class MovingListener extends CheckListener implements TickListener, IRemo final PlayerLocation pLoc = moveInfo.from; pLoc.collectBlockFlags(yOnGround); if (event.isCancelled() || !MovingUtil.shouldCheckSurvivalFly(player, pLoc, data, cc, pData) - || !noFall.isEnabled(player, cc)) { + || !noFall.isEnabled(player, pData)) { data.clearNoFallData(); useLoc.setWorld(null); aux.returnPlayerMoveInfo(moveInfo); return; } + final boolean debug = pData.isDebugActive(CheckType.MOVING_NOFALL); boolean allowReset = true; float fallDistance = player.getFallDistance(); final float yDiff = (float) (data.noFallMaxY - loc.getY()); final double damage = BridgeHealth.getDamage(event); - if (data.debug) { + if (debug) { debug(player, "Damage(FALL/PRE): " + damage + " / mc=" + player.getFallDistance() + " nf=" + data.noFallFallDistance + " yDiff=" + yDiff); } // NoFall bypass checks. @@ -2117,7 +2160,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * are other cases not ending up in lava, but having a * reduced fall distance (then bigger than nofall data). */ - if (data.debug) { + if (debug) { debug(player, "NoFall/Damage: allow fall damage in lava (hotfix)."); } } @@ -2134,7 +2177,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo } else { // Adjust and continue. - if (data.debug) { + if (debug) { debug(player, "NoFall/Damage: override player fall distance and damage (" + fallDistance + " -> " + dataDist + ")."); } fallDistance = dataDist; @@ -2169,14 +2212,14 @@ public class MovingListener extends CheckListener implements TickListener, IRemo if (maxD > damage) { // TODO: respect dealDamage ? BridgeHealth.setDamage(event, maxD); - if (data.debug) { + if (debug) { debug(player, "Adjust fall damage to: " + maxD); } } if (allowReset) { // Normal fall damage, reset data. data.clearNoFallData(); - if (data.debug) { + if (debug) { debug(player, "Reset NoFall data on fall damage."); } } @@ -2218,12 +2261,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @EventHandler(priority = EventPriority.MONITOR) public void onPlayerRespawn(final PlayerRespawnEvent event) { final Player player = event.getPlayer(); - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); // TODO: Prevent/cancel scheduled teleport (use PlayerData/task for teleport, or a sequence count). data.clearMostMovingCheckData(); data.resetSetBack(); // To force dataOnJoin to set it to loc. // Handle respawn like join. - dataOnJoin(player, event.getRespawnLocation(), data, MovingConfig.getConfig(player), true); + dataOnJoin(player, event.getRespawnLocation(), true, + data, pData.getGenericInstance(MovingConfig.class), + pData.isDebugActive(checkType)); // Patch up issues. if (Bridge1_9.hasGetItemInOffHand() && player.isBlocking()) { // Attempt to fix server-side-only blocking after respawn. @@ -2254,7 +2300,11 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @Override public void playerJoins(final Player player) { - dataOnJoin(player, player.getLocation(useLoc), MovingData.getData(player), MovingConfig.getConfig(player), false); + final IPlayerData pData = DataManager.getPlayerData(player); + dataOnJoin(player, player.getLocation(useLoc), + false, pData.getGenericInstance(MovingData.class), + pData.getGenericInstance(MovingConfig.class), + pData.isDebugActive(checkType)); // Cleanup. useLoc.setWorld(null); } @@ -2266,10 +2316,13 @@ public class MovingListener extends CheckListener implements TickListener, IRemo *
  • data.setSetBack(...)
  • * @param player * @param loc Can be useLoc (!). + * @param isRespawn * @param data * @param cc + * @param debug */ - private void dataOnJoin(Player player, Location loc, MovingData data, MovingConfig cc, boolean isRespawn) { + private void dataOnJoin(Player player, Location loc, boolean isRespawn, + MovingData data, MovingConfig cc, final boolean debug) { final int tick = TickTask.getTick(); final String tag = isRespawn ? "Respawn" : "Join"; @@ -2277,7 +2330,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo if (cc.loadChunksOnJoin) { // (Don't use past-move heuristic for skipping here.) final int loaded = MapUtil.ensureChunksLoaded(loc.getWorld(), loc.getX(), loc.getZ(), Magic.CHUNK_LOAD_MARGIN_MIN); - if (loaded > 0 && data.debug) { + if (loaded > 0 && debug) { StaticLog.logInfo("Player " + tag + ": Loaded " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + loc.getWorld().getName() + " for player: " + player.getName()); } } @@ -2325,7 +2378,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo vehicleChecks.onPlayerVehicleEnter(player, player.getVehicle()); } - if (data.debug) { + if (debug) { // Log location. debug(player, tag + ": " + loc); } @@ -2355,10 +2408,11 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @Override public void playerLeaves(final Player player) { - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); final Location loc = player.getLocation(useLoc); // Debug logout. - if (data.debug) { + if (pData.isDebugActive(checkType)) { StaticLog.logInfo("Player " + player.getName() + " leaves at location: " + loc.toString()); } if (!player.isSleeping() && !player.isDead()) { @@ -2373,7 +2427,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo if (d > 0.0) { // TODO: Consider to always set back here. Might skip on big distances. if (TrigUtil.manhattan(loc, refLoc) > 0 || BlockProperties.isPassable(refLoc)) { - if (passable.isEnabled(player)) { + if (passable.isEnabled(player, pData)) { StaticLog.logWarning("Potential exploit: Player " + player.getName() + " leaves, having moved into a block (not tracked by moving checks): " + player.getWorld().getName() + " / " + DebugUtil.formatMove(refLoc, loc)); // TODO: Actually trigger a passable violation (+tag). if (d > 1.25) { @@ -2395,7 +2449,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo useLoc.setWorld(null); // Adjust data. survivalFly.setReallySneaking(player, false); - noFall.onLeave(player); + noFall.onLeave(player, data, pData); // TODO: Add a method for ordinary presence-change resetting (use in join + leave). data.onPlayerLeave(); if (data.vehicleSetBackTaskId != -1) { @@ -2419,7 +2473,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerToggleSprint(final PlayerToggleSprintEvent event) { if (!event.isSprinting()) { - MovingData.getData(event.getPlayer()).timeSprinting = 0; + DataManager.getGenericInstance(event.getPlayer(), MovingData.class).timeSprinting = 0; } } @@ -2430,9 +2484,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo if (player.isFlying() || event.isFlying() && !event.isCancelled()) { return; } - final PlayerData pData = DataManager.getPlayerData(player); - final MovingData data = MovingData.getData(player); - final MovingConfig cc = MovingConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); final PlayerMoveInfo moveInfo = aux.usePlayerMoveInfo(); final Location loc = player.getLocation(useLoc); moveInfo.set(player, loc, null, cc.yOnGround); @@ -2485,7 +2539,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo rem.add(playerName); continue; } - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); if (player.isDead() || player.isSleeping() || player.isInsideVehicle()) { data.sfHoverTicks = -1; // (Removed below.) @@ -2500,7 +2555,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo data.sfHoverLoginTicks --; continue; } - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); // Check if enabled at all. if (!cc.sfHoverCheck) { rem.add(playerName); @@ -2513,7 +2568,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Don't do the heavier checking here, let moving checks reset these. continue; } - final PlayerData pData = DataManager.getPlayerData(player); if (checkHover(player, data, cc, pData, info)) { rem.add(playerName); } @@ -2538,7 +2592,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo // Don't remove but also don't check [subject to change]. continue; } - final MovingData data = MovingData.getData(player); + final MovingData data = DataManager.getGenericInstance(player, MovingData.class); final Location newTo = enforceLocation(player, player.getLocation(useLoc), data); if (newTo != null) { data.prepareSetBack(newTo); @@ -2579,7 +2633,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo * @return */ private boolean checkHover(final Player player, - final MovingData data, final MovingConfig cc, final PlayerData pData, + final MovingData data, final MovingConfig cc, final IPlayerData pData, final PlayerMoveInfo info) { // Check if player is on ground. final Location loc = player.getLocation(useLoc); // useLoc.setWorld(null) is done in onTick. @@ -2588,7 +2642,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo final boolean res; // TODO: Collect flags, more margin ? final int loaded = info.from.ensureChunksLoaded(); - if (loaded > 0 && data.debug) { + if (loaded > 0 && pData.isDebugActive(checkType)) { // DEBUG StaticLog.logInfo("Hover check: Needed to load " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + loc.getWorld().getName() + " around " + loc.getBlockX() + "," + loc.getBlockZ() + " in order to check player: " + player.getName()); } @@ -2602,7 +2656,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo final PlayerMoveInfo moveInfo = aux.usePlayerMoveInfo(); moveInfo.set(player, loc, null, cc.yOnGround); if (MovingUtil.shouldCheckSurvivalFly(player, moveInfo.from, data, cc, pData)) { - handleHoverViolation(player, loc, cc, data); + handleHoverViolation(player, loc, cc, data, pData); // Assume the player might still be hovering. res = false; data.sfHoverTicks = 0; @@ -2622,11 +2676,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo return res; } - private void handleHoverViolation(final Player player, final Location loc, final MovingConfig cc, final MovingData data) { + private void handleHoverViolation(final Player player, final Location loc, + final MovingConfig cc, final MovingData data, final IPlayerData pData) { // Check nofall damage (!). - if (cc.sfHoverFallDamage && noFall.isEnabled(player, cc)) { + if (cc.sfHoverFallDamage && noFall.isEnabled(player, pData)) { // Consider adding 3/3.5 to fall distance if fall distance > 0? - noFall.checkDamage(player, data, loc.getY()); + noFall.checkDamage(player, loc.getY(), data, pData); } // Delegate violation handling. survivalFly.handleHoverViolation(player, loc, cc, data); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/CreativeFly.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/CreativeFly.java index 4a576e80..ca6a2ace 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/CreativeFly.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/CreativeFly.java @@ -39,6 +39,7 @@ import fr.neatmonster.nocheatplus.checks.moving.util.MovingUtil; import fr.neatmonster.nocheatplus.compat.Bridge1_9; import fr.neatmonster.nocheatplus.compat.BridgeMisc; import fr.neatmonster.nocheatplus.compat.blocks.changetracker.BlockChangeTracker; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.location.PlayerLocation; import fr.neatmonster.nocheatplus.utilities.location.TrigUtil; @@ -71,12 +72,15 @@ public class CreativeFly extends Check { * @return */ public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, - final MovingData data, final MovingConfig cc, final long time, final int tick, + final MovingData data, final MovingConfig cc, final IPlayerData pData, + final long time, final int tick, final boolean useBlockChangeTracker) { // Reset tags, just in case. tags.clear(); + final boolean debug = pData.isDebugActive(type); + // Some edge data for this move. final GameMode gameMode = player.getGameMode(); final PlayerMoveData thisMove = data.playerMoves.getCurrentMove(); @@ -197,7 +201,7 @@ public class CreativeFly extends Check { final double result = Math.max(0.0, resultH) + Math.max(0.0, resultV); - if (data.debug) { + if (debug) { outpuDebugMove(player, hDistance, limitH, yDistance, limitV, model, tags, data); } @@ -228,7 +232,7 @@ public class CreativeFly extends Check { // Maximum height check (silent set back). if (to.getY() > maximumHeight) { setBack = data.getSetBack(to); - if (data.debug) { + if (debug) { debug(player, "Maximum height exceeded, silent set-back."); } } @@ -244,7 +248,7 @@ public class CreativeFly extends Check { if (setBack.getY() > maximumHeight) { // Correct the y position. setBack.setY(getCorrectedHeight(maximumHeight, setBack.getWorld())); - if (data.debug) { + if (debug) { debug(player, "Maximum height exceeded by set back, correct to: " + setBack.getY()); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/MorePackets.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/MorePackets.java index a7fae928..e587705f 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/MorePackets.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/MorePackets.java @@ -27,6 +27,7 @@ import fr.neatmonster.nocheatplus.checks.ViolationData; import fr.neatmonster.nocheatplus.checks.moving.MovingConfig; import fr.neatmonster.nocheatplus.checks.moving.MovingData; import fr.neatmonster.nocheatplus.checks.net.NetStatic; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.location.PlayerLocation; @@ -62,9 +63,11 @@ public class MorePackets extends Check { * @return */ public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, - final boolean allowSetSetBack, final MovingData data, final MovingConfig cc) { + final boolean allowSetSetBack, final MovingData data, final MovingConfig cc, + final IPlayerData pData) { // Take time once, first: final long time = System.currentTimeMillis(); + final boolean debug = pData.isDebugActive(type); // if (from.isSamePos(to)) { // // Ignore moves with "just look" for now. @@ -94,7 +97,7 @@ public class MorePackets extends Check { // Violation handling. final ViolationData vd = new ViolationData(this, player, data.morePacketsVL, violation, cc.morePacketsActions); - if (data.debug || vd.needsParameters()) { + if (debug || vd.needsParameters()) { vd.setParameter(ParameterName.PACKETS, Integer.toString(new Double(violation).intValue())); vd.setParameter(ParameterName.TAGS, StringUtil.join(tags, "+")); } @@ -107,7 +110,7 @@ public class MorePackets extends Check { // Update the set back location. (CHANGED to only update, if not a violation.) // (Might update whenever newTo == null) data.setMorePacketsSetBack(from); - if (data.debug) { + if (debug) { debug(player, "Update set back (morepackets) to from."); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/NoFall.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/NoFall.java index 781ec859..c9b0c949 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/NoFall.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/NoFall.java @@ -29,9 +29,7 @@ import fr.neatmonster.nocheatplus.checks.moving.magic.Magic; import fr.neatmonster.nocheatplus.checks.moving.model.LocationData; import fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData; import fr.neatmonster.nocheatplus.compat.BridgeHealth; -import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager; -import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.location.PlayerLocation; /** @@ -71,7 +69,8 @@ public class NoFall extends Check { * Double.NEGATIVE_INFINITY. */ private void handleOnGround(final Player player, final double y, final double previousSetBackY, - final boolean reallyOnGround, final MovingData data, final MovingConfig cc) { + final boolean reallyOnGround, final MovingData data, final MovingConfig cc, + final IPlayerData pData) { // Damage to be dealt. final float fallDist = (float) getApplicableFallHeight(player, y, previousSetBackY, data); final double maxD = getDamage(fallDist); @@ -85,7 +84,7 @@ public class NoFall extends Check { } else { // TODO: more effects like sounds, maybe use custom event with violation added. - if (data.debug) { + if (pData.isDebugActive(type)) { debug(player, "NoFall deal damage" + (reallyOnGround ? "" : "violation") + ": " + maxD); } // TODO: might not be necessary: if (mcPlayer.invulnerableTicks <= 0) [no damage event for resetting] @@ -209,8 +208,9 @@ public class NoFall extends Check { */ public void check(final Player player, final PlayerLocation pFrom, final PlayerLocation pTo, final double previousSetBackY, - final MovingData data, final MovingConfig cc) { + final MovingData data, final MovingConfig cc, final IPlayerData pData) { + final boolean debug = pData.isDebugActive(type); final PlayerMoveData thisMove = data.playerMoves.getCurrentMove(); final LocationData from = thisMove.from; final LocationData to = thisMove.to; @@ -260,7 +260,7 @@ public class NoFall extends Check { } else if (fromOnGround || !toOnGround && thisMove.touchedGround) { // Check if to deal damage (fall back damage check). - touchDown(player, minY, previousSetBackY, data, cc); // Includes the current y-distance on descend! + touchDown(player, minY, previousSetBackY, data, cc, pData); // Includes the current y-distance on descend! // Ensure very big/strange moves don't yield violations. if (toY - fromY <= -Magic.FALL_DAMAGE_DIST) { data.noFallSkipAirCheck = true; @@ -276,7 +276,7 @@ public class NoFall extends Check { // In this case the player has traveled further: add the difference. data.noFallFallDistance -= yDiff; } - touchDown(player, minY, previousSetBackY, data, cc); + touchDown(player, minY, previousSetBackY, data, cc, pData); } else { // Ensure fall distance is correct, or "anyway"? @@ -301,7 +301,7 @@ public class NoFall extends Check { else if (cc.noFallAntiCriticals && (toReset || toOnGround || (fromReset || fromOnGround || thisMove.touchedGround) && yDiff >= 0)) { final double max = Math.max(data.noFallFallDistance, mcFallDistance); if (max > 0.0 && max < 0.75) { // (Ensure this does not conflict with deal-damage set to false.) - if (data.debug) { + if (debug) { debug(player, "NoFall: Reset fall distance (anticriticals): mc=" + mcFallDistance +" / nf=" + data.noFallFallDistance); } if (data.noFallFallDistance > 0) { @@ -313,7 +313,7 @@ public class NoFall extends Check { } } - if (data.debug) { + if (debug) { debug(player, "NoFall: mc=" + mcFallDistance +" / nf=" + data.noFallFallDistance + (oldNFDist < data.noFallFallDistance ? " (+" + (data.noFallFallDistance - oldNFDist) + ")" : "") + " | ymax=" + data.noFallMaxY); } @@ -331,9 +331,9 @@ public class NoFall extends Check { * @param cc */ private void touchDown(final Player player, final double minY, final double previousSetBackY, - final MovingData data, final MovingConfig cc) { + final MovingData data, final MovingConfig cc, IPlayerData pData) { if (cc.noFallDealDamage) { - handleOnGround(player, minY, previousSetBackY, true, data, cc); + handleOnGround(player, minY, previousSetBackY, true, data, cc, pData); } else { adjustFallDistance(player, minY, true, data, cc); @@ -359,15 +359,16 @@ public class NoFall extends Check { * Quit or kick: adjust fall distance if necessary. * @param player */ - public void onLeave(final Player player) { - final MovingData data = MovingData.getData(player); + public void onLeave(final Player player, final MovingData data, + final IPlayerData pData) { final float fallDistance = player.getFallDistance(); // TODO: Might also detect too high mc fall dist. if (data.noFallFallDistance > fallDistance) { final double playerY = player.getLocation(useLoc).getY(); useLoc.setWorld(null); if (player.isFlying() || player.getGameMode() == GameMode.CREATIVE - || player.getAllowFlight() && MovingConfig.getConfig(player).noFallSkipAllowFlight) { + || player.getAllowFlight() + && pData.getGenericInstance(MovingConfig.class).noFallSkipAllowFlight) { // Forestall potential issues with flying plugins. player.setFallDistance(0f); data.noFallFallDistance = 0f; @@ -387,22 +388,12 @@ public class NoFall extends Check { * @param player * @param data */ - public void checkDamage(final Player player, final MovingData data, final double y) { - final MovingConfig cc = MovingConfig.getConfig(player); + public void checkDamage(final Player player, final double y, + final MovingData data, final IPlayerData pData) { + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); // Deal damage. handleOnGround(player, y, data.hasSetBack() ? data.getSetBackY() : Double.NEGATIVE_INFINITY, - false, data, cc); - } - - /** - * Convenience method bypassing the factories. - * @param player - * @param cc - * @return - */ - public boolean isEnabled(final Player player , final MovingConfig cc, final PlayerData pData) { - return cc.noFallCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_NOFALL) - && !pData.hasPermission(Permissions.MOVING_NOFALL, player); + false, data, cc, pData); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/Passable.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/Passable.java index 73a56e23..ea0d0223 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/Passable.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/Passable.java @@ -28,6 +28,7 @@ import fr.neatmonster.nocheatplus.checks.ViolationData; import fr.neatmonster.nocheatplus.checks.moving.MovingConfig; import fr.neatmonster.nocheatplus.checks.moving.MovingData; import fr.neatmonster.nocheatplus.compat.blocks.changetracker.BlockChangeTracker; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.collision.Axis; import fr.neatmonster.nocheatplus.utilities.collision.ICollidePassable; import fr.neatmonster.nocheatplus.utilities.collision.PassableAxisTracing; @@ -70,13 +71,20 @@ public class Passable extends Check { blockTracker = NCPAPIProvider.getNoCheatPlusAPI().getBlockChangeTracker(); } - public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, - final MovingData data, final MovingConfig cc, final int tick, final boolean useBlockChangeTracker) { - return checkActual(player, from, to, data, cc, tick, useBlockChangeTracker); + public Location check(final Player player, + final PlayerLocation from, final PlayerLocation to, + final MovingData data, final MovingConfig cc, final IPlayerData pData, + final int tick, final boolean useBlockChangeTracker) { + return checkActual(player, from, to, data, cc, pData, tick, useBlockChangeTracker); } - private Location checkActual(final Player player, final PlayerLocation from, final PlayerLocation to, - final MovingData data, final MovingConfig cc, final int tick, final boolean useBlockChangeTracker) { + private Location checkActual(final Player player, + final PlayerLocation from, final PlayerLocation to, + final MovingData data, final MovingConfig cc, final IPlayerData pData, + final int tick, final boolean useBlockChangeTracker) { + + final boolean debug = pData.isDebugActive(type); + // TODO: Distinguish feet vs. box. // Block distances (sum, max) for from-to (not for loc!). @@ -84,9 +92,11 @@ public class Passable extends Check { // Check default order first, then others. rayTracing.setAxisOrder(Axis.AXIS_ORDER_YXZ); - String newTag = checkRayTracing(player, from, to, manhattan, data, cc, tick, useBlockChangeTracker); + String newTag = checkRayTracing(player, from, to, manhattan, + data, cc, debug, tick, useBlockChangeTracker); if (newTag != null) { - newTag = checkRayTracingAlernateOrder(player, from, to, manhattan, data, cc, tick, + newTag = checkRayTracingAlernateOrder(player, from, to, manhattan, + debug, data, cc, tick, useBlockChangeTracker, newTag); } // Finally handle violations. @@ -97,13 +107,16 @@ public class Passable extends Check { } else { // Direct return. - return potentialViolation(player, from, to, manhattan, newTag, data, cc); + return potentialViolation(player, from, to, manhattan, + debug, newTag, data, cc); } } private String checkRayTracingAlernateOrder(final Player player, - final PlayerLocation from, final PlayerLocation to, final int manhattan, - final MovingData data, final MovingConfig cc, final int tick, final boolean useBlockChangeTracker, + final PlayerLocation from, final PlayerLocation to, + final int manhattan, final boolean debug, + final MovingData data, final MovingConfig cc, + final int tick, final boolean useBlockChangeTracker, final String previousTag) { /* * General assumption for now: Not all combinations have to be checked. @@ -116,16 +129,19 @@ public class Passable extends Check { if (axis == Axis.X_AXIS || axis == Axis.Z_AXIS) { // Test the horizontal alternative only. rayTracing.setAxisOrder(Axis.AXIS_ORDER_YZX); - return checkRayTracing(player, from, to, manhattan, data, cc, tick, useBlockChangeTracker); + return checkRayTracing(player, from, to, manhattan, data, cc, + debug, tick, useBlockChangeTracker); } else if (axis == Axis.Y_AXIS) { // Test both horizontal options, each before vertical. rayTracing.setAxisOrder(Axis.AXIS_ORDER_XZY); - if (checkRayTracing(player, from, to, manhattan, data, cc, tick, useBlockChangeTracker) == null) { + if (checkRayTracing(player, from, to, manhattan, data, cc, + debug, tick, useBlockChangeTracker) == null) { return null; } rayTracing.setAxisOrder(Axis.AXIS_ORDER_ZXY); - return checkRayTracing(player, from, to, manhattan, data, cc, tick, useBlockChangeTracker); + return checkRayTracing(player, from, to, manhattan, data, cc, + debug, tick, useBlockChangeTracker); } else { return previousTag; // In case nothing could be done. @@ -134,7 +150,8 @@ public class Passable extends Check { private String checkRayTracing(final Player player, final PlayerLocation from, final PlayerLocation to, final int manhattan, - final MovingData data, final MovingConfig cc, final int tick, final boolean useBlockChangeTracker) { + final MovingData data, final MovingConfig cc, final boolean debug, + final int tick, final boolean useBlockChangeTracker) { String tags = null; // NOTE: axis order is set externally. setNormalMargins(rayTracing, from); @@ -153,7 +170,7 @@ public class Passable extends Check { else if (rayTracing.getStepsDone() >= rayTracing.getMaxSteps()) { tags = "raytracing_maxsteps_"; } - if (data.debug) { + if (debug) { debugExtraCollisionDetails(player, rayTracing, "std"); } rayTracing.cleanup(); @@ -182,22 +199,25 @@ public class Passable extends Check { * @return */ private Location potentialViolation(final Player player, - final PlayerLocation from, final PlayerLocation to, final int manhattan, + final PlayerLocation from, final PlayerLocation to, + final int manhattan, final boolean debug, String tags, final MovingData data, final MovingConfig cc) { // TODO: Might need the workaround for fences. - return actualViolation(player, from, to, tags, data, cc); + return actualViolation(player, from, to, tags, debug, data, cc); } - private Location actualViolation(final Player player, final PlayerLocation from, final PlayerLocation to, - final String tags, final MovingData data, final MovingConfig cc) { + private Location actualViolation(final Player player, + final PlayerLocation from, final PlayerLocation to, + final String tags, final boolean debug, + final MovingData data, final MovingConfig cc) { Location setBackLoc = null; // Alternative to from.getLocation(). // Prefer the set back location from the data. if (data.hasSetBack()) { setBackLoc = data.getSetBack(to); - if (data.debug) { + if (debug) { debug(player, "Using set back location for passable."); } } @@ -205,7 +225,7 @@ public class Passable extends Check { // Return the reset position. data.passableVL += 1d; final ViolationData vd = new ViolationData(this, player, data.passableVL, 1, cc.passableActions); - if (data.debug || vd.needsParameters()) { + if (debug || vd.needsParameters()) { 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", TrigUtil.distance(from, to))); @@ -221,7 +241,7 @@ public class Passable extends Check { newTo = LocUtil.clone(setBackLoc); } else { newTo = from.getLocation(); - if (data.debug) { + if (debug) { debug(player, "Using from location for passable."); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/SurvivalFly.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/SurvivalFly.java index f951df45..d77aeae8 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/SurvivalFly.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/SurvivalFly.java @@ -49,7 +49,7 @@ import fr.neatmonster.nocheatplus.components.modifier.IAttributeAccess; import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle; import fr.neatmonster.nocheatplus.logging.Streams; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionAccumulator; @@ -117,12 +117,14 @@ public class SurvivalFly extends Check { * @param useBlockChangeTracker * @return */ - public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, + public Location check(final Player player, + final PlayerLocation from, final PlayerLocation to, final int multiMoveCount, - final MovingData data, final MovingConfig cc, final PlayerData pData, + final MovingData data, final MovingConfig cc, final IPlayerData pData, final int tick, final long now, final boolean useBlockChangeTracker) { tags.clear(); - if (data.debug) { + final boolean debug = pData.isDebugActive(type); + if (debug) { justUsedWorkarounds.clear(); data.ws.setJustUsedIds(justUsedWorkarounds); } @@ -255,7 +257,7 @@ public class SurvivalFly extends Check { && TrigUtil.isSamePosAndLook(thisMove.from, lastMove.to)) { // Ground somehow appeared out of thin air (block place). data.setSetBack(from); - if (data.debug) { + if (debug) { debug(player, "Adjust set back on move: from is now on ground."); } } @@ -436,7 +438,7 @@ public class SurvivalFly extends Check { vDistanceAboveLimit = res[1]; if (res[0] == Double.MIN_VALUE && res[1] == Double.MIN_VALUE) { // Silent set back. - if (data.debug) { + if (debug) { tags.add("silentsbcobweb"); outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom, yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo, thisMove); @@ -486,7 +488,7 @@ public class SurvivalFly extends Check { // Debug output. final int tagsLength; - if (data.debug) { + if (debug) { outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom, yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo, thisMove); tagsLength = tags.size(); @@ -660,7 +662,7 @@ public class SurvivalFly extends Check { // Update unused velocity tracking. // TODO: Hide and seek with API. // TODO: Pull down tick / timing data (perhaps add an API object for millis + source + tick + sequence count (+ source of sequence count). - if (data.debug) { + if (debug) { // TODO: Only update, if velocity is queued at all. data.getVerticalVelocityTracker().updateBlockedState(tick, // Assume blocked with being in web/water, despite not entirely correct. @@ -676,14 +678,16 @@ public class SurvivalFly extends Check { data.lastFrictionVertical = data.nextFrictionVertical; // Log tags added after violation handling. - if (data.debug && tags.size() > tagsLength) { + if (debug && tags.size() > tagsLength) { logPostViolationTags(player); } return null; } - private boolean toOnGroundPastStates(final PlayerLocation from, final PlayerLocation to, - final PlayerMoveData thisMove, int tick, final MovingData data, final MovingConfig cc) { + private boolean toOnGroundPastStates( + final PlayerLocation from, final PlayerLocation to, + final PlayerMoveData thisMove, int tick, + final MovingData data, final MovingConfig cc) { // TODO: Heuristics / more / which? (too short move, typical step up moves, typical levels, ...) if (to.isOnGroundOpportune(cc.yOnGround, 0L, blockChangeTracker, data.blockChangeRef, tick)) { tags.add("pastground_to"); @@ -782,7 +786,8 @@ public class SurvivalFly extends Check { * @param data * @param cc */ - private void setNextFriction(final PlayerMoveData thisMove, final MovingData data, final MovingConfig cc) { + private void setNextFriction(final PlayerMoveData thisMove, + final MovingData data, final MovingConfig cc) { // NOTE: Other methods might still override nextFriction to 1.0 due to burst/lift-off envelope. // TODO: Other media / medium transitions / friction by block. final LocationData from = thisMove.from; @@ -830,7 +835,7 @@ public class SurvivalFly extends Check { */ private double setAllowedhDist(final Player player, final boolean sprinting, final PlayerMoveData thisMove, - final MovingData data, final MovingConfig cc, final PlayerData pData, + final MovingData data, final MovingConfig cc, final IPlayerData pData, final boolean checkPermissions) { // TODO: Optimize for double checking? @@ -1003,9 +1008,10 @@ public class SurvivalFly extends Check { */ private double[] vDistAir(final long now, final Player player, final PlayerLocation from, final boolean fromOnGround, final boolean resetFrom, final PlayerLocation to, - final boolean toOnGround, final boolean resetTo, final double hDistance, final double yDistance, + final boolean toOnGround, final boolean resetTo, + final double hDistance, final double yDistance, final int multiMoveCount, final PlayerMoveData lastMove, - final MovingData data, final MovingConfig cc, final PlayerData pData) { + final MovingData data, final MovingConfig cc, final IPlayerData pData) { final PlayerMoveData thisMove = data.playerMoves.getCurrentMove(); // Y-distance for normal jumping, like in air. double vAllowedDistance = 0.0; @@ -1327,7 +1333,8 @@ public class SurvivalFly extends Check { * @param cc * @return */ - private double vAllowedDistanceNoData(final PlayerMoveData thisMove, final PlayerMoveData lastMove, + private double vAllowedDistanceNoData( + final PlayerMoveData thisMove, final PlayerMoveData lastMove, final double maxJumpGain, final double jumpGainMargin, final MovingData data, final MovingConfig cc) { if (lastMove.valid) { @@ -1425,7 +1432,8 @@ public class SurvivalFly extends Check { * @param tag Tag to be added in case of a violation of this sub-check. * @return A violation value > 0.001, to be interpreted like a moving violation. */ - private static final double verticalAccounting(final double yDistance, final ActionAccumulator acc, final ArrayList tags, final String tag) { + private static final double verticalAccounting(final double yDistance, + final ActionAccumulator acc, final ArrayList tags, final String tag) { // TODO: Add air friction and do it per move anyway !? final int count0 = acc.bucketCount(0); if (count0 > 0) { @@ -1463,7 +1471,9 @@ public class SurvivalFly extends Check { * @param vDistanceAboveLimit * @return vDistanceAboveLimit */ - private double yDirChange(final PlayerLocation from, final PlayerLocation to, final double yDistance, double vDistanceAboveLimit, final PlayerMoveData lastMove, final MovingData data) { + private double yDirChange(final PlayerLocation from, final PlayerLocation to, + final double yDistance, double vDistanceAboveLimit, + final PlayerMoveData lastMove, final MovingData data) { // TODO: Does this account for velocity in a sufficient way? if (yDistance > 0) { // TODO: Clear active vertical velocity here ? @@ -1538,10 +1548,11 @@ public class SurvivalFly extends Check { * @param skipPermChecks * @return hAllowedDistance, hDistanceAboveLimit, hFreedom */ - private double[] hDistAfterFailure(final Player player, final PlayerLocation from, final PlayerLocation to, + private double[] hDistAfterFailure(final Player player, + final PlayerLocation from, final PlayerLocation to, double hAllowedDistance, double hDistanceAboveLimit, final boolean sprinting, final PlayerMoveData thisMove, final PlayerMoveData lastMove, - final MovingData data, final MovingConfig cc, final PlayerData pData, + final MovingData data, final MovingConfig cc, final IPlayerData pData, final boolean skipPermChecks) { // TODO: Still not entirely sure about this checking order. @@ -1633,7 +1644,10 @@ public class SurvivalFly extends Check { * @param data * @return hDistanceAboveLimit */ - private double bunnyHop(final PlayerLocation from, final PlayerLocation to, final double hAllowedDistance, double hDistanceAboveLimit, final boolean sprinting, final PlayerMoveData thisMove, final PlayerMoveData lastMove, final MovingData data, final MovingConfig cc) { + private double bunnyHop(final PlayerLocation from, final PlayerLocation to, + final double hAllowedDistance, double hDistanceAboveLimit, final boolean sprinting, + final PlayerMoveData thisMove, final PlayerMoveData lastMove, + final MovingData data, final MovingConfig cc) { // Check "bunny fly" here, to not fall over sprint resetting on the way. boolean allowHop = true; boolean double_bunny = false; @@ -1819,7 +1833,9 @@ public class SurvivalFly extends Check { * @param data * @return vAllowedDistance, vDistanceAboveLimit */ - private double[] vDistLiquid(final PlayerLocation from, final PlayerLocation to, final boolean toOnGround, final double yDistance, final PlayerMoveData lastMove, final MovingData data) { + private double[] vDistLiquid(final PlayerLocation from, final PlayerLocation to, + final boolean toOnGround, final double yDistance, final PlayerMoveData lastMove, + final MovingData data) { data.sfNoLowJump = true; // Expected envelopes. @@ -1879,7 +1895,8 @@ public class SurvivalFly extends Check { * @param data * @return vDistanceAboveLimit */ - private double vDistClimbable(final Player player, final PlayerLocation from, final PlayerLocation to, + private double vDistClimbable(final Player player, + final PlayerLocation from, final PlayerLocation to, final boolean fromOnGround, final boolean toOnGround, final PlayerMoveData thisMove, final PlayerMoveData lastMove, final double yDistance, final MovingData data) { @@ -1951,7 +1968,9 @@ public class SurvivalFly extends Check { * @param cc * @return vAllowedDistance, vDistanceAboveLimit */ - private double[] vDistWeb(final Player player, final PlayerMoveData thisMove, final boolean toOnGround, final double hDistanceAboveLimit, final long now, final MovingData data, final MovingConfig cc) { + private double[] vDistWeb(final Player player, final PlayerMoveData thisMove, + final boolean toOnGround, final double hDistanceAboveLimit, final long now, + final MovingData data, final MovingConfig cc) { final double yDistance = thisMove.yDistance; double vAllowedDistance = 0.0; double vDistanceAboveLimit = 0.0; @@ -2000,7 +2019,9 @@ public class SurvivalFly extends Check { * @param cc * @return */ - private Location handleViolation(final long now, final double result, final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc) + private Location handleViolation(final long now, final double result, + final Player player, final PlayerLocation from, final PlayerLocation to, + final MovingData data, final MovingConfig cc) { // Increment violation level. data.survivalFlyVL += result; @@ -2032,7 +2053,8 @@ public class SurvivalFly extends Check { * @param cc * @param data */ - public final void handleHoverViolation(final Player player, final Location loc, final MovingConfig cc, final MovingData data) { + public final void handleHoverViolation(final Player player, final Location loc, + final MovingConfig cc, final MovingData data) { data.survivalFlyVL += cc.sfHoverViolation; // TODO: Extra options for set back / kick, like vl? @@ -2125,7 +2147,8 @@ public class SurvivalFly extends Check { final MovingData data, final MovingConfig cc, final double hDistance, final double hAllowedDistance, final double hFreedom, final double yDistance, final double vAllowedDistance, - final boolean fromOnGround, final boolean resetFrom, final boolean toOnGround, final boolean resetTo, + final boolean fromOnGround, final boolean resetFrom, + final boolean toOnGround, final boolean resetTo, final PlayerMoveData thisMove) { // TODO: Show player name once (!) final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove(); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/UnusedVelocity.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/UnusedVelocity.java index e8cefcf9..b45f8e5c 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/UnusedVelocity.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/UnusedVelocity.java @@ -14,15 +14,15 @@ */ package fr.neatmonster.nocheatplus.checks.moving.player; -import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.checks.moving.MovingConfig; - import org.bukkit.entity.Player; +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.checks.moving.MovingConfig; import fr.neatmonster.nocheatplus.checks.moving.MovingData; import fr.neatmonster.nocheatplus.checks.moving.velocity.SimpleAxisVelocity; import fr.neatmonster.nocheatplus.checks.moving.velocity.UnusedTracker; import fr.neatmonster.nocheatplus.logging.debug.DebugUtil; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.CheckUtils; public class UnusedVelocity { @@ -35,8 +35,13 @@ public class UnusedVelocity { * @param player * @return If the player has failed the check, whatever that means. */ - public static boolean checkUnusedVelocity(final Player player, final CheckType checkType) { - return checkUnusedVelocity(player, checkType, MovingData.getData(player), MovingConfig.getConfig(player)); + public static boolean checkUnusedVelocity(final Player player, + final CheckType checkType, final IPlayerData pData) { + return checkUnusedVelocity( + player, checkType, + pData.getGenericInstance(MovingData.class), + pData.getGenericInstance(MovingConfig.class) + ); } @@ -48,7 +53,8 @@ public class UnusedVelocity { * @param cc * @return If the player has failed the check, whatever that means. */ - public static boolean checkUnusedVelocity(final Player player, final CheckType checkType, final MovingData data, final MovingConfig cc) { + public static boolean checkUnusedVelocity(final Player player, + final CheckType checkType, final MovingData data, final MovingConfig cc) { boolean violation = false; final SimpleAxisVelocity verVel = data.getVerticalVelocityTracker(); violation |= quickCheckDirection(player, verVel.unusedTrackerPos, checkType, "vert/pos", data, cc); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/util/MovingUtil.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/util/MovingUtil.java index 11c09b85..0e33f0e5 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/util/MovingUtil.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/util/MovingUtil.java @@ -39,11 +39,9 @@ import fr.neatmonster.nocheatplus.compat.Bridge1_9; import fr.neatmonster.nocheatplus.compat.BridgeMisc; import fr.neatmonster.nocheatplus.compat.MCAccess; import fr.neatmonster.nocheatplus.components.debug.IDebugPlayer; -import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager; import fr.neatmonster.nocheatplus.logging.StaticLog; -import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.location.LocUtil; import fr.neatmonster.nocheatplus.utilities.location.PlayerLocation; @@ -77,17 +75,13 @@ public class MovingUtil { * @return */ public static final boolean shouldCheckSurvivalFly(final Player player, final PlayerLocation fromLocation, - final MovingData data, final MovingConfig cc, final PlayerData pData) { + final MovingData data, final MovingConfig cc, final IPlayerData pData) { final GameMode gameMode = player.getGameMode(); - /* - * TODO: Model rare to check conditions (elytra, ...) on base of one - * pre-check and a method to delegate to. Reuse method(s) with - * MovingConfig. - */ - return cc.survivalFlyCheck && gameMode != BridgeMisc.GAME_MODE_SPECTATOR + // (Full activation check - use permission caching for performance rather.) + return pData.isCheckActive(CheckType.MOVING_SURVIVALFLY, player) + && gameMode != BridgeMisc.GAME_MODE_SPECTATOR && (cc.ignoreCreative || gameMode != GameMode.CREATIVE) && !player.isFlying() && (cc.ignoreAllowFlight || !player.getAllowFlight()) - && !NCPExemptionManager.isExempted(player, CheckType.MOVING_SURVIVALFLY) && ( !Bridge1_9.isGlidingWithElytra(player) || !isGlidingWithElytraValid(player, fromLocation, data, cc) @@ -96,7 +90,7 @@ public class MovingUtil { Double.isInfinite(Bridge1_9.getLevitationAmplifier(player)) || fromLocation.isInLiquid() ) - && !pData.hasPermission(Permissions.MOVING_SURVIVALFLY, player); + ; } /** @@ -287,10 +281,11 @@ public class MovingUtil { * @param loc * @return */ - public static boolean shouldCheckUntrackedLocation(final Player player, final Location loc) { + public static boolean shouldCheckUntrackedLocation(final Player player, + final Location loc, final IPlayerData pData) { return !TrigUtil.isSamePos(loc, loc.getWorld().getSpawnLocation()) && !BlockProperties.isPassable(loc) - && CheckType.MOVING_PASSABLE.isEnabled(player); + && pData.isCheckActive(CheckType.MOVING_PASSABLE, player); } /** @@ -321,7 +316,8 @@ public class MovingUtil { // TODO: Exempt other warps -> HASH based exemption (expire by time, keep high count)? if (TrigUtil.isSamePos(loc, refLoc) && (entity instanceof Player)) { final Player other = (Player) entity; - final MovingData otherData = MovingData.getData(other); + final IPlayerData otherPData = DataManager.getPlayerData(other); + final MovingData otherData = otherPData.getGenericInstance(MovingData.class); final PlayerMoveData otherLastMove = otherData.playerMoves.getFirstPastMove(); if (!otherLastMove.toIsValid) { // Data might have been removed. @@ -365,8 +361,10 @@ public class MovingUtil { * @param data * @return */ - public static double getRealisticFallDistance(final Player player, final double fromY, final double toY, final MovingData data) { - if (CheckType.MOVING_NOFALL.isEnabled(player)) { // Not optimal + public static double getRealisticFallDistance(final Player player, + final double fromY, final double toY, + final MovingData data, final IPlayerData pData) { + if (pData.isCheckActive(CheckType.MOVING_NOFALL, player)) { // (NoFall will not be checked, if this method is called.) if (data.noFallMaxY >= fromY ) { return Math.max(0.0, data.noFallMaxY - toY); @@ -387,7 +385,8 @@ public class MovingUtil { * @param from * @param data */ - public static void checkSetBack(final Player player, final PlayerLocation from, final MovingData data, final IDebugPlayer idp) { + public static void checkSetBack(final Player player, final PlayerLocation from, + final MovingData data, final IPlayerData pData, final IDebugPlayer idp) { if (!data.hasSetBack()) { data.setSetBack(from); } @@ -396,7 +395,7 @@ public class MovingUtil { (from.isOnGround() || from.isResetCond())) { // TODO: Move most to a method? // TODO: Is a margin needed for from.isOnGround()? [bukkitapionly] - if (data.debug) { + if (pData.isDebugActive(CheckType.MOVING)) { // TODO: Should this be info? idp.debug(player, "Adjust set back after join/respawn: " + from.getLocation()); } @@ -446,8 +445,9 @@ public class MovingUtil { * @param data * @param cc */ - public static void ensureChunksLoaded(final Player player, final Location from, final Location to, final PlayerMoveData lastMove, - final String tag, final MovingData data, final MovingConfig cc) { + public static void ensureChunksLoaded(final Player player, + final Location from, final Location to, final PlayerMoveData lastMove, + final String tag, final MovingConfig cc, final IPlayerData pData) { // (Worlds must be equal. Ensured in player move handling.) final double x0 = from.getX(); final double z0 = from.getZ(); @@ -489,7 +489,7 @@ public class MovingUtil { if (loadTo) { loaded += MapUtil.ensureChunksLoaded(to.getWorld(), x1, z1, margin); } - if (loaded > 0 && data.debug) { + if (loaded > 0 && pData.isDebugActive(CheckType.MOVING)) { StaticLog.logInfo("Player " + tag + ": Loaded " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + from.getWorld().getName() + " for player: " + player.getName()); } } @@ -505,8 +505,10 @@ public class MovingUtil { * @param data * @param cc */ - public static void ensureChunksLoaded(final Player player, final Location loc, final String tag, - final MovingData data, final MovingConfig cc) { + public static void ensureChunksLoaded(final Player player, + final Location loc, final String tag, + final MovingData data, final MovingConfig cc, + final IPlayerData pData) { final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove(); final double x0 = loc.getX(); final double z0 = loc.getZ(); @@ -524,7 +526,7 @@ public class MovingUtil { } } int loaded = MapUtil.ensureChunksLoaded(loc.getWorld(), loc.getX(), loc.getZ(), Magic.CHUNK_LOAD_MARGIN_MIN); - if (loaded > 0 && data.debug) { + if (loaded > 0 && pData.isDebugActive(CheckType.MOVING)) { StaticLog.logInfo("Player " + tag + ": Loaded " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + loc.getWorld().getName() + " for player: " + player.getName()); } } @@ -537,7 +539,8 @@ public class MovingUtil { * @return */ public static boolean hasScheduledPlayerSetBack(final Player player) { - return hasScheduledPlayerSetBack(player.getUniqueId(), MovingData.getData(player)); + return hasScheduledPlayerSetBack(player.getUniqueId(), + DataManager.getGenericInstance(player, MovingData.class)); } /** @@ -548,8 +551,12 @@ public class MovingUtil { * @return */ public static boolean hasScheduledPlayerSetBack(final UUID playerId, final MovingData data) { - final PlayerData pd = DataManager.getPlayerData(playerId); - return pd != null && data.hasTeleported() && pd.isPlayerSetBackScheduled(); + return data.hasTeleported() && isPlayersetBackScheduled(playerId); + } + + private static boolean isPlayersetBackScheduled(final UUID playerId) { + final IPlayerData pd = DataManager.getPlayerData(playerId); + return pd != null && pd.isPlayerSetBackScheduled(); } /** @@ -558,10 +565,12 @@ public class MovingUtil { * @param debugMessagePrefix * @return True, if the teleport has been successful. */ - public static boolean processStoredSetBack(final Player player, final String debugMessagePrefix) { - final MovingData data = MovingData.getData(player); + public static boolean processStoredSetBack(final Player player, + final String debugMessagePrefix, final IPlayerData pData) { + final MovingData data = pData.getGenericInstance(MovingData.class); + final boolean debug = pData.isDebugActive(CheckType.MOVING); if (!data.hasTeleported()) { - if (data.debug) { + if (debug) { CheckUtils.debug(player, CheckType.MOVING, debugMessagePrefix + "No stored location available."); } return false; @@ -571,7 +580,7 @@ public class MovingUtil { final Location loc = player.getLocation(useLoc); if (data.isTeleportedPosition(loc)) { // Skip redundant teleport. - if (data.debug) { + if (debug) { CheckUtils.debug(player, CheckType.MOVING, debugMessagePrefix + "Skip teleport, player is there, already."); } data.resetTeleported(); // Not necessary to keep. @@ -582,7 +591,7 @@ public class MovingUtil { // (player is somewhere else.) // Post-1.9 packet level workaround. - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); // TODO: Consider to skip checking for packet level, if not available (plus optimize access). // TODO: Consider a config flag, so this can be turned off (set back method). final PlayerSetBackMethod method = cc.playerSetBackMethod; @@ -605,9 +614,9 @@ public class MovingUtil { */ // (CANCEL + UPDATE_FROM mean a certain teleport to the set back, still could be repeated tp.) // TODO: Better method, full sync reference? - final CountableLocation cl = ((NetData) CheckType.NET.getDataFactory().getData(player)).teleportQueue.getLastAck(); + final CountableLocation cl = pData.getGenericInstance(NetData.class).teleportQueue.getLastAck(); if (data.isTeleportedPosition(cl)) { - if (data.debug) { + if (debug) { CheckUtils.debug(player, CheckType.MOVING, debugMessagePrefix + "Skip teleport, having received an ACK for the teleport on packet level. Player is at: " + LocUtil.simpleFormat(loc)); } // Keep teleported in data. Subject to debug logs and/or discussion. @@ -623,7 +632,7 @@ public class MovingUtil { return true; } else { - if (data .debug) { + if (debug) { CheckUtils.debug(player, CheckType.MOVING, "Player set back on tick: Teleport failed."); } return false; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleChecks.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleChecks.java index 0dedc36e..850c7576 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleChecks.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleChecks.java @@ -57,13 +57,14 @@ import fr.neatmonster.nocheatplus.components.registry.event.IHandle; import fr.neatmonster.nocheatplus.logging.StaticLog; import fr.neatmonster.nocheatplus.logging.Streams; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.entity.PassengerUtil; import fr.neatmonster.nocheatplus.utilities.location.LocUtil; import fr.neatmonster.nocheatplus.utilities.location.RichBoundsLocation; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; +import fr.neatmonster.nocheatplus.worlds.IWorldDataManager; /** * Aggregate vehicle checks (moving, a player is somewhere above in the @@ -85,6 +86,8 @@ public class VehicleChecks extends CheckListener { /** The instance of NoCheatPlus. */ private final Plugin plugin = Bukkit.getPluginManager().getPlugin("NoCheatPlus"); // TODO + private final IWorldDataManager worldDataManager = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + private final Set normalVehicles = new HashSet(); /** Temporary use, reset world to null afterwards, avoid nesting. */ @@ -146,10 +149,11 @@ public class VehicleChecks extends CheckListener { return; } final EntityType vehicleType = vehicle.getType(); - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); final Location from = event.getFrom(); final Location to = event.getTo(); - if (data.debug) { + if (pData.isDebugActive(checkType)) { outputDebugVehicleMoveEvent(player, from, to); } if (from == null) { @@ -178,11 +182,14 @@ public class VehicleChecks extends CheckListener { // TODO: Ignore or continue? } // Process as move. - debug(player, "VehicleMoveEvent: legacy handling, potential issue."); + final boolean debug = pData.isDebugActive(checkType); + if (debug) { + debug(player, "VehicleMoveEvent: legacy handling, potential issue."); + } // TODO: Actually here consistency with past position tracking should be tested. // TODO: Abstraction creation before calling checkVehicleMove, compare/align with onVehicleUpdate. - checkVehicleMove(vehicle, vehicleType, from, to, player, false, data); + checkVehicleMove(vehicle, vehicleType, from, to, player, false, data, pData, debug); } private void outputDebugVehicleMoveEvent(final Player player, final Location from, final Location to) { @@ -201,12 +208,14 @@ public class VehicleChecks extends CheckListener { * @param to * @param data */ - public Location onPlayerMoveVehicle(final Player player, final Location from, final Location to, final MovingData data) { + public Location onPlayerMoveVehicle(final Player player, + final Location from, final Location to, + final MovingData data, final IPlayerData pData) { // Workaround for pigs and other (1.5.x and before)! // Note that with 1.6 not even PlayerMove fires for horses and pigs. // (isInsideVehicle is the faster check without object creation, do re-check though, if it changes to only check for Vehicle instances.) final Entity vehicle = passengerUtil.getLastNonPlayerVehicle(player); - if (data.debug) { + if (pData.isDebugActive(checkType)) { debug(player, "onPlayerMoveVehicle: vehicle: " + vehicle); } data.wasInVehicle = true; @@ -225,14 +234,15 @@ public class VehicleChecks extends CheckListener { final EntityType vehicleType = vehicle.getType(); if (!normalVehicles.contains(vehicleType)) { // Treat like VehicleUpdateEvent. - onVehicleUpdate(vehicle, vehicleType, player, true, data); + onVehicleUpdate(vehicle, vehicleType, player, true, + data, pData, pData.isDebugActive(checkType)); return null; } else { final Location vLoc = vehicle.getLocation(); data.vehicleConsistency = MoveConsistency.getConsistency(from, to, vLoc); // TODO: Consider TeleportUtil.forceMount or similar. - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); if (data.vehicleConsistency == MoveConsistency.INCONSISTENT) { if (cc.vehicleEnforceLocation) { // checks.moving.vehicle.enforcelocation @@ -258,7 +268,7 @@ public class VehicleChecks extends CheckListener { * @param event */ @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void b(final VehicleUpdateEvent event) { + public void onVehicleUpdate(final VehicleUpdateEvent event) { // TODO: VehicleUpdateEvent. How to track teleporting of the vehicle? // TODO: Track just left vehicle/entity positions otherwise (on tick + vehicle update)? // TODO: No problem: (?) update 'authorized state' if no player passenger. @@ -267,7 +277,7 @@ public class VehicleChecks extends CheckListener { if (!normalVehicles.contains(vehicleType)) { // A little extra sweep to check for debug flags. normalVehicles.add(vehicleType); - if (MovingConfig.getConfig(vehicle.getWorld().getName()).debug) { + if (worldDataManager.getWorldData(vehicle.getWorld()).isDebugActive(checkType)) { debug(null, "VehicleUpdateEvent fired for: " + vehicleType); } } @@ -285,14 +295,16 @@ public class VehicleChecks extends CheckListener { onPlayerVehicleLeave(player, vehicle); return; } - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); //final MovingConfig cc = MovingConfig.getConfig(player); - if (data.debug) { + final boolean debug = pData.isDebugActive(checkType); + if (debug) { final Location loc = vehicle.getLocation(useLoc1); debug(player, "VehicleUpdateEvent: " + vehicleType + " " + loc); useLoc1.setWorld(null); } - onVehicleUpdate(vehicle, vehicleType, player, false, data); + onVehicleUpdate(vehicle, vehicleType, player, false, data, pData, debug); } /** @@ -309,19 +321,20 @@ public class VehicleChecks extends CheckListener { * @param fake * True, if this is the real VehicleUpdateEvent, false if it's * the PlayerMoveEvent (or other). + * @param pData */ private void onVehicleUpdate(final Entity vehicle, final EntityType vehicleType, final Player player, final boolean fake, - final MovingData data) { + final MovingData data, final IPlayerData pData, final boolean debug) { // TODO: (private or public?) // TODO: Might pass last position for reference. - if (data.debug) { + if (debug) { if (lastPosLook != null) { // Retrieve last pos. lastPosLook.getHandle().getPositionAndLook(vehicle, usePos1); debug(player, "Last position is reported as: " + LocUtil.simpleFormat(usePos1)); } } - checkVehicleMove(vehicle, vehicleType, null, null, player, true, data); + checkVehicleMove(vehicle, vehicleType, null, null, player, true, data, pData, debug); } /** @@ -337,13 +350,14 @@ public class VehicleChecks extends CheckListener { * @param player * @param fake * @param data + * @param pData2 + * @param debug */ private void checkVehicleMove(final Entity vehicle, final EntityType vehicleType, final Location from, final Location to, final Player player, final boolean fake, - final MovingData data) { + final MovingData data, final IPlayerData pData, boolean debug) { // TODO: Detect teleportation and similar. - final PlayerData pData = DataManager.getPlayerData(player); - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); // Exclude certain vehicle types. if (cc.ignoredVehicles.contains(vehicleType)) { // 100% legit. @@ -360,9 +374,9 @@ public class VehicleChecks extends CheckListener { // Determine the best location to use as past move. // TODO: Could also check the set backs for plausible entries, however that would lead to a violation by default. Could use an indicator. final Location refLoc = from == null ? vehicleLocation : from; - MovingUtil.ensureChunksLoaded(player, refLoc, "vehicle move (no past move)", data, cc); + MovingUtil.ensureChunksLoaded(player, refLoc, "vehicle move (no past move)", data, cc, pData); aux.resetVehiclePositions(vehicle, refLoc, data, cc); - if (data.debug) { + if (pData.isDebugActive(checkType)) { // TODO: Might warn instead. debug(player, "Missing past move data, set to: " + firstPastMove.from); } @@ -391,12 +405,13 @@ public class VehicleChecks extends CheckListener { recoverVehicleSetBack(player, vehicle, vehicleLocation, moveInfo, data, cc); } NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.STATUS, CheckUtils.getLogMessagePrefix(player, CheckType.MOVING_VEHICLE) + "Illegal coordinates on checkVehicleMove: from: " + from + " , to: " + to); - setBack(player, vehicle, newTo, data, cc); + setBack(player, vehicle, newTo, data, cc, pData); aux.returnVehicleMoveInfo(moveInfo); return; } // Ensure chunks are loaded. - MovingUtil.ensureChunksLoaded(player, useFrom, useTo, firstPastMove, "vehicle move", data, cc); + MovingUtil.ensureChunksLoaded(player, useFrom, useTo, firstPastMove, + "vehicle move", cc, pData); // Initialize currentMove. final VehicleMoveData thisMove = data.vehicleMoves.getCurrentMove(); thisMove.set(moveInfo.from, moveInfo.to); @@ -480,8 +495,9 @@ public class VehicleChecks extends CheckListener { final Location vehicleLocation, final World world, final VehicleMoveInfo moveInfo, final VehicleMoveData thisMove, final VehicleMoveData firstPastMove, final Player player, final boolean fake, - final MovingData data, final MovingConfig cc, final PlayerData pData) { + final MovingData data, final MovingConfig cc, final IPlayerData pData) { // TODO: (private or public?) + final boolean debug = pData.isDebugActive(checkType); data.joinOrRespawn = false; data.vehicleConsistency = MoveConsistency.getConsistency(thisMove, player.getLocation(useLoc1)); @@ -506,7 +522,7 @@ public class VehicleChecks extends CheckListener { data.clearNoFallData(); } - if (data.debug) { + if (debug) { // Log move. outputDebugVehicleMove(player, vehicle, thisMove, fake); } @@ -515,19 +531,19 @@ public class VehicleChecks extends CheckListener { // Ensure a common set back for now. if (!data.vehicleSetBacks.isDefaultEntryValid()) { - ensureSetBack(player, thisMove, data); + ensureSetBack(player, thisMove, data, pData); } // Moving envelope check(s). // TODO: Use set back storage for testing if this is appropriate (use SetBackEntry instead, remove Location retrieval then?). if ((newTo == null || data.vehicleSetBacks.getSafeMediumEntry().isValidAndOlderThan(newTo)) - && vehicleEnvelope.isEnabled(player, cc, pData)) { + && pData.isCheckActive(CheckType.MOVING_VEHICLE_ENVELOPE, player)) { // Skip if this is the first move after set back, with to=set back. if (data.timeSinceSetBack == 0 || thisMove.to.hashCode() == data.lastSetBackHash) { // TODO: This is a hot fix, to prevent a set back loop. Depends on having only the morepackets set back for vehicles. // TODO: Perhaps might want to add || !data.equalsAnyVehicleSetBack(to) thisMove.specialCondition = true; - if (data.debug) { + if (debug) { debug(player, "Skip envelope check on first move after set back acknowledging the set back with an odd starting point (from)."); } } @@ -535,7 +551,8 @@ public class VehicleChecks extends CheckListener { // Set up basic details about what/how to check. vehicleEnvelope.prepareCheckDetails(vehicle, moveInfo, thisMove); // Check. - final SetBackEntry tempNewTo = vehicleEnvelope.check(player, vehicle, thisMove, fake, data, cc); + final SetBackEntry tempNewTo = vehicleEnvelope.check(player, vehicle, + thisMove, fake, data, cc, pData); if (tempNewTo != null) { newTo = tempNewTo; } @@ -545,8 +562,9 @@ public class VehicleChecks extends CheckListener { // More packets: Sort this in last, to avoid setting the set back early. Always check to adjust set back, for now. // TODO: Still always update the frequency part? if ((newTo == null || data.vehicleSetBacks.getMidTermEntry().isValidAndOlderThan(newTo))) { - if (vehicleMorePackets.isEnabled(player, cc, pData)) { - final SetBackEntry tempNewTo = vehicleMorePackets.check(player, thisMove, newTo, data, cc); + if (pData.isCheckActive(CheckType.MOVING_VEHICLE_MOREPACKETS, player)) { + final SetBackEntry tempNewTo = vehicleMorePackets.check(player, thisMove, newTo, + data, cc, pData); if (tempNewTo != null) { newTo = tempNewTo; } @@ -571,7 +589,7 @@ public class VehicleChecks extends CheckListener { data.vehicleMoves.finishCurrentMove(); } else { - setBack(player, vehicle, newTo, data, cc); + setBack(player, vehicle, newTo, data, cc, pData); } useLoc1.setWorld(null); } @@ -581,7 +599,7 @@ public class VehicleChecks extends CheckListener { for (final Entity passenger : passengers) { if ((passenger instanceof Player) && !player.equals(passenger)) { final Player otherPlayer = (Player) passenger; - final MovingData otherData = MovingData.getData(otherPlayer); + final MovingData otherData = DataManager.getGenericInstance(otherPlayer, MovingData.class); otherData.resetVehiclePositions(moveInfo.to); // TODO: Reset all precisely to what there is or this or what not. otherData.vehicleSetBacks.resetAllLazily(data.vehicleSetBacks.getOldestValidEntry()); @@ -599,7 +617,8 @@ public class VehicleChecks extends CheckListener { * @param thisMove * @param data */ - private void ensureSetBack(final Player player, final VehicleMoveData thisMove, final MovingData data) { + private void ensureSetBack(final Player player, final VehicleMoveData thisMove, + final MovingData data, final IPlayerData pData) { final IGetLocationWithLook ensureLoc; if (!data.vehicleSetBacks.isAnyEntryValid()) { ensureLoc = thisMove.from; @@ -608,20 +627,23 @@ public class VehicleChecks extends CheckListener { ensureLoc = data.vehicleSetBacks.getOldestValidEntry(); } data.vehicleSetBacks.setDefaultEntry(ensureLoc); - if (data.debug) { + if (pData.isDebugActive(checkType)) { debug(player, "Ensure vehicle set back: " + ensureLoc); } // if (data.vehicleSetBackTaskId != -1) { // // TODO: This is likely the wrong thing to do! // Bukkit.getScheduler().cancelTask(data.vehicleSetBackTaskId); // data.vehicleSetBackTaskId = -1; - // if (data.debug) { + // if (debug) { // debug(player, "Cancel set back task on ensureSetBack."); // } // } } - private void setBack(final Player player, final Entity vehicle, final SetBackEntry newTo, final MovingData data, final MovingConfig cc) { + private void setBack(final Player player, final Entity vehicle, + final SetBackEntry newTo, final MovingData data, + final MovingConfig cc, final IPlayerData pData) { + final boolean debug = pData.isDebugActive(checkType); // TODO: Generic set back manager, preventing all sorts of stuff that might be attempted or just happen before the task is running? if (data.vehicleSetBackTaskId == -1) { // Schedule a delayed task to teleport back the vehicle with the player. @@ -632,20 +654,20 @@ public class VehicleChecks extends CheckListener { // TODO: Prevent vehicle data resetting due to dismount/mount/teleport. // TODO: Force fall type of set back? // (Future: Dismount penalty does not need extra handling, both are teleported anyway.) - if (data.debug) { + if (debug) { debug(player, "Will set back to: " + newTo); } boolean scheduleSetBack = cc.scheduleVehicleSetBacks; // Schedule as task, if set so. if (scheduleSetBack) { aux.resetVehiclePositions(vehicle, LocUtil.set(useLoc2, vehicle.getWorld(), newTo), data, cc); // Heavy-ish, though. - data.vehicleSetBackTaskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new VehicleSetBackTask(vehicle, player, newTo.getLocation(vehicle.getWorld()), data.debug)); + data.vehicleSetBackTaskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new VehicleSetBackTask(vehicle, player, newTo.getLocation(vehicle.getWorld()), debug)); if (data.vehicleSetBackTaskId == -1) { NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.STATUS, "Failed to schedule vehicle set back task. Player: " + player.getName() + " , set back: " + newTo); scheduleSetBack = false; // Force direct teleport as a fall-back measure. } - else if (data.debug) { + else if (debug) { debug(player, "Vehicle set back task id: " + data.vehicleSetBackTaskId); } } @@ -658,14 +680,15 @@ public class VehicleChecks extends CheckListener { * resetting and updating the set back (if needed) is done there * (hack, subject to current review). */ - if (data.debug) { + if (debug) { debug(player, "Attempt to set the player back directly."); } - passengerUtil.teleportWithPassengers(vehicle, player, newTo.getLocation(vehicle.getWorld()), data.debug); + passengerUtil.teleportWithPassengers(vehicle, player, + newTo.getLocation(vehicle.getWorld()), debug, pData); } } - else if (data.debug) { + else if (debug) { // TODO: Reset positions. data.vehicleMoves.invalidate(); debug(player, "Vehicle set back task already scheduled, skip this time."); @@ -692,21 +715,23 @@ public class VehicleChecks extends CheckListener { * @return True, if an event is to be cancelled. */ public boolean onPlayerVehicleEnter(final Player player, final Entity vehicle) { - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final boolean debug = pData.isDebugActive(checkType); + final MovingData data = pData.getGenericInstance(MovingData.class); if (!data.isVehicleSetBack && MovingUtil.hasScheduledPlayerSetBack(player.getUniqueId(), data)) { - if (data.debug) { + if (debug) { debug(player, "Vehicle enter: prevent, due to a scheduled set back."); } return true; } - if (data.debug) { + if (debug) { debug(player, "Vehicle enter: first vehicle: " + vehicle.getClass().getName()); } // Check for nested vehicles. final Entity lastVehicle = passengerUtil.getLastNonPlayerVehicle(vehicle, true); if (lastVehicle == null) { data.clearVehicleData(); - if (data.debug) { + if (debug) { debugNestedVehicleEnter(player); } return false; @@ -714,14 +739,14 @@ public class VehicleChecks extends CheckListener { else if (!lastVehicle.equals(vehicle)) { // Nested vehicles. // TODO: Should in general skip checking these? Set backs don't yet work with these anyway (either... or ...). - if (data.debug) { + if (debug) { debug(player, "Vehicle enter: last of nested vehicles: " + lastVehicle.getClass().getName()); } - dataOnVehicleEnter(player, lastVehicle, data); + dataOnVehicleEnter(player, lastVehicle, data, pData); } else { // Proceed normally. - dataOnVehicleEnter(player, vehicle, data); + dataOnVehicleEnter(player, vehicle, data, pData); } return false; } @@ -745,9 +770,10 @@ public class VehicleChecks extends CheckListener { * @param player * @param vehicle */ - private void dataOnVehicleEnter(final Player player, final Entity vehicle, final MovingData data) { + private void dataOnVehicleEnter(final Player player, final Entity vehicle, + final MovingData data, final IPlayerData pData) { // Adjust data. - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); data.joinOrRespawn = false; data.removeAllVelocity(); // Event should have a vehicle, in case check this last. @@ -764,7 +790,7 @@ public class VehicleChecks extends CheckListener { data.vehicleSetBacks.resetAll(vLoc); } aux.resetVehiclePositions(vehicle, vLoc, data, cc); - if (data.debug) { + if (pData.isDebugActive(checkType)) { debug(player, "Vehicle enter: " + vehicle.getType() + " , player: " + useLoc2 + " c=" + data.vehicleConsistency); } useLoc1.setWorld(null); @@ -778,8 +804,9 @@ public class VehicleChecks extends CheckListener { * @param data * @param cc */ - public void onVehicleLeaveMiss(final Player player, final MovingData data, final MovingConfig cc) { - if (data.debug) { + public void onVehicleLeaveMiss(final Player player, + final MovingData data, final MovingConfig cc, final IPlayerData pData) { + if (pData.isDebugActive(checkType)) { StaticLog.logWarning("VehicleExitEvent missing for: " + player.getName()); } onPlayerVehicleLeave(player, null); @@ -808,11 +835,11 @@ public class VehicleChecks extends CheckListener { final Entity attacker = event.getAttacker(); if (attacker instanceof Player && passengerUtil.isPassenger(attacker, event.getVehicle())) { final Player player = (Player) attacker; - final MovingConfig cc = MovingConfig.getConfig(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); if (cc.vehiclePreventDestroyOwn) { - final PlayerData pData = DataManager.getPlayerData(player); - if (CheckUtils.isEnabled(CheckType.MOVING_SURVIVALFLY, player, cc, pData) - || CheckUtils.isEnabled(CheckType.MOVING_CREATIVEFLY, player, cc, pData)) { + if (pData.isCheckActive(CheckType.MOVING_SURVIVALFLY, player) + || pData.isCheckActive(CheckType.MOVING_CREATIVEFLY, player)) { } event.setCancelled(true); // TODO: This message must be configurable. @@ -836,7 +863,9 @@ public class VehicleChecks extends CheckListener { * @param vehicle May be null in case of "not possible to determine". */ private void onPlayerVehicleLeave(final Player player, final Entity vehicle) { - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); + final boolean debug = pData.isDebugActive(checkType); data.wasInVehicle = false; data.joinOrRespawn = false; // if (data.vehicleSetBackTaskId != -1) { @@ -845,7 +874,7 @@ public class VehicleChecks extends CheckListener { // return; // } - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = pData.getGenericInstance(MovingConfig.class); // TODO: Loc can be inconsistent, determine which to use ! final Location pLoc = player.getLocation(useLoc1); Location loc = pLoc; // The location to use as set back. @@ -875,7 +904,7 @@ public class VehicleChecks extends CheckListener { } } } - if (data.debug) { + if (debug) { debug(player, "Vehicle leave: " + vehicle.getType() + "@" + pLoc.distance(vLoc)); } } @@ -885,7 +914,7 @@ public class VehicleChecks extends CheckListener { loc.setY(Location.locToBlock(loc.getY()) + 1.25); } - if (data.debug) { + if (debug) { debug(player, "Vehicle leave: " + pLoc.toString() + (pLoc.equals(loc) ? "" : " / player at: " + pLoc.toString())); } aux.resetPositionsAndMediumProperties(player, loc, data, cc); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleEnvelope.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleEnvelope.java index 28f2e8d9..ea570cd7 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleEnvelope.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleEnvelope.java @@ -36,6 +36,7 @@ import fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData; import fr.neatmonster.nocheatplus.checks.moving.model.VehicleMoveData; import fr.neatmonster.nocheatplus.checks.moving.model.VehicleMoveInfo; import fr.neatmonster.nocheatplus.checks.workaround.WRPT; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.ReflectionUtil; import fr.neatmonster.nocheatplus.utilities.StringUtil; @@ -103,16 +104,21 @@ public class VehicleEnvelope extends Check { bestHorse = clazz == null ? ReflectionUtil.getClass("org.bukkit.entity.Horse") : clazz; } - public SetBackEntry check(final Player player, final Entity vehicle, final VehicleMoveData thisMove, final boolean isFake, final MovingData data, final MovingConfig cc) { + public SetBackEntry check(final Player player, final Entity vehicle, + final VehicleMoveData thisMove, final boolean isFake, + final MovingData data, final MovingConfig cc, + final IPlayerData pData) { + final boolean debug = pData.isDebugActive(type); // Delegate to a sub-check. tags.clear(); tags.add("entity." + vehicle.getType()); - if (data.debug) { + if (debug) { debugDetails.clear(); data.ws.setJustUsedIds(debugDetails); // Add just used workaround ids to this list directly, for now. } - final boolean violation = checkEntity(player, vehicle, thisMove, isFake, data, cc); - if (data.debug && !debugDetails.isEmpty()) { + final boolean violation = checkEntity(player, vehicle, thisMove, isFake, + data, cc, debug); + if (debug && !debugDetails.isEmpty()) { debugDetails(player); debugDetails.clear(); } @@ -157,9 +163,12 @@ public class VehicleEnvelope extends Check { } } - private boolean checkEntity(final Player player, final Entity vehicle, final VehicleMoveData thisMove, final boolean isFake, final MovingData data, final MovingConfig cc) { + private boolean checkEntity(final Player player, final Entity vehicle, + final VehicleMoveData thisMove, final boolean isFake, + final MovingData data, final MovingConfig cc, + final boolean debug) { boolean violation = false; - if (data.debug) { + if (debug) { debugDetails.add("inair: " + data.sfJumpPhase); } @@ -179,7 +188,7 @@ public class VehicleEnvelope extends Check { // TODO: Get extended liquid specs (allow confine to certain flags, here: water). Contains info if water is only flowing down, surface properties (non liquid blocks?), still water. if (thisMove.from.inWeb) { // TODO: Check anything? - if (data.debug) { + if (debug) { debugDetails.add(""); } // if (thisMove.yDistance > 0.0) { @@ -205,7 +214,7 @@ public class VehicleEnvelope extends Check { } else if (thisMove.from.inWater && thisMove.to.inWater) { // Default in-medium move. - if (data.debug) { + if (debug) { debugDetails.add("water-water"); } // TODO: Should still cover extreme moves here. @@ -229,27 +238,27 @@ public class VehicleEnvelope extends Check { } if (thisMove.from.onIce && thisMove.to.onIce) { // Default on-ice move. - if (data.debug) { + if (debug) { debugDetails.add("ice-ice"); } // TODO: Should still cover extreme moves here. } else { // (TODO: actually a default on-ground move.) - if (data.debug) { + if (debug) { debugDetails.add("ground-ground"); } } } else if (checkDetails.inAir) { // In-air move. - if (checkInAir(thisMove, data)) { + if (checkInAir(thisMove, data, debug)) { violation = true; } } else { // Some transition to probably handle. - if (data.debug) { + if (debug) { debugDetails.add("?-?"); } // TODO: Lift off speed etc. @@ -371,11 +380,12 @@ public class VehicleEnvelope extends Check { * @param data * @return */ - private boolean checkInAir(final VehicleMoveData thisMove, final MovingData data) { + private boolean checkInAir(final VehicleMoveData thisMove, final MovingData data, + final boolean debug) { // TODO: Distinguish sfJumpPhase and inAirDescendCount (after reaching the highest point). - if (data.debug) { + if (debug) { debugDetails.add("air-air"); } @@ -422,7 +432,7 @@ public class VehicleEnvelope extends Check { violation = false; checkDetails.checkDescendMuch = checkDetails.checkAscendMuch = false; // (Full envelope has been checked.) } - if (data.debug) { + if (debug) { debugDetails.add("maxDescend: " + maxDescend); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleMorePackets.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleMorePackets.java index c4458c24..f581db8b 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleMorePackets.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleMorePackets.java @@ -24,6 +24,7 @@ import fr.neatmonster.nocheatplus.checks.moving.MovingConfig; import fr.neatmonster.nocheatplus.checks.moving.MovingData; import fr.neatmonster.nocheatplus.checks.moving.location.setback.SetBackEntry; import fr.neatmonster.nocheatplus.checks.moving.model.VehicleMoveData; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * This check does the exact same thing as the MorePacket check but this one works for players inside vehicles. @@ -58,7 +59,8 @@ public class VehicleMorePackets extends Check { * @return the location */ public SetBackEntry check(final Player player, final VehicleMoveData thisMove, - final SetBackEntry setBack, final MovingData data, final MovingConfig cc) { + final SetBackEntry setBack, final MovingData data, final MovingConfig cc, + final IPlayerData pData) { // Take time once, first: final long time = System.currentTimeMillis(); final boolean allowSetSetBack = setBack == null && data.vehicleSetBackTaskId == -1; @@ -74,6 +76,9 @@ public class VehicleMorePackets extends Check { return data.vehicleSetBacks.getValidMidTermEntry(); } + final boolean debug = pData.isDebugActive(type); + + // Player used up buffer, they fail the check. if (data.vehicleMorePacketsBuffer < 0) { @@ -83,7 +88,7 @@ public class VehicleMorePackets extends Check { // Execute whatever actions are associated with this check and the violation level and find out if we should // cancel the event. final ViolationData vd = new ViolationData(this, player, data.vehicleMorePacketsVL, -data.vehicleMorePacketsBuffer, cc.vehicleMorePacketsActions); - if (data.debug || vd.needsParameters()) { + if (debug || vd.needsParameters()) { vd.setParameter(ParameterName.PACKETS, Integer.toString(-data.vehicleMorePacketsBuffer)); } if (executeActions(vd).willCancel()){ @@ -114,11 +119,12 @@ public class VehicleMorePackets extends Check { // Set the new set back location. if (allowSetSetBack && newTo == null) { data.vehicleSetBacks.setMidTermEntry(thisMove.from); - if (data.debug) { + if (debug) { debug(player, "Update vehicle morepackets set back: " + thisMove.from); } } - } else if (data.vehicleMorePacketsLastTime > time) { + } + else if (data.vehicleMorePacketsLastTime > time) { // Security check, maybe system time changed. data.vehicleMorePacketsLastTime = time; } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleSetBackTask.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleSetBackTask.java index 01a71bdc..007960ce 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleSetBackTask.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/vehicle/VehicleSetBackTask.java @@ -21,6 +21,8 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.moving.MovingData; import fr.neatmonster.nocheatplus.logging.StaticLog; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.entity.PassengerUtil; /** @@ -57,11 +59,12 @@ public class VehicleSetBackTask implements Runnable{ @Override public void run() { - final MovingData data = MovingData.getData(player); + final IPlayerData pData = DataManager.getPlayerData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); data.vehicleSetBackTaskId = -1; try{ NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(PassengerUtil.class).teleportWithPassengers( - vehicle, player, location, debug, passengers, true); + vehicle, player, location, debug, passengers, true, pData); } catch(Throwable t){ StaticLog.logSevere(t); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/AttackFrequency.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/AttackFrequency.java index 3b4ac69f..04257637 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/AttackFrequency.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/AttackFrequency.java @@ -20,6 +20,7 @@ import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.TickTask; public class AttackFrequency extends Check { @@ -28,7 +29,8 @@ public class AttackFrequency extends Check { super(CheckType.NET_ATTACKFREQUENCY); } - public boolean check(final Player player, final long time, final NetData data, final NetConfig cc) { + public boolean check(final Player player, final long time, + final NetData data, final NetConfig cc, final IPlayerData pData) { // Update frequency. data.attackFrequencySeconds.add(time, 1f); double maxVL = 0.0; @@ -84,7 +86,7 @@ public class AttackFrequency extends Check { if (maxVL > 0.0) { // Trigger a violation. final ViolationData vd = new ViolationData(this, player, maxVL, 1.0, cc.attackFrequencyActions); - if (data.debug || vd.needsParameters()) { + if (pData.isDebugActive(type) || vd.needsParameters()) { vd.setParameter(ParameterName.PACKETS, Integer.toString((int) sum)); vd.setParameter(ParameterName.LIMIT, Integer.toString((int) maxLimit)); vd.setParameter(ParameterName.TAGS, tags); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/FlyingFrequency.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/FlyingFrequency.java index a7c8925e..57483e49 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/FlyingFrequency.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/FlyingFrequency.java @@ -19,8 +19,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying; -import fr.neatmonster.nocheatplus.players.PlayerData; -import fr.neatmonster.nocheatplus.utilities.CheckUtils; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * Check frequency of (pos/look/) flying packets, disregarding packet content. @@ -48,11 +47,10 @@ public class FlyingFrequency extends Check { * @return */ public boolean check(final Player player, final DataPacketFlying packetData, final long time, - final NetData data, final NetConfig cc, final PlayerData pData) { + final NetData data, final NetConfig cc, final IPlayerData pData) { data.flyingFrequencyAll.add(time, 1f); final float allScore = data.flyingFrequencyAll.score(1f); - if (allScore / cc.flyingFrequencySeconds > cc.flyingFrequencyPPS - && !CheckUtils.hasBypass(CheckType.NET_FLYINGFREQUENCY, player, pData) + if (allScore / cc.flyingFrequencySeconds > cc.flyingFrequencyPPS && executeActions(player, allScore / cc.flyingFrequencySeconds - cc.flyingFrequencyPPS, 1.0 / cc.flyingFrequencySeconds, cc.flyingFrequencyActions).willCancel()) { return true; } else { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/FlyingQueueHandle.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/FlyingQueueHandle.java index 24e26d39..df12760a 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/FlyingQueueHandle.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/FlyingQueueHandle.java @@ -14,11 +14,9 @@ */ package fr.neatmonster.nocheatplus.checks.net; -import org.bukkit.entity.Player; - -import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying; import fr.neatmonster.nocheatplus.components.registry.event.IHandle; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * Convenience for providing several checks with a lazy-init handle for fetching @@ -32,7 +30,7 @@ import fr.neatmonster.nocheatplus.components.registry.event.IHandle; */ public class FlyingQueueHandle implements IHandle { - private final Player player; + private final IPlayerData pData; private DataPacketFlying[] queue; /** * Convenience flag for keeping track amongst multiple checks, which all get @@ -40,14 +38,15 @@ public class FlyingQueueHandle implements IHandle { */ private boolean currentLocationValid = true; - public FlyingQueueHandle(Player player) { - this.player = player; + public FlyingQueueHandle(IPlayerData pData) { + // TODO: PlayerData ? + this.pData = pData; } @Override public DataPacketFlying[] getHandle() { if (queue == null) { - queue = ((NetData) CheckType.NET.getDataFactory().getData(player)).copyFlyingQueue(); + queue = pData.getGenericInstance(NetData.class).copyFlyingQueue(); } return queue; } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/KeepAliveFrequency.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/KeepAliveFrequency.java index 9fa9f777..fe520b32 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/KeepAliveFrequency.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/KeepAliveFrequency.java @@ -18,8 +18,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.players.PlayerData; -import fr.neatmonster.nocheatplus.utilities.CheckUtils; +import fr.neatmonster.nocheatplus.players.IPlayerData; public class KeepAliveFrequency extends Check { @@ -36,10 +35,10 @@ public class KeepAliveFrequency extends Check { * @return If to cancel. */ public boolean check(final Player player, final long time, final NetData data, final NetConfig cc, - final PlayerData pData) { + final IPlayerData pData) { data.keepAliveFreq.add(time, 1f); final float first = data.keepAliveFreq.bucketScore(0); - if (first > 1f && !CheckUtils.hasBypass(CheckType.NET_KEEPALIVEFREQUENCY, player, pData)) { + if (first > 1f) { // Trigger a violation. final double vl = Math.max(first - 1f, data.keepAliveFreq.score(1f) - data.keepAliveFreq.numberOfBuckets()); if (executeActions(player, vl, 1.0, cc.keepAliveFrequencyActions).willCancel()) { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetConfig.java index a3256470..ee769c59 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetConfig.java @@ -17,12 +17,15 @@ package fr.neatmonster.nocheatplus.checks.net; import fr.neatmonster.nocheatplus.actions.ActionList; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.access.ACheckConfig; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; import fr.neatmonster.nocheatplus.compat.versions.ServerVersion; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigFile; import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** * Configuration for the net checks (fast version, sparse). @@ -47,7 +50,6 @@ public class NetConfig extends ACheckConfig { // Instance ///////////// - public final boolean attackFrequencyActive; public final float attackFrequencyLimitSecondsHalf; public final float attackFrequencyLimitSecondsOne; public final float attackFrequencyLimitSecondsTwo; @@ -55,7 +57,6 @@ public class NetConfig extends ACheckConfig { public final float attackFrequencyLimitSecondsEight; public final ActionList attackFrequencyActions; - public final boolean flyingFrequencyActive; public final int flyingFrequencySeconds; public final double flyingFrequencyPPS; public final ActionList flyingFrequencyActions; @@ -63,27 +64,24 @@ public class NetConfig extends ACheckConfig { public final int flyingFrequencyRedundantSeconds; public final ActionList flyingFrequencyRedundantActions; - public final boolean keepAliveFrequencyActive; public final ActionList keepAliveFrequencyActions; - public final boolean packetFrequencyActive; public final float packetFrequencyPacketsPerSecond; public final int packetFrequencySeconds; public final ActionList packetFrequencyActions; - public final boolean soundDistanceActive; /** Maximum distance for lightning effects (squared). */ public final double soundDistanceSq; public final boolean supersededFlyingCancelWaiting; - public NetConfig(final ConfigFile config) { + public NetConfig(final IWorldData worldData) { // TODO: These permissions should have default policies. - super(config, ConfPaths.NET); + super(worldData); + final ConfigFile config = worldData.getRawConfiguration(); final ConfigFile globalConfig = ConfigManager.getConfigFile(); - attackFrequencyActive = config.getBoolean(ConfPaths.NET_ATTACKFREQUENCY_ACTIVE); attackFrequencyLimitSecondsHalf = config.getInt(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_HALF); attackFrequencyLimitSecondsOne = config.getInt(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_ONE); attackFrequencyLimitSecondsTwo = config.getInt(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_TWO); @@ -91,7 +89,6 @@ public class NetConfig extends ACheckConfig { attackFrequencyLimitSecondsEight = config.getInt(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_EIGHT); attackFrequencyActions = config.getOptimizedActionList(ConfPaths.NET_ATTACKFREQUENCY_ACTIONS, Permissions.NET_ATTACKFREQUENCY); - flyingFrequencyActive = config.getBoolean(ConfPaths.NET_FLYINGFREQUENCY_ACTIVE); flyingFrequencySeconds = Math.max(1, globalConfig.getInt(ConfPaths.NET_FLYINGFREQUENCY_SECONDS)); flyingFrequencyPPS = Math.max(1.0, globalConfig.getDouble(ConfPaths.NET_FLYINGFREQUENCY_PACKETSPERSECOND)); flyingFrequencyActions = config.getOptimizedActionList(ConfPaths.NET_FLYINGFREQUENCY_ACTIONS, Permissions.NET_FLYINGFREQUENCY); @@ -100,15 +97,17 @@ public class NetConfig extends ACheckConfig { // Same permission for "silent". flyingFrequencyRedundantActions = config.getOptimizedActionList(ConfPaths.NET_FLYINGFREQUENCY_REDUNDANT_ACTIONS, Permissions.NET_FLYINGFREQUENCY); - keepAliveFrequencyActive = config.getBoolean(ConfPaths.NET_KEEPALIVEFREQUENCY_ACTIVE); keepAliveFrequencyActions = config.getOptimizedActionList(ConfPaths.NET_KEEPALIVEFREQUENCY_ACTIONS, Permissions.NET_KEEPALIVEFREQUENCY); - packetFrequencyActive = config.getAlmostBoolean(ConfPaths.NET_PACKETFREQUENCY_ACTIVE, ServerVersion.compareMinecraftVersion("1.9") < 0, false); + if (ServerVersion.compareMinecraftVersion("1.9") >= 0) { + // TODO: Disable packet frequency or activate 'pessimistically'. + worldData.overrideCheckActivation(CheckType.NET_PACKETFREQUENCY, + AlmostBoolean.NO, OverrideType.PERMANENT, true); + } packetFrequencyPacketsPerSecond = config.getInt(ConfPaths.NET_PACKETFREQUENCY_PPS); packetFrequencySeconds = config.getInt(ConfPaths.NET_PACKETFREQUENCY_SECONDS); packetFrequencyActions = config.getOptimizedActionList(ConfPaths.NET_PACKETFREQUENCY_ACTIONS, Permissions.NET_PACKETFREQUENCY); - soundDistanceActive = config.getBoolean(ConfPaths.NET_SOUNDDISTANCE_ACTIVE); double dist = config.getDouble(ConfPaths.NET_SOUNDDISTANCE_MAXDISTANCE); soundDistanceSq = dist * dist; @@ -116,22 +115,4 @@ public class NetConfig extends ACheckConfig { } - @Override - public boolean isEnabled(final CheckType checkType) { - switch(checkType) { - case NET_ATTACKFREQUENCY: - return attackFrequencyActive; - case NET_FLYINGFREQUENCY: - return flyingFrequencyActive; - case NET_PACKETFREQUENCY: - return packetFrequencyActive; - case NET_SOUNDDISTANCE: - return soundDistanceActive; - case NET_KEEPALIVEFREQUENCY: - return keepAliveFrequencyActive; - default: - return true; - } - } - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetConfigCache.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetConfigCache.java deleted file mode 100644 index 27dcc3a9..00000000 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetConfigCache.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package fr.neatmonster.nocheatplus.checks.net; - -import org.bukkit.entity.Player; - -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.WorldConfigCache; - -/** - * Copy-on-write per-world configuration cache. - * @author asofold - * - */ -public class NetConfigCache extends WorldConfigCache implements CheckConfigFactory { - - public NetConfigCache() { - super(true); - } - - @Override - protected NetConfig newConfig(String key, ConfigFile configFile) { - return new NetConfig(configFile); - } - - @Override - public NetConfig getConfig(final Player player) { - return getConfig(player.getWorld()); - } - - @Override - public void removeAllConfigs() { - clearAllConfigs(); - } - -} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetData.java index 28c6d13f..d3b0605a 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetData.java @@ -92,7 +92,6 @@ public class NetData extends ACheckData { public final ActionFrequency packetFrequency; public NetData(final NetConfig config) { - super(config); flyingFrequencyAll = new ActionFrequency(config.flyingFrequencySeconds, 1000L); flyingFrequencyRedundantFreq = new ActionFrequency(config.flyingFrequencyRedundantSeconds, 1000L); if (config.packetFrequencySeconds <= 2) { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetDataFactory.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetDataFactory.java deleted file mode 100644 index 52be6ca1..00000000 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetDataFactory.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package fr.neatmonster.nocheatplus.checks.net; - -import java.util.Iterator; -import java.util.UUID; -import java.util.Map.Entry; - -import org.bukkit.entity.Player; - -import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; -import fr.neatmonster.nocheatplus.components.data.ICanHandleTimeRunningBackwards; -import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW; - -/** - * Factory for NetData. - * @author asofold - * - */ -public class NetDataFactory implements CheckDataFactory, ICanHandleTimeRunningBackwards { - - private final HashMapLOW dataMap = new HashMapLOW(35); - - @Override - public void removeAllData() { - dataMap.clear(); - } - - @Override - public NetData getData(Player player) { - NetData data = dataMap.get(player.getName()); - if (data != null) { - return data; - } else { - data = new NetData((NetConfig) CheckType.NET.getConfigFactory().getConfig(player)); - dataMap.put(player.getName(), data); - return data; - } - } - - @Override - public ICheckData getDataIfPresent(UUID playerId, String playerName) { - return dataMap.get(playerName); - } - - @Override - public NetData removeData(String playerName) { - return dataMap.remove(playerName); - } - - @Override - public void handleTimeRanBackwards() { - final Iterator> it = dataMap.iterator(); - while (it.hasNext()) { - final Entry entry = it.next(); - entry.getValue().handleSystemTimeRanBackwards(); - } - } - -} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetStatic.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetStatic.java index 3df81c4b..f3a5de93 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetStatic.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/net/NetStatic.java @@ -16,10 +16,6 @@ package fr.neatmonster.nocheatplus.checks.net; import java.util.List; -import org.bukkit.World; -import org.bukkit.entity.Player; - -import fr.neatmonster.nocheatplus.checks.chat.ChatData; import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; @@ -167,23 +163,4 @@ public class NetStatic { return Math.max(0.0, violation); } - /** - * Convenience: Check stored world names in case the world is null. - * - * NOTE: - * @param player - * @param configCache - * @param dataFactory - * @return - */ - public static NetConfig getWorldConfig(Player player, NetConfigCache configCache, NetDataFactory dataFactory) { - World world = null; - try { - world = player.getWorld(); - } - catch (UnsupportedOperationException e) {} - // TODO: Abusing ChatData for tracking world names. Should be in PlayerData or some generic data. - return configCache.getConfig(world == null ? ChatData.getData(player).currentWorldName : world.getName()); - } - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/ModUtil.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/ModUtil.java index 43b7fadb..49d7e5b7 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/ModUtil.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/ModUtil.java @@ -27,7 +27,7 @@ import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigFile; import fr.neatmonster.nocheatplus.config.ConfigManager; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * Utilities for dealing with client mods. This is likely to by just a refactoring stage. @@ -63,7 +63,7 @@ public class ModUtil { final boolean allowAll = config.getBoolean(ConfPaths.PROTECT_CLIENTS_MOTD_ALLOWALL); String message = ""; - final PlayerData data = DataManager.getPlayerData(player); + final IPlayerData data = DataManager.getPlayerData(player); for (int i = 0; i < motdS.length; i++){ message = motdS[i].onPlayerJoin(message, player, data, allowAll); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/CJBMOTD.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/CJBMOTD.java index 1689588c..fd08ed18 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/CJBMOTD.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/CJBMOTD.java @@ -17,12 +17,12 @@ package fr.neatmonster.nocheatplus.clients.motd; import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; public class CJBMOTD extends ClientMOTD { @Override - public String onPlayerJoin(final String message, final Player player, final PlayerData data, + public String onPlayerJoin(final String message, final Player player, final IPlayerData data, final boolean allowAll) { if (allowAll){ diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ClientMOTD.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ClientMOTD.java index 450b2512..cb8f62e7 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ClientMOTD.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ClientMOTD.java @@ -16,7 +16,7 @@ package fr.neatmonster.nocheatplus.clients.motd; import org.bukkit.entity.Player; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * Setup for all "motd" sending for enabling/disabling client mod features. @@ -32,6 +32,6 @@ public abstract class ClientMOTD { * @param allowAll * @return The message to send / process further. */ - public abstract String onPlayerJoin(String message, Player player, PlayerData data, + public abstract String onPlayerJoin(String message, Player player, IPlayerData data, boolean allowAll); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/JourneyMapMOTD.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/JourneyMapMOTD.java index 7002bc3e..eca15c49 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/JourneyMapMOTD.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/JourneyMapMOTD.java @@ -17,7 +17,7 @@ package fr.neatmonster.nocheatplus.clients.motd; import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * JourneyMap + VoxelMap mod. @@ -27,7 +27,7 @@ import fr.neatmonster.nocheatplus.players.PlayerData; public class JourneyMapMOTD extends ClientMOTD { @Override - public String onPlayerJoin(final String message, final Player player, final PlayerData data, final boolean allowAll) { + public String onPlayerJoin(final String message, final Player player, final IPlayerData data, final boolean allowAll) { if (allowAll) { return message; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/MCAutoMapMOTD.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/MCAutoMapMOTD.java index 7684c1c5..af10392a 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/MCAutoMapMOTD.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/MCAutoMapMOTD.java @@ -17,12 +17,12 @@ package fr.neatmonster.nocheatplus.clients.motd; import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; public class MCAutoMapMOTD extends ClientMOTD { @Override - public String onPlayerJoin(final String message, final Player player, final PlayerData data, + public String onPlayerJoin(final String message, final Player player, final IPlayerData data, final boolean allowAll) { if (allowAll){ diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ReiMOTD.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ReiMOTD.java index 1c006aed..6e8a2351 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ReiMOTD.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ReiMOTD.java @@ -17,7 +17,7 @@ package fr.neatmonster.nocheatplus.clients.motd; import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * Rei's Minimap v3.3_04 @@ -40,7 +40,7 @@ import fr.neatmonster.nocheatplus.players.PlayerData; public class ReiMOTD extends ClientMOTD { @Override - public String onPlayerJoin(final String message, final Player player, final PlayerData data, + public String onPlayerJoin(final String message, final Player player, final IPlayerData data, final boolean allowAll) { String rei = ""; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/SmartMovingMOTD.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/SmartMovingMOTD.java index 6a2770b1..13db993c 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/SmartMovingMOTD.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/SmartMovingMOTD.java @@ -17,12 +17,12 @@ package fr.neatmonster.nocheatplus.clients.motd; import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; public class SmartMovingMOTD extends ClientMOTD { @Override - public String onPlayerJoin(final String message, final Player player, final PlayerData data, + public String onPlayerJoin(final String message, final Player player, final IPlayerData data, final boolean allowAll) { if (allowAll){ diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ZombeMOTD.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ZombeMOTD.java index 6c95a1c7..167a3f22 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ZombeMOTD.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/clients/motd/ZombeMOTD.java @@ -17,12 +17,12 @@ package fr.neatmonster.nocheatplus.clients.motd; import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.permissions.Permissions; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; public class ZombeMOTD extends ClientMOTD { @Override - public String onPlayerJoin(final String message, final Player player, final PlayerData data, + public String onPlayerJoin(final String message, final Player player, final IPlayerData data, final boolean allowAll) { String zombe = ""; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/ReloadCommand.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/ReloadCommand.java index 92371eb4..3abb92fd 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/ReloadCommand.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/ReloadCommand.java @@ -34,6 +34,7 @@ import fr.neatmonster.nocheatplus.logging.Streams; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.players.DataManager; import fr.neatmonster.nocheatplus.utilities.StringUtil; +import fr.neatmonster.nocheatplus.worlds.WorldDataManager; public class ReloadCommand extends BaseCommand { @@ -69,7 +70,9 @@ public class ReloadCommand extends BaseCommand { // Do the actual reload. ConfigManager.cleanup(); - ConfigManager.init(access); + // (Magic/TODO) + ConfigManager.init(access, + (WorldDataManager) NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager()); if (logManager instanceof INotifyReload) { // TODO: This is a band-aid. ((INotifyReload) logManager).onReload(); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/RemovePlayerCommand.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/RemovePlayerCommand.java index 0d650e46..48b9d761 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/RemovePlayerCommand.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/RemovePlayerCommand.java @@ -38,6 +38,7 @@ public class RemovePlayerCommand extends BaseCommand { }); } + @SuppressWarnings("deprecation") @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/debug/DebugPlayerCommand.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/debug/DebugPlayerCommand.java index 2b580e1a..67644b3f 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/debug/DebugPlayerCommand.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/command/admin/debug/DebugPlayerCommand.java @@ -14,7 +14,12 @@ */ package fr.neatmonster.nocheatplus.command.admin.debug; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -22,15 +27,53 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.command.BaseCommand; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; +import fr.neatmonster.nocheatplus.utilities.IdUtil; +import fr.neatmonster.nocheatplus.utilities.StringUtil; public class DebugPlayerCommand extends BaseCommand { + static class DebugEntry { + public AlmostBoolean active = AlmostBoolean.YES; + public final Set checkTypes = new LinkedHashSet(); + + /** + * AlmostBoolean[:CheckType1[:CheckType2[...]]] + * @param input + * @return + */ + public static DebugEntry parseEntry(String input) { + String[] split = input.split(":"); + DebugEntry entry = new DebugEntry(); + entry.active = AlmostBoolean.match(split[0]); + if (entry.active == null) { + return null; + } + for (int i = 1; i < split.length; i++) { + try { + CheckType checkType = CheckType.valueOf(split[i].toUpperCase().replace('.', '_')); + if (checkType == null) { + // TODO: Possible !? + return null; + } + entry.checkTypes.add(checkType); + } + catch (Exception e){ + return null; + } + } + return entry; + } + + } + public DebugPlayerCommand(JavaPlugin plugin) { super(plugin, "player", null); + usage = "/ncp debug player ... online player name or UUID, ?(yes|no|default)[:CheckType1[:CheckType2...]] to set the default behavior - mix with player names/ids."; } @Override @@ -40,33 +83,68 @@ public class DebugPlayerCommand extends BaseCommand { @Override public boolean onCommand(CommandSender sender, Command command, String alias, String[] args) { - - // TODO: This is a minimal version just to turn it on (!). Further: check types, -off. + // TODO: Wild cards (all players)? + // TODO: (Allow to specify OverrideType ?) + + // Note that MAYBE means to reset here, it's not the same as direct PlayerData API access. + DebugEntry entry = new DebugEntry(); for (int i = 2; i < args.length; i++) { - final String name = args[i]; - final Player player = DataManager.getPlayer(name); + String input = args[i]; + if (input.startsWith("?")) { + entry = DebugEntry.parseEntry(input.substring(1)); + if (entry == null) { + sender.sendMessage("Bad setup: " + input); + // Can't continue. + return true; + } + else { + // Only update the entry. + continue; + } + } + + final String name = input; + final Player player; + if (IdUtil.isValidMinecraftUserName(name)) { + player = DataManager.getPlayer(name); + } + else { + UUID id = IdUtil.UUIDFromStringSafe(input); + if (id == null) { + sender.sendMessage("Bad name or UUID: " + input); + continue; + } + else { + player = DataManager.getPlayer(id); + } + } if (player == null) { sender.sendMessage("Not online: " + name); - } else { - setDebugAll(player); - sender.sendMessage("Set all checks to debug for player: " + player.getName()); + continue; } + + // Execute for online player. + final Collection checkTypes; + if (entry.checkTypes.isEmpty()) { + // CheckType.ALL + checkTypes = Arrays.asList(CheckType.ALL); + } + else { + checkTypes = entry.checkTypes; + } + final IPlayerData data = DataManager.getPlayerData(player); + for (final CheckType checkType : checkTypes) { + if (entry.active == AlmostBoolean.MAYBE) { + data.resetDebug(checkType); + } + else { + data.overrideDebug(checkType, entry.active, + OverrideType.CUSTOM, true); + } + } + sender.sendMessage("Set debug = " + entry.active + " for player " + player.getName() + " for checks: " + StringUtil.join(checkTypes, ",")); } return true; } - private void setDebugAll(final Player player) { - for (final CheckType type : CheckType.values()) { - CheckDataFactory factory = type.getDataFactory(); - if (factory != null) { - ICheckData data = factory.getData(player); - if (data != null) { - data.setDebug(true); - } - } - } - } - - - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/NoCheatPlusAPI.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/NoCheatPlusAPI.java index a78c6ae3..b9ccc204 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/NoCheatPlusAPI.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/NoCheatPlusAPI.java @@ -25,6 +25,8 @@ import fr.neatmonster.nocheatplus.components.registry.GenericInstanceRegistry; import fr.neatmonster.nocheatplus.event.mini.EventRegistryBukkit; import fr.neatmonster.nocheatplus.logging.LogManager; import fr.neatmonster.nocheatplus.permissions.PermissionRegistry; +import fr.neatmonster.nocheatplus.players.IPlayerDataManager; +import fr.neatmonster.nocheatplus.worlds.IWorldDataManager; @@ -196,6 +198,22 @@ public interface NoCheatPlusAPI extends ComponentRegistry, ComponentRegi * * @return */ + // TODO: Remove in favor of per world permission registries (!). public PermissionRegistry getPermissionRegistry(); + /** + * Get the WorldDataManager, which stores per-world data and configuration. + * + * @return + */ + public IWorldDataManager getWorldDataManager(); + + /** + * Get the PlayerDataManager, which stores per player data and + * configuration. + * + * @return + */ + public IPlayerDataManager getPlayerDataManager(); + } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/concurrent/IPrimaryThreadContextTester.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/concurrent/IPrimaryThreadContextTester.java new file mode 100644 index 00000000..14b074a3 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/concurrent/IPrimaryThreadContextTester.java @@ -0,0 +1,35 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.concurrent; + +/** + * Simply an interface to detach from the exact thread / method of testing. + * + * @author asofold + * + */ +public interface IPrimaryThreadContextTester { + + /** + * Test if this is the primary thread context. In case of Bukkit, note that + * there might be asynchronous tasks, with access methods that have 'another + * primary thread' than the primary server thread, i.e. not all + * implementations are interchangeable. + * + * @return + */ + public boolean isPrimaryThread(); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/AbstractValueWithOverride.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/AbstractValueWithOverride.java new file mode 100644 index 00000000..1b777860 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/AbstractValueWithOverride.java @@ -0,0 +1,65 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.config.value; + +/** + * Store a value (override this class for actual value), store an OverrideType, + * provide some auxiliary methods for checking. Not intended as an API feature + * to pass to the outside. + *
    + * Sub classes should implement a 'boolean setValue(value, OverrideType)' method + * checking for allowsOverrideBy and returning true iff the value has been + * overridden, and a getValue method. A reset method may be needed for certain + * contexts, to hard-reset to an underlying parent configuration - behavior in + * case of OverrideType.PERMANENT needs to be specified. + * + * @author asofold + * + */ +public class AbstractValueWithOverride { + + protected OverrideType overrideType = OverrideType.INITIAL; + + /** + * Retrieve the currently set OverrideType instance. + * + * @return + */ + public OverrideType getOverrideType() { + return overrideType; + } + + /** + * Test if this value would allow an override by the given instance - would, + * provided the type is appropriate at all. + * + * @param other + */ + public boolean wouldAllowOverrideBy(AbstractValueWithOverride other) { + return allowsOverrideBy(other.overrideType); + } + + /** + * Test if this instance allows an override for the given overrideSource. + * + * @param overrideType + * @return + */ + public boolean allowsOverrideBy(OverrideType overrideType) { + return this.overrideType.allowsOverrideBy(overrideType); + } + + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/AlmostBooleanWithOverride.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/AlmostBooleanWithOverride.java new file mode 100644 index 00000000..663f103d --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/AlmostBooleanWithOverride.java @@ -0,0 +1,92 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.config.value; + +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; + +public class AlmostBooleanWithOverride extends ValueWithOverride { + + public AlmostBooleanWithOverride() { + super(AlmostBoolean.MAYBE); + } + + public AlmostBooleanWithOverride(AlmostBoolean value, + OverrideType overrideType) { + super(value, overrideType); + } + + public AlmostBooleanWithOverride(AlmostBoolean value) { + super(value); + } + + public boolean setValue(boolean value, OverrideType overrideType) { + return setValue(AlmostBoolean.match(value), overrideType); + } + + /** + * Convenience: null is translated to MAYBE (default). See: + * {@link #setValue(boolean, OverrideType)} + * + * @param value + * @param overrideType + * @return + */ + public boolean setValue(Boolean value, OverrideType overrideType) { + return setValue(value == null ? AlmostBoolean.MAYBE : AlmostBoolean.match(value), + overrideType); + } + + /** + * Convenience method. See: {@link #setValue(boolean, OverrideType)} + * + * @param other + * @return + */ + public boolean setValue(FlagWithOverride other) { + return this.setValue(other.getValue(), other.getOverrideType()); + } + + /** + * Convenience method. See: {@link #resetValue(Object, OverrideType)} + * + * @param value + * @param overrideType + */ + public void resetValue(boolean value, OverrideType overrideType) { + resetValue(AlmostBoolean.match(value), overrideType); + } + + /** + * Convenience: null is translated to MAYBE (default). See: + * {@link #resetValue(Object, OverrideType)} + * + * @param value + * @param overrideType + */ + public void resetValue(Boolean value, OverrideType overrideType) { + resetValue(value == null ? AlmostBoolean.MAYBE : AlmostBoolean.match(value), + overrideType); + } + + /** + * Convenience method. See: {@link #resetValue(Object, OverrideType)} + * + * @param other + */ + public void resetValue(FlagWithOverride other) { + resetValue(other.getValue(), other.getOverrideType()); + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/FlagWithOverride.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/FlagWithOverride.java new file mode 100644 index 00000000..241315ec --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/FlagWithOverride.java @@ -0,0 +1,123 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.config.value; + +public class FlagWithOverride extends AbstractValueWithOverride { + + private boolean value; + + /** + * Initialize to null / INITIAL. + */ + public FlagWithOverride() { + this(false); + } + + /** + * Initialize to the given value / INITIAL. + * + * @param value + */ + public FlagWithOverride(boolean value) { + this(value, OverrideType.INITIAL); + } + + /** + * Custom initialization. + * + * @param value + * @param overrideType + */ + public FlagWithOverride(boolean value, OverrideType overrideType) { + this.value = value; + this.overrideType = overrideType; + } + + public boolean getValue() { + return value; + } + + /** + * Override, if the given overrideType satisfies the conditions for + * overriding. + * + * @param value + * @param overrideType + * The override source/reason/priority. + * @return True, iff the internally stored value has been updated. + */ + public boolean setValue(boolean value, OverrideType overrideType) { + if (allowsOverrideBy(overrideType)) { + this.value = value; + this.overrideType = overrideType; + return true; + } + else { + return false; + } + } + + /** + * Convenience method. See: {@link #setValue(boolean, OverrideType)} + * @param other + * @return + */ + public boolean setValue(FlagWithOverride other) { + return setValue(other.getValue(), other.getOverrideType()); + } + + /** + * Convenience method. See: {@link #setValue(boolean, OverrideType)} + * @param other + * @return + */ + public boolean setValue(ValueWithOverride other) { + return setValue(other.getValue(), other.getOverrideType()); + } + + /** + * Allow resetting if the given overrideType is PERMANENT or allows + * overriding. + * + * @param value + * @param overrideType + */ + public void resetValue(boolean value, OverrideType overrideType) { + if (allowsOverrideBy(overrideType) + || OverrideType.PERMANENT.allowsOverrideBy(overrideType)) { + this.value = value; + this.overrideType = overrideType; + } + } + + /** + * Convenience method. See: {@link #resetValue(boolean, OverrideType)} + * @param other + * @return + */ + public void resetValue(FlagWithOverride other) { + resetValue(other.getValue(), other.getOverrideType()); + } + + /** + * Convenience method. See: {@link #resetValue(boolean, OverrideType)} + * @param other + * @return + */ + public void resetValue(ValueWithOverride other) { + resetValue(other.getValue(), other.getOverrideType()); + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/OverrideType.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/OverrideType.java new file mode 100644 index 00000000..a8a0287e --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/OverrideType.java @@ -0,0 +1,59 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.config.value; + +public enum OverrideType { + /** + * Initial value after object creation. Gets overridden by everything. + */ + INITIAL(-100), + /** + * Explicitly set, but clearly meant temporary (gets overridden by all + * others, except initial). + */ + VOLATILE(0), + /** Set from a default configuration (inherited). */ + DEFAULT(0), + /** + * Set from a specific configuration (not inherited). SPECIFIC has the same + * priority as DEFAULT, because both should be mutually exclusive, assuming + * specific values to get applied after the default ones, always, if in + * doubt. This value exists for distinction, it may not be accurate, in case + * an underlying configuration contains values of varying origin - typically + * this would lead to SPECIFIC, as opposed to a plain reference or copy of + * the default configuration. + */ + SPECIFIC(0), + /** Explicitly set, to not get overridden for inherited properties. */ + CUSTOM(50), + /** Last resort, e.g. on permanent incompatibility. */ + PERMANENT(100) + ; + + private int priority; + + private OverrideType(int priority) { + this.priority = priority; + } + + public int getPriority() { + return this.priority; + } + + public boolean allowsOverrideBy(OverrideType overrideType) { + return overrideType.getPriority() >= this.priority; + } + +} \ No newline at end of file diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/ValueWithOverride.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/ValueWithOverride.java new file mode 100644 index 00000000..8649a044 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/config/value/ValueWithOverride.java @@ -0,0 +1,111 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.config.value; + +/** + * Generic value with override functionality. + * + * @author asofold + * + * @param + */ +public class ValueWithOverride extends AbstractValueWithOverride { + + private V value; + + /** + * Initialize to null / INITIAL. + */ + public ValueWithOverride() { + this(null); + } + + /** + * Initialize to the given value / INITIAL. + * + * @param value + */ + public ValueWithOverride(V value) { + this(value, OverrideType.INITIAL); + } + + /** + * Custom initialization. + * + * @param value + * @param overrideType + */ + public ValueWithOverride(V value, OverrideType overrideType) { + this.value = value; + this.overrideType = overrideType; + } + + public V getValue() { + return value; + } + + /** + * Override, if the given overrideType satisfies the conditions for + * overriding. + * + * @param value + * @param overrideType + * The override source/reason/priority. + * @return True, iff the internally stored value has been updated. + */ + public boolean setValue(V value, OverrideType overrideType) { + if (allowsOverrideBy(overrideType)) { + this.value = value; + this.overrideType = overrideType; + return true; + } + else { + return false; + } + } + + /** + * Convenience method. See: {@link #setValue(boolean, OverrideType)} + * @param other + * @return + */ + public boolean setValue(ValueWithOverride other) { + return this.setValue(other.getValue(), other.getOverrideType()); + } + + /** + * Allow resetting if the given overrideType is PERMANENT or allows + * overriding. + * + * @param value + * @param overrideType + */ + public void resetValue(V value, OverrideType overrideType) { + if (allowsOverrideBy(overrideType) + || OverrideType.PERMANENT.allowsOverrideBy(overrideType)) { + this.value = value; + this.overrideType = overrideType; + } + } + + /** + * Convenience method. See: {@link #resetValue(Object, OverrideType)} + * @param other + */ + public void resetValue(ValueWithOverride other) { + resetValue(other.getValue(), other.getOverrideType()); + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/BaseCheckNode.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/BaseCheckNode.java new file mode 100644 index 00000000..a83d338a --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/BaseCheckNode.java @@ -0,0 +1,133 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.data.checktype; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.AlmostBooleanWithOverride; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; +import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree.CheckTypeTreeNode; +import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree.CheckTypeTreeNodeFactory; +import fr.neatmonster.nocheatplus.config.ConfigFile; + +/** + * Auxiliary base class to allow standard configuration flags (AlmostBoolean) + * with boolean resolution and overriding functionality. + * + * @author asofold + * + * @param + */ +public abstract class BaseCheckNode> extends CheckTypeTreeNode { + + // TODO: Not optimal - references that are from the container should be fetched from there. + protected OverrideType configOverrideType = OverrideType.DEFAULT; + + protected static interface IConfigFlagAccess { + // Might move somewhere generic. + + public AlmostBooleanWithOverride getConfigState(N node); + public boolean getState(N node); + public void setState(N node, boolean state); + public String getConfigPath(N node); + + } + + public BaseCheckNode(CheckType checkType, N parent, + CheckTypeTreeNodeFactory factory) { + super(checkType, parent, factory); + } + + // TODO: GENERIC (ConfigFlagAccess/Fetch based) Override / update / reset. + + protected void configFlagOverride(final ConfigFile rawConfiguration, + final AlmostBoolean active, final OverrideType overrideType, + final boolean overrideChildren, final IConfigFlagAccess access) { + @SuppressWarnings("unchecked") + final boolean applicable = access.getConfigState((N) this).setValue(active, overrideType); + if (applicable) { + // The flag is updated here. + configFlagUpdate(rawConfiguration, false, access); + } + if (overrideChildren) { + // Always override children, as there can be arbitrary sequences of overrides. + for (final N child : getChildren()) { + child.configFlagOverride(rawConfiguration, active, overrideType, + true, access); + } + } + else if (applicable) { + // Updates child nodes recursively, provided they depend on their parent. + for (final N child : getChildren()) { + if (access.getConfigState(child).getValue() == AlmostBoolean.MAYBE) { + child.configFlagUpdate(rawConfiguration, false, access); + } + } + } + } + + protected void configFlagUpdate(final ConfigFile rawConfiguration, + final boolean forceUpdateChildren, final IConfigFlagAccess access) { + @SuppressWarnings("unchecked") + final N thisNode = (N) this; // TODO + final boolean previousActive = access.getState(thisNode); + final AlmostBooleanWithOverride configActivation = access.getConfigState(thisNode); + AlmostBoolean newActive = configActivation.getValue(); + if (newActive != AlmostBoolean.MAYBE) { + access.setState(thisNode, newActive.decide()); + } + else { + + // Only fetch from configuration, if override level allows so. + if (rawConfiguration != null && configActivation.allowsOverrideBy( + OverrideType.SPECIFIC)) { + final String configPath = access.getConfigPath(thisNode); + if (configPath != null) { + // TODO: Contract? Either config is null, or path must exist. + newActive = rawConfiguration.getAlmostBoolean(configPath, + AlmostBoolean.MAYBE); + configActivation.setValue(newActive, configOverrideType); + } + } + // If not set by configuration, fetch from parent. + if (newActive == AlmostBoolean.MAYBE) { + N parent = getParent(); + if (parent == null) { + access.setState(thisNode, true); + } + else { + // Assume top-down updating always. + access.setState(thisNode, access.getState(parent)); + } + } + else { + access.setState(thisNode, newActive.decide()); + } + } + // Update on changes, or if forced. + if (forceUpdateChildren || previousActive != access.getState(thisNode)) { + // Update children. + for (final N node : this.getChildren()) { + // Only update, if the state depends on the parent. + if (forceUpdateChildren + || access.getConfigState(node).getValue() == AlmostBoolean.MAYBE) { + node.configFlagUpdate(rawConfiguration, forceUpdateChildren, access); + } + } + } + + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/CheckNodeWithDebug.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/CheckNodeWithDebug.java new file mode 100644 index 00000000..32526f73 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/CheckNodeWithDebug.java @@ -0,0 +1,95 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.data.checktype; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.AlmostBooleanWithOverride; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; +import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree.CheckTypeTreeNodeFactory; +import fr.neatmonster.nocheatplus.config.ConfigFile; + +public abstract class CheckNodeWithDebug> extends BaseCheckNode implements IBaseCheckNode { + + /** + * Deja vu: java 10? + * + * @author asofold + * + * @param + */ + protected static class AccessDebug> implements IConfigFlagAccess { + + @Override + public AlmostBooleanWithOverride getConfigState(N node) { + return node.configDebug; + } + + @Override + public boolean getState(N node) { + return node.debug; + } + + @Override + public void setState(N node, boolean state) { + node.debug = state; + } + + @Override + public String getConfigPath(N node) { + return node.getCheckType().getConfigPathDebug(); + } + + }; + + @SuppressWarnings("rawtypes") + protected static final AccessDebug accessDebug = new AccessDebug(); + + /////////////// + // Instance + /////////////// + + public CheckNodeWithDebug(CheckType checkType, N parent, + CheckTypeTreeNodeFactory factory) { + super(checkType, parent, factory); + } + + protected final AlmostBooleanWithOverride configDebug = new AlmostBooleanWithOverride(); + protected boolean debug = false; + + @Override + public boolean isDebugActive() { + return debug; + } + + // TODO: Visibility of methods -> public but not expose via interface or protected. + + // TODO: @Override + @SuppressWarnings("unchecked") + protected void overrideDebug(final ConfigFile rawConfiguration, + final AlmostBoolean active, final OverrideType overrideType, + final boolean overrideChildren) { + configFlagOverride(rawConfiguration, active, overrideType, overrideChildren, accessDebug); + } + + // TODO: @Override + @SuppressWarnings("unchecked") + protected void updateDebug(final ConfigFile rawConfiguration, final boolean forceUpdateChildren) { + configFlagUpdate(rawConfiguration, forceUpdateChildren, accessDebug); + } + + // TODO: resetDebug(...) + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IBaseCheckNode.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IBaseCheckNode.java new file mode 100644 index 00000000..298e7e2b --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IBaseCheckNode.java @@ -0,0 +1,31 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.data.checktype; + +/** + * Common functionality for per check nodes. + * + * @author asofold + * + */ +public interface IBaseCheckNode { + + /** + * + * @return + */ + public boolean isDebugActive(); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IBaseDataAccess.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IBaseDataAccess.java new file mode 100644 index 00000000..2bc76020 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IBaseDataAccess.java @@ -0,0 +1,29 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.data.checktype; + +import fr.neatmonster.nocheatplus.checks.CheckType; + +/** + * Command check type specific data interface. + * + * @author asofold + * + */ +public interface IBaseDataAccess { + + public boolean isDebugActive(CheckType checkType); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IConfigCheckNode.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IConfigCheckNode.java new file mode 100644 index 00000000..628a5fae --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IConfigCheckNode.java @@ -0,0 +1,29 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.data.checktype; + +/** + * Generic per check type node within an IConfigData instance. These are meant + * to be stored within context-specific data/configurations for most efficient + * access. + * + * @author asofold + * + */ +public interface IConfigCheckNode extends IBaseCheckNode { + + public boolean isCheckActive(); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IConfigDataAccess.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IConfigDataAccess.java new file mode 100644 index 00000000..7a8b91f1 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/data/checktype/IConfigDataAccess.java @@ -0,0 +1,102 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.data.checktype; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; +import fr.neatmonster.nocheatplus.config.ConfigFile; + +/** + * Data node representing an already processed state above a raw configuration. + * Contained are per check type nodes containing further information, at least + * activation and debug flags. Methods for overriding flags are also contained. + * This can be per-world basic configuration, but it might also be the common + * super interface for both worlds and players at some point. + *
    + * Subject to change. + * + * @author asofold + * + */ +public interface IConfigDataAccess extends IBaseDataAccess { + // TODO: Naming. + + /** + * Get the applicable raw configuration file. + * + * @return + */ + public ConfigFile getRawConfiguration(); + + /** + * Test if a check is activated by configuration (respecting overrides). + *
    + * Thread-safe. + *
    + * + * @param checkType + * @return + */ + public boolean isCheckActive(CheckType checkType); + + /** + * Override the activation of a check (/group, including all descendant + * checks). This does not change the underlying raw configuration, and may + * be reset with reloading the configuration, due to automatic overrides + * which get applied after reloading the raw configuration, independently of + * what is set in there - depends on the argument overrideType. + *
    + * TODO: With overrideType CUSTOM this is persistent over reloading the + * configuration. + *
    + *

    IWorldData

    In order to reliably override check activation for + * all stored WorldData instances, use + * {@link fr.neatmonster.nocheatplus.worlds.WorldDataManager#overrideCheckActivation(CheckType, AlmostBoolean, boolean)} + *
    + * Assume this to be registry functionality, thus primary-thread only. + *
    + * + * @param checkType + * @param active + * The desired activation state. MAYBE means to use the + * activation state of the super type. + * @param overrideType + * The priority/type for overriding. Only values with same or + * lower priority can be overridden. + * @param overrideChildren + * Explicitly attempt to override child nodes too, if set to + * true. Otherwise child nodes are just updated to the current + * state. + * @TODO Registration priorities and tags to relate to, for custom + * overrides. + */ + // TODO: IWorldData - move to IWorldData ? + public void overrideCheckActivation(CheckType checkType, AlmostBoolean active, + OverrideType overrideType, boolean overrideChildren); + + // TODO: resetCheckActivation -> reset to config value, except if set to PERMANENT. + + + /** + * Thread-safe. + * + * @param checkType + * @return + */ + public IConfigCheckNode getCheckNode(CheckType checkType); + + +} diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/components/registry/DefaultGenericInstanceRegistry.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/DefaultGenericInstanceRegistry.java similarity index 70% rename from NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/components/registry/DefaultGenericInstanceRegistry.java rename to NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/DefaultGenericInstanceRegistry.java index b52e2325..509591f7 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/components/registry/DefaultGenericInstanceRegistry.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/DefaultGenericInstanceRegistry.java @@ -14,8 +14,12 @@ */ package fr.neatmonster.nocheatplus.components.registry; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import fr.neatmonster.nocheatplus.components.registry.event.GenericInstanceHandle.ReferenceCountHandle; import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle; @@ -24,7 +28,7 @@ import fr.neatmonster.nocheatplus.components.registry.event.IUnregisterGenericIn import fr.neatmonster.nocheatplus.components.registry.exception.RegistrationLockedException; import fr.neatmonster.nocheatplus.logging.details.IGetStreamId; import fr.neatmonster.nocheatplus.logging.details.ILogString; -import fr.neatmonster.nocheatplus.utilities.ds.corw.LinkedHashMapCOW; +import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW; /** * Default/simple implementation. Handles are kept forever once fetched, for @@ -52,6 +56,7 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, // TODO: unique handles + use private final GenericInstanceRegistry registry; + private final Lock lock; private final IUnregisterGenericInstanceRegistryListener unregister; private final Class registeredFor; private T instance = null; @@ -63,19 +68,28 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, private final List> listeners = new LinkedList>(); public Registration(Class registeredFor, T instance, - GenericInstanceRegistry registry, IUnregisterGenericInstanceRegistryListener unregister) { + GenericInstanceRegistry registry, + IUnregisterGenericInstanceRegistryListener unregister, + Lock lock) { this.registry = registry; this.unregister = unregister; this.registeredFor = registeredFor; this.instance = instance; + this.lock = lock; + } + + private void setFlag(long flag) { + lock.lock(); + accessFlags |= flag; + lock.unlock(); } public void denyOverrideInstance() { - accessFlags |= DENY_OVERRIDE_INSTANCE; + setFlag(DENY_OVERRIDE_INSTANCE); } public void denyRemoveInstance() { - accessFlags |= DENY_REMOVE_INSTANCE; + setFlag(DENY_REMOVE_INSTANCE); } /** @@ -85,7 +99,9 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, * @return The previously registered instance. */ public T unregisterInstance() { + lock.lock(); if ((accessFlags & DENY_REMOVE_INSTANCE) != 0) { + lock.unlock(); throw new RegistrationLockedException(); } T oldInstance = this.instance; @@ -95,6 +111,7 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, ((IGenericInstanceRegistryListener) listener).onGenericInstanceRemove(registeredFor, oldInstance); } } + lock.unlock(); return oldInstance; } @@ -106,7 +123,9 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, * @return */ public T registerInstance(T instance) { + lock.lock(); if ((accessFlags & DENY_OVERRIDE_INSTANCE) != 0) { + lock.unlock(); throw new RegistrationLockedException(); } T oldInstance = this.instance; @@ -123,11 +142,25 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, } } } + lock.unlock(); return oldInstance; } public IGenericInstanceHandle getHandle() { - if (uniqueHandle != null && uniqueHandle.isDisabled()) { + lock.lock(); + if (uniqueHandle == null) { + updateUniqueHandle(); + } + IGenericInstanceHandle handle = uniqueHandle.getNewHandle(); + lock.unlock(); + return handle; + } + + /** + * Only call if uniqueHandle is null and under lock. + */ + private void updateUniqueHandle() { + if (uniqueHandle.isDisabled()) { unregisterListener(uniqueHandle); } if (uniqueHandle == null) { @@ -135,11 +168,11 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, this.listeners.add(uniqueHandle); uniqueHandle.getHandle(); // Keep the count up, so this never unregisters automatically. } - return uniqueHandle.getNewHandle(); } public void unregisterListener(IGenericInstanceRegistryListener listener) { - IGenericInstanceHandle disable = null; + lock.lock(); + IGenericInstanceHandle disable = null; if (listener == uniqueHandle) { disable = uniqueHandle; uniqueHandle = null; @@ -148,16 +181,25 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, if (disable != null) { disable.disableHandle(); } + lock.unlock(); } public T getInstance() { return (T) instance; } - public boolean canBeRemoved() { - return instance == null && uniqueHandle == null && listeners.isEmpty(); + /** + * Must be called under lock. + * + * @return + */ + private boolean canBeRemoved() { + return instance == null || uniqueHandle == null && listeners.isEmpty(); } + /** + * Call under lock only. + */ public void clear() { instance = null; if (uniqueHandle != null) { @@ -169,13 +211,9 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, } - /* - * TODO: Not sure about thread-safety here. Registration might later contain - * lots of objects and we might like to do some kind of opportunistic - * skipping of the copying, e.g. if no handles have been fetched yet, OR - * change implementation on the fly after 'activating' the registry. - */ - private final LinkedHashMapCOW, Registration> registrations = new LinkedHashMapCOW, Registration>(); + + private final Lock lock = new ReentrantLock(); + private final HashMapLOW, Registration> registrations = new HashMapLOW, Registration>(lock,30); private ILogString logger = null; @@ -194,18 +232,41 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, Registration registration = (Registration) registrations.get(registeredFor); if (registration == null && create) { // Create empty. - registration = new Registration(registeredFor, null, this, this); - this.registrations.put(registeredFor, registration); + return createEmptyRegistration(registeredFor); } + else { + return registration; + } + } + + @SuppressWarnings("unchecked") + private Registration createEmptyRegistration(Class registeredFor) { + lock.lock(); + Registration registration = (Registration) registrations.get(registeredFor); // Re-check. + if (registration == null) { + try { + // TODO: Consider individual locks / configuration for it. + registration = new Registration(registeredFor, null, this, this, lock); + this.registrations.put(registeredFor, registration); + } + catch (Throwable t) { + lock.unlock(); + throw new IllegalArgumentException(t); // Might document. + } + } + lock.unlock(); return registration; } @Override public void unregisterGenericInstanceRegistryListener(Class registeredFor, IGenericInstanceRegistryListener listener) { + lock.lock(); + // (Include getRegistration, as no object creation is involved.) Registration registration = getRegistration(registeredFor, false); if (registration != null) { registration.unregisterListener(listener); } + lock.lock(); } @SuppressWarnings("unchecked") @@ -216,18 +277,20 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, @Override public T registerGenericInstance(Class registerFor, TI instance) { - Registration registration = getRegistration(registerFor, true); + Registration registration = getRegistration(registerFor, true); // Locks / throws. T previouslyRegistered = registration.registerInstance(instance); - String msg = previouslyRegistered == null ? "Registered for " : "Registered (override) for "; - String registerForName = registerFor.getName(); - String instanceName = instance.getClass().getName(); - if (registerForName.equals(instanceName)) { - msg += "itself: " + instanceName; + if (logger != null) { + String msg = previouslyRegistered == null ? "Registered for " : "Registered (override) for "; + String registerForName = registerFor.getName(); + String instanceName = instance.getClass().getName(); + if (registerForName.equals(instanceName)) { + msg += "itself: " + instanceName; + } + else { + msg += registerForName + ": " + instanceName; + } + logRegistryEvent(msg); } - else { - msg += registerForName + ": " + instanceName; - } - logRegistryEvent(msg); return previouslyRegistered; } @@ -239,18 +302,22 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, @Override public T unregisterGenericInstance(Class registeredFor) { + lock.lock(); Registration registration = getRegistration(registeredFor, false); T registered = registration == null ? null : registration.unregisterInstance(); - if (registered != null) { - logRegistryEvent("Unregister, remove mapping for: " + registeredFor.getName()); - } - else { - logRegistryEvent("Unregister, no mapping present for: " + registeredFor.getName()); - } // Repeat getting for removal test. if (registrations.containsKey(registeredFor) && getRegistration(registeredFor, false).canBeRemoved()) { registrations.remove(registeredFor); } + lock.unlock(); + if (logger != null) { + if (registered != null) { + logRegistryEvent("Unregister, removed mapping for: " + registeredFor.getName()); + } + else { + logRegistryEvent("Unregister, no mapping present for: " + registeredFor.getName()); + } + } return registered; } @@ -261,11 +328,14 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, public void clear() { // TODO: consider fire unregister or add a removal method ? - for (final Registration registration : registrations.values()) { - registration.clear(); + lock.lock(); + final Iterator, Registration>> it = registrations.iterator(); + while (it.hasNext()) { + it.next().getValue().clear(); } registrations.clear(); logRegistryEvent("Registry cleared."); + lock.unlock(); } /** diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/FactoryOneRegistry.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/FactoryOneRegistry.java new file mode 100644 index 00000000..3c1e8f86 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/FactoryOneRegistry.java @@ -0,0 +1,101 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.registry; + +import java.util.concurrent.locks.Lock; + +import fr.neatmonster.nocheatplus.components.concurrent.IPrimaryThreadContextTester; +import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne; +import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW; + +/** + * Register IFactoryOne instances for object creation. + *
    + * Instance fetching from factories is done under lock. If instance creation is + * thread-safe, naturally depends on the underlying factory implementations. + * + * @author asofold + * + * @param + * Argument type for IFactoryOne instances. + */ +public class FactoryOneRegistry { + + private final Lock lock; + private final IPrimaryThreadContextTester primaryThreadContextTester; + private final HashMapLOW, IFactoryOne> factories; + + + public FactoryOneRegistry(Lock lock, IPrimaryThreadContextTester primaryThreadContextTester) { + this.lock = lock; + this.primaryThreadContextTester = primaryThreadContextTester; + // TODO: RegisteredItemStore can't do classes -> need RegisteredClassStore (...). + factories = new HashMapLOW, IFactoryOne>(lock, 30); + } + + /** + * Note that types are automatically sorted into registered groups. + * + * @param registerFor + * @param factory + */ + public void registerFactory(final Class registerFor, + final IFactoryOne factory) { + if (!primaryThreadContextTester.isPrimaryThread()) { + outsideThreadContext("register factory"); + } + lock.lock(); + factories.put(registerFor, factory); + lock.unlock(); + } + + private void outsideThreadContext(final String tag) { + throw new IllegalStateException("Can't call off the primary thread context: " + tag); + } + + /** + * Fetch a new instance from a registered factory. + * + * @param registeredFor + * @param arg + * @return + * @throws A + * RuntimeException (might get changed to a registry type of + * exception), in case a factory throws something- + */ + public T getNewInstance(final Class registeredFor, final A arg) { + @SuppressWarnings("unchecked") + final IFactoryOne factory = (IFactoryOne) factories.get(registeredFor); + if (factory == null) { + return null; + } + else { + lock.lock(); + T instance; + try { + instance = factory.getNewInstance(arg); + } + catch (Exception e) { + // TODO: Exception type to throw. + throw new RuntimeException(e); + } + finally { + lock.unlock(); + } + return instance; + } + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/GenericInstanceRegistry.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/GenericInstanceRegistry.java index 3a377943..46646bc8 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/GenericInstanceRegistry.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/GenericInstanceRegistry.java @@ -14,7 +14,6 @@ */ package fr.neatmonster.nocheatplus.components.registry; -import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle; import fr.neatmonster.nocheatplus.components.registry.exception.RegistrationLockedException; /** @@ -22,11 +21,13 @@ import fr.neatmonster.nocheatplus.components.registry.exception.RegistrationLock * Currently there is no specification for what happens with registering for an * already registered class, neither if exceptions are thrown, nor if * dependencies will use those then. + *
    + * Note getters: {@link IGetGenericInstance} * * @author asofold * */ -public interface GenericInstanceRegistry { +public interface GenericInstanceRegistry extends IGetGenericInstance, IGetGenericInstanceHandle { /** * Register the instance by its own class. This demands type parameters to @@ -50,14 +51,6 @@ public interface GenericInstanceRegistry { */ public T registerGenericInstance(Class registerFor, TI instance); - /** - * Retrieve the instance registered for the given class. - * - * @param registeredBy - * @return The instance, or null, if none is registered. - */ - public T getGenericInstance(Class registeredFor); - /** * Remove a registration. The registry implementation might specify id * removing is allowed. @@ -70,13 +63,4 @@ public interface GenericInstanceRegistry { */ public T unregisterGenericInstance(Class registeredFor); - /** - * Get a self-updating handle for conveniently getting the currently - * registered instance. - * - * @param registeredFor - * @return - */ - public IGenericInstanceHandle getGenericInstanceHandle(Class registeredFor); - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/IGetGenericInstance.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/IGetGenericInstance.java new file mode 100644 index 00000000..16e1bf9c --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/IGetGenericInstance.java @@ -0,0 +1,33 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.registry; + +/** + * Generic instance fetching (minimal getter). + * + * @author asofold + * + */ +public interface IGetGenericInstance { + + /** + * Retrieve the instance registered for the given class. + * + * @param registeredFor + * @return The instance, or null, if none is registered. + */ + public T getGenericInstance(Class registeredFor); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/CheckConfigFactory.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/IGetGenericInstanceHandle.java similarity index 59% rename from NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/CheckConfigFactory.java rename to NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/IGetGenericInstanceHandle.java index 74546417..831d072d 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/access/CheckConfigFactory.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/IGetGenericInstanceHandle.java @@ -1,40 +1,36 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package fr.neatmonster.nocheatplus.checks.access; - -import org.bukkit.entity.Player; - -/** - * A factory for creating and accessing configurations. - * - * @author asofold - */ -public interface CheckConfigFactory { - - /** - * Gets the configuration for a specified player. - * - * @param player - * the player - * @return the configuration - */ - public ICheckConfig getConfig(Player player); - - /** - * Remove all stored configurations. - */ - public void removeAllConfigs(); - -} +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.registry; + +import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle; + +/** + * Generic instance handle getting. + * + * @author asofold + * + */ +public interface IGetGenericInstanceHandle { + + /** + * Get a self-updating handle for conveniently getting the currently + * registered instance. + * + * @param registeredFor + * @return + */ + public IGenericInstanceHandle getGenericInstanceHandle(Class registeredFor); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/TypeSetRegistry.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/TypeSetRegistry.java new file mode 100644 index 00000000..5eb24522 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/TypeSetRegistry.java @@ -0,0 +1,150 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.registry; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Map.Entry; +import java.util.concurrent.locks.Lock; + +import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW; + +/** + * Register sets of 'item types' for group types. + *
    + * Typo :). + * + * @author asofold + * + */ +public class TypeSetRegistry { + + /** + * Idea of typed nodes is to help the JIT, not sure such ever will work. + * + * @author asofold + * + * @param + */ + private static class GroupNode { + + @SuppressWarnings("unchecked") + private Collection> group = Collections.EMPTY_LIST; + private final Class groupType; + + GroupNode(Class groupType) { + this.groupType = groupType; + } + + void add(Class itemClass) { + final Collection> copyGroup = new LinkedHashSet>(group); + copyGroup.add(itemClass); + group = Collections.unmodifiableCollection(copyGroup); + } + + @SuppressWarnings("unchecked") + void add(Class groupType, Class itemClass) { + if (groupType == this.groupType) { + add((Class) itemClass); + } + else { + throw new IllegalArgumentException("Invalid group type."); + } + } + + Collection> getItems() { + return group; + } + + } + + ////////////////////////77 + // Instance. + ///////////////////// + + private final Lock lock; + /** + * Types grouped by other types for efficient getting. + */ + private final HashMapLOW, GroupNode> groupedTypes; + + + public TypeSetRegistry(Lock lock) { + this.lock = lock; + groupedTypes = new HashMapLOW, GroupNode>(lock, 10); + } + + /** + * Register the item type for the given group types. + * + * @param itemType + * @param groupTypes + */ + public void addToGroups(final Class itemType, final Class... groupTypes) { + lock.lock(); + for (final Class groupType : groupTypes) { + if (!groupType.isAssignableFrom(itemType)) { + lock.unlock(); + throw new IllegalArgumentException("Can't assign " + itemType.getName() + " to " + groupType.getName() + "!"); + } + @SuppressWarnings("unchecked") + GroupNode node = (GroupNode) groupedTypes.get(groupType); + if (node == null) { + node = newGroupNode(groupType); + } + node.add(groupType, itemType); + } + lock.unlock(); + } + + private GroupNode newGroupNode(Class groupType) { + final GroupNode node = new GroupNode(groupType); + groupedTypes.put(groupType, node); + return node; + } + + /** + * Add the item type only to already registered (super) groups. + * + * @param itemType + */ + public void addToExistingGroups(final Class itemType) { + lock.lock(); + // Sort in all existing registered group types. + for (final Entry, GroupNode> entry : groupedTypes.iterable()) { + final Class groupType = entry.getKey(); + if (groupType.isAssignableFrom(itemType)) { + // TODO: also here try catch. + final GroupNode group = entry.getValue(); + group.add(groupType, itemType); + } + } + lock.unlock(); + } + + /** + * Retrieve all types that are grouped under the given group type. + * + * @param groupType + * @return + */ + @SuppressWarnings("unchecked") + public Collection> getGroupedTypes(Class groupType) { + final GroupNode group = (GroupNode) groupedTypes.get(groupType); + return group == null ? Collections.EMPTY_LIST : group.getItems(); + } + +} diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/components/registry/event/GenericInstanceHandle.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/event/GenericInstanceHandle.java similarity index 100% rename from NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/components/registry/event/GenericInstanceHandle.java rename to NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/event/GenericInstanceHandle.java diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/factory/IFactoryOne.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/factory/IFactoryOne.java new file mode 100644 index 00000000..4bd974b4 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/factory/IFactoryOne.java @@ -0,0 +1,38 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.components.registry.factory; + +/** + * + * Factory with one generic argument. + * + * @author asofold + * + * @param
    + * Argument type. + * @param + * Return type. + */ +public interface IFactoryOne { + + /** + * Get a new instance. + * + * @param arg + * @return + */ + public R getNewInstance(A arg); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/lockable/BasicLockable.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/lockable/BasicLockable.java index 00be439a..d7415f02 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/lockable/BasicLockable.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/lockable/BasicLockable.java @@ -1,3 +1,17 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package fr.neatmonster.nocheatplus.components.registry.lockable; /** diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/lockable/ILockable.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/lockable/ILockable.java index c7ff9065..76a48e93 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/lockable/ILockable.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/components/registry/lockable/ILockable.java @@ -1,3 +1,17 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package fr.neatmonster.nocheatplus.components.registry.lockable; /** diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfPaths.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfPaths.java index 3892de46..267f2c5e 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfPaths.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfPaths.java @@ -29,6 +29,7 @@ public abstract class ConfPaths { // Sub-paths that are used with different path prefixes potentially. // TODO: These might better be in another class. + public static final String SUB_ACTIVE = "active"; public static final String SUB_ALLOWINSTANTBREAK = "allowinstantbreak"; public static final String SUB_ASCEND = "ascend"; public static final String SUB_DEBUG = "debug"; @@ -78,19 +79,19 @@ public abstract class ConfPaths { @GlobalConfig private static final String LOGGING = "logging."; - public static final String LOGGING_ACTIVE = LOGGING + "active"; + public static final String LOGGING_ACTIVE = LOGGING + SUB_ACTIVE; public static final String LOGGING_MAXQUEUESIZE = LOGGING + "maxqueuesize"; private static final String LOGGING_BACKEND = LOGGING + "backend."; private static final String LOGGING_BACKEND_CONSOLE = LOGGING_BACKEND + "console."; - public static final String LOGGING_BACKEND_CONSOLE_ACTIVE = LOGGING_BACKEND_CONSOLE + "active"; + public static final String LOGGING_BACKEND_CONSOLE_ACTIVE = LOGGING_BACKEND_CONSOLE + SUB_ACTIVE; public static final String LOGGING_BACKEND_CONSOLE_ASYNCHRONOUS = LOGGING_BACKEND_CONSOLE + "asynchronous"; private static final String LOGGING_BACKEND_FILE = LOGGING_BACKEND + "file."; - public static final String LOGGING_BACKEND_FILE_ACTIVE = LOGGING_BACKEND_FILE + "active"; + public static final String LOGGING_BACKEND_FILE_ACTIVE = LOGGING_BACKEND_FILE + SUB_ACTIVE; public static final String LOGGING_BACKEND_FILE_FILENAME = LOGGING_BACKEND_FILE + "filename"; public static final String LOGGING_BACKEND_FILE_PREFIX = LOGGING_BACKEND_FILE + "prefix"; private static final String LOGGING_BACKEND_INGAMECHAT = LOGGING_BACKEND + "ingamechat."; - public static final String LOGGING_BACKEND_INGAMECHAT_ACTIVE = LOGGING_BACKEND_INGAMECHAT + "active"; + public static final String LOGGING_BACKEND_INGAMECHAT_ACTIVE = LOGGING_BACKEND_INGAMECHAT + SUB_ACTIVE; public static final String LOGGING_BACKEND_INGAMECHAT_PREFIX = LOGGING_BACKEND_INGAMECHAT + "prefix"; private static final String LOGGING_EXTENDED = LOGGING + "extended."; @@ -117,13 +118,13 @@ public abstract class ConfPaths { private static final String DATA = "data."; // Expired data removal. private static final String DATA_EXPIRATION = DATA + "expiration."; - public static final String DATA_EXPIRATION_ACTIVE = DATA_EXPIRATION + "active"; + public static final String DATA_EXPIRATION_ACTIVE = DATA_EXPIRATION + SUB_ACTIVE; public static final String DATA_EXPIRATION_DURATION = DATA_EXPIRATION + "duration"; public static final String DATA_EXPIRATION_DATA = DATA_EXPIRATION + "data"; public static final String DATA_EXPIRATION_HISTORY = DATA_EXPIRATION + "history"; // Consistency checking. private static final String DATA_CONSISTENCYCHECKS = DATA + "consistencychecks."; - public static final String DATA_CONSISTENCYCHECKS_CHECK = DATA_CONSISTENCYCHECKS + "active"; + public static final String DATA_CONSISTENCYCHECKS_CHECK = DATA_CONSISTENCYCHECKS + SUB_ACTIVE; public static final String DATA_CONSISTENCYCHECKS_INTERVAL = DATA_CONSISTENCYCHECKS + "interval"; public static final String DATA_CONSISTENCYCHECKS_MAXTIME = DATA_CONSISTENCYCHECKS + "maxtime"; /** @@ -144,20 +145,20 @@ public abstract class ConfPaths { private static final String PROTECT_CLIENTS = PROTECT + "clients."; @GlobalConfig private static final String PROTECT_CLIENTS_MOTD = PROTECT_CLIENTS + "motd."; - public static final String PROTECT_CLIENTS_MOTD_ACTIVE = PROTECT_CLIENTS_MOTD + "active"; + public static final String PROTECT_CLIENTS_MOTD_ACTIVE = PROTECT_CLIENTS_MOTD + SUB_ACTIVE; public static final String PROTECT_CLIENTS_MOTD_ALLOWALL = PROTECT_CLIENTS_MOTD + "allowall"; // Other commands settings @GlobalConfig private static final String PROTECT_COMMANDS = PROTECT + "commands."; private static final String PROTECT_COMMANDS_CONSOLEONLY = PROTECT_COMMANDS + "consoleonly."; - public static final String PROTECT_COMMANDS_CONSOLEONLY_ACTIVE = PROTECT_COMMANDS_CONSOLEONLY + "active"; + public static final String PROTECT_COMMANDS_CONSOLEONLY_ACTIVE = PROTECT_COMMANDS_CONSOLEONLY + SUB_ACTIVE; public static final String PROTECT_COMMANDS_CONSOLEONLY_MSG = PROTECT_COMMANDS_CONSOLEONLY + "message"; public static final String PROTECT_COMMANDS_CONSOLEONLY_CMDS = PROTECT_COMMANDS_CONSOLEONLY + "commands"; // Plugins settings. private static final String PROTECT_PLUGINS = PROTECT + "plugins."; @GlobalConfig private static final String PROTECT_PLUGINS_HIDE = PROTECT_PLUGINS + "hide."; - public static final String PROTECT_PLUGINS_HIDE_ACTIVE = PROTECT_PLUGINS_HIDE + "active"; + public static final String PROTECT_PLUGINS_HIDE_ACTIVE = PROTECT_PLUGINS_HIDE + SUB_ACTIVE; private static final String PROTECT_PLUGINS_HIDE_NOCOMMAND = PROTECT_PLUGINS_HIDE + "unknowncommand."; public static final String PROTECT_PLUGINS_HIDE_NOCOMMAND_MSG = PROTECT_PLUGINS_HIDE_NOCOMMAND + "message"; public static final String PROTECT_PLUGINS_HIDE_NOCOMMAND_CMDS = PROTECT_PLUGINS_HIDE_NOCOMMAND + "commands"; @@ -175,11 +176,11 @@ public abstract class ConfPaths { private static final String BLOCKBREAK_DIRECTION = BLOCKBREAK + "direction."; - public static final String BLOCKBREAK_DIRECTION_CHECK = BLOCKBREAK_DIRECTION + "active"; + public static final String BLOCKBREAK_DIRECTION_CHECK = BLOCKBREAK_DIRECTION + SUB_ACTIVE; public static final String BLOCKBREAK_DIRECTION_ACTIONS = BLOCKBREAK_DIRECTION + "actions"; private static final String BLOCKBREAK_FASTBREAK = BLOCKBREAK + "fastbreak."; - public static final String BLOCKBREAK_FASTBREAK_CHECK = BLOCKBREAK_FASTBREAK + "active"; + public static final String BLOCKBREAK_FASTBREAK_CHECK = BLOCKBREAK_FASTBREAK + SUB_ACTIVE; public static final String BLOCKBREAK_FASTBREAK_STRICT = BLOCKBREAK_FASTBREAK + "strict"; private static final String BLOCKBREAK_FASTBREAK_BUCKETS = BLOCKBREAK + "buckets."; public static final String BLOCKBREAK_FASTBREAK_BUCKETS_CONTENTION = BLOCKBREAK_FASTBREAK_BUCKETS + "contention"; @@ -194,7 +195,7 @@ public abstract class ConfPaths { public static final String BLOCKBREAK_FASTBREAK_ACTIONS = BLOCKBREAK_FASTBREAK + "actions"; private static final String BLOCKBREAK_FREQUENCY = BLOCKBREAK + "frequency."; - public static final String BLOCKBREAK_FREQUENCY_CHECK = BLOCKBREAK_FREQUENCY + "active"; + public static final String BLOCKBREAK_FREQUENCY_CHECK = BLOCKBREAK_FREQUENCY + SUB_ACTIVE; public static final String BLOCKBREAK_FREQUENCY_MOD_CREATIVE = BLOCKBREAK_FREQUENCY + "intervalcreative"; public static final String BLOCKBREAK_FREQUENCY_MOD_SURVIVAL = BLOCKBREAK_FREQUENCY + "intervalsurvival"; private static final String BLOCKBREAK_FREQUENCY_BUCKETS = BLOCKBREAK_FREQUENCY + "buckets."; @@ -209,56 +210,56 @@ public abstract class ConfPaths { public static final String BLOCKBREAK_FREQUENCY_ACTIONS = BLOCKBREAK_FREQUENCY + "actions"; private static final String BLOCKBREAK_NOSWING = BLOCKBREAK + "noswing."; - public static final String BLOCKBREAK_NOSWING_CHECK = BLOCKBREAK_NOSWING + "active"; + public static final String BLOCKBREAK_NOSWING_CHECK = BLOCKBREAK_NOSWING + SUB_ACTIVE; public static final String BLOCKBREAK_NOSWING_ACTIONS = BLOCKBREAK_NOSWING + "actions"; private static final String BLOCKBREAK_REACH = BLOCKBREAK + "reach."; - public static final String BLOCKBREAK_REACH_CHECK = BLOCKBREAK_REACH + "active"; + public static final String BLOCKBREAK_REACH_CHECK = BLOCKBREAK_REACH + SUB_ACTIVE; public static final String BLOCKBREAK_REACH_ACTIONS = BLOCKBREAK_REACH + "actions"; private static final String BLOCKBREAK_WRONGBLOCK = BLOCKBREAK + "wrongblock."; - public static final String BLOCKBREAK_WRONGBLOCK_CHECK = BLOCKBREAK_WRONGBLOCK + "active"; + public static final String BLOCKBREAK_WRONGBLOCK_CHECK = BLOCKBREAK_WRONGBLOCK + SUB_ACTIVE; public static final String BLOCKBREAK_WRONGBLOCK_LEVEL = BLOCKBREAK_WRONGBLOCK + "level"; public static final String BLOCKBREAK_WRONGBLOCK_ACTIONS = BLOCKBREAK_WRONGBLOCK + "actions"; public static final String BLOCKINTERACT = CHECKS + "blockinteract."; private static final String BLOCKINTERACT_DIRECTION = BLOCKINTERACT + "direction."; - public static final String BLOCKINTERACT_DIRECTION_CHECK = BLOCKINTERACT_DIRECTION + "active"; + public static final String BLOCKINTERACT_DIRECTION_CHECK = BLOCKINTERACT_DIRECTION + SUB_ACTIVE; public static final String BLOCKINTERACT_DIRECTION_ACTIONS = BLOCKINTERACT_DIRECTION + "actions"; private static final String BLOCKINTERACT_REACH = BLOCKINTERACT + "reach."; - public static final String BLOCKINTERACT_REACH_CHECK = BLOCKINTERACT_REACH + "active"; + public static final String BLOCKINTERACT_REACH_CHECK = BLOCKINTERACT_REACH + SUB_ACTIVE; public static final String BLOCKINTERACT_REACH_ACTIONS = BLOCKINTERACT_REACH + "actions"; private static final String BLOCKINTERACT_SPEED = BLOCKINTERACT + "speed."; - public static final String BLOCKINTERACT_SPEED_CHECK = BLOCKINTERACT_SPEED + "active"; + public static final String BLOCKINTERACT_SPEED_CHECK = BLOCKINTERACT_SPEED + SUB_ACTIVE; public static final String BLOCKINTERACT_SPEED_INTERVAL = BLOCKINTERACT_SPEED + "interval"; public static final String BLOCKINTERACT_SPEED_LIMIT = BLOCKINTERACT_SPEED + "limit"; public static final String BLOCKINTERACT_SPEED_ACTIONS = BLOCKINTERACT_SPEED + "actions"; private static final String BLOCKINTERACT_VISIBLE = BLOCKINTERACT + "visible."; - public static final String BLOCKINTERACT_VISIBLE_CHECK = BLOCKINTERACT_VISIBLE + "active"; + public static final String BLOCKINTERACT_VISIBLE_CHECK = BLOCKINTERACT_VISIBLE + SUB_ACTIVE; public static final String BLOCKINTERACT_VISIBLE_ACTIONS = BLOCKINTERACT_VISIBLE + "actions"; // BLOCKPLACE public static final String BLOCKPLACE = CHECKS + "blockplace."; private static final String BLOCKPLACE_AGAINST = BLOCKPLACE + "against."; - public static final String BLOCKPLACE_AGAINST_CHECK = BLOCKPLACE_AGAINST + "active"; + public static final String BLOCKPLACE_AGAINST_CHECK = BLOCKPLACE_AGAINST + SUB_ACTIVE; public static final String BLOCKPLACE_AGAINST_ACTIONS = BLOCKPLACE_AGAINST + "actions"; private static final String BLOCKPLACE_AUTOSIGN = BLOCKPLACE + "autosign."; - public static final String BLOCKPLACE_AUTOSIGN_CHECK = BLOCKPLACE_AUTOSIGN + "active"; + public static final String BLOCKPLACE_AUTOSIGN_CHECK = BLOCKPLACE_AUTOSIGN + SUB_ACTIVE; public static final String BLOCKPLACE_AUTOSIGN_SKIPEMPTY = BLOCKPLACE_AUTOSIGN + "skipempty"; public static final String BLOCKPLACE_AUTOSIGN_ACTIONS = BLOCKPLACE_AUTOSIGN + "actions"; private static final String BLOCKPLACE_DIRECTION = BLOCKPLACE + "direction."; - public static final String BLOCKPLACE_DIRECTION_CHECK = BLOCKPLACE_DIRECTION + "active"; + public static final String BLOCKPLACE_DIRECTION_CHECK = BLOCKPLACE_DIRECTION + SUB_ACTIVE; public static final String BLOCKPLACE_DIRECTION_ACTIONS = BLOCKPLACE_DIRECTION + "actions"; private static final String BLOCKPLACE_FASTPLACE = BLOCKPLACE + "fastplace."; - public static final String BLOCKPLACE_FASTPLACE_CHECK = BLOCKPLACE_FASTPLACE + "active"; + public static final String BLOCKPLACE_FASTPLACE_CHECK = BLOCKPLACE_FASTPLACE + SUB_ACTIVE; public static final String BLOCKPLACE_FASTPLACE_LIMIT = BLOCKPLACE_FASTPLACE + "limit"; private static final String BLOCKPLACE_FASTPLACE_SHORTTERM = BLOCKPLACE_FASTPLACE + "shortterm."; public static final String BLOCKPLACE_FASTPLACE_SHORTTERM_TICKS = BLOCKPLACE_FASTPLACE_SHORTTERM + "ticks"; @@ -266,16 +267,16 @@ public abstract class ConfPaths { public static final String BLOCKPLACE_FASTPLACE_ACTIONS = BLOCKPLACE_FASTPLACE + "actions"; private static final String BLOCKPLACE_NOSWING = BLOCKPLACE + "noswing."; - public static final String BLOCKPLACE_NOSWING_CHECK = BLOCKPLACE_NOSWING + "active"; + public static final String BLOCKPLACE_NOSWING_CHECK = BLOCKPLACE_NOSWING + SUB_ACTIVE; public static final String BLOCKPLACE_NOSWING_EXCEPTIONS = BLOCKPLACE_NOSWING + "exceptions"; public static final String BLOCKPLACE_NOSWING_ACTIONS = BLOCKPLACE_NOSWING + "actions"; private static final String BLOCKPLACE_REACH = BLOCKPLACE + "reach."; - public static final String BLOCKPLACE_REACH_CHECK = BLOCKPLACE_REACH + "active"; + public static final String BLOCKPLACE_REACH_CHECK = BLOCKPLACE_REACH + SUB_ACTIVE; public static final String BLOCKPLACE_REACH_ACTIONS = BLOCKPLACE_REACH + "actions"; private static final String BLOCKPLACE_SPEED = BLOCKPLACE + "speed."; - public static final String BLOCKPLACE_SPEED_CHECK = BLOCKPLACE_SPEED + "active"; + public static final String BLOCKPLACE_SPEED_CHECK = BLOCKPLACE_SPEED + SUB_ACTIVE; public static final String BLOCKPLACE_SPEED_INTERVAL = BLOCKPLACE_SPEED + "interval"; public static final String BLOCKPLACE_SPEED_ACTIONS = BLOCKPLACE_SPEED + "actions"; @@ -285,7 +286,7 @@ public abstract class ConfPaths { public static final String CHAT = CHECKS + "chat."; private static final String CHAT_CAPTCHA = CHAT + "captcha."; - public static final String CHAT_CAPTCHA_CHECK = CHAT_CAPTCHA + "active"; + public static final String CHAT_CAPTCHA_CHECK = CHAT_CAPTCHA + SUB_ACTIVE; private static final String CHAT_CAPTCHA_SKIP = CHAT_CAPTCHA + "skip."; public static final String CHAT_CAPTCHA_SKIP_COMMANDS = CHAT_CAPTCHA_SKIP + "commands"; public static final String CHAT_CAPTCHA_CHARACTERS = CHAT_CAPTCHA + "characters"; @@ -296,11 +297,11 @@ public abstract class ConfPaths { public static final String CHAT_CAPTCHA_ACTIONS = CHAT_CAPTCHA + "actions"; private static final String CHAT_COLOR = CHAT + "color."; - public static final String CHAT_COLOR_CHECK = CHAT_COLOR + "active"; + public static final String CHAT_COLOR_CHECK = CHAT_COLOR + SUB_ACTIVE; public static final String CHAT_COLOR_ACTIONS = CHAT_COLOR + "actions"; private static final String CHAT_COMMANDS = CHAT + "commands."; - public static final String CHAT_COMMANDS_CHECK = CHAT_COMMANDS + "active"; + public static final String CHAT_COMMANDS_CHECK = CHAT_COMMANDS + SUB_ACTIVE; @GlobalConfig public static final String CHAT_COMMANDS_EXCLUSIONS = CHAT_COMMANDS + "exclusions"; @GlobalConfig @@ -313,7 +314,7 @@ public abstract class ConfPaths { // Text private static final String CHAT_TEXT = CHAT + "text."; - public static final String CHAT_TEXT_CHECK = CHAT_TEXT + "active"; + public static final String CHAT_TEXT_CHECK = CHAT_TEXT + SUB_ACTIVE; public static final String CHAT_TEXT_DEBUG = CHAT_TEXT + "debug"; public static final String CHAT_TEXT_ENGINE_MAXIMUM = CHAT_TEXT + "maximum"; public static final String CHAT_TEXT_ALLOWVLRESET = CHAT_TEXT + "allowvlreset"; @@ -350,40 +351,40 @@ public abstract class ConfPaths { public static final String CHAT_TEXT_MSG_WORDS_NOLETTER = CHAT_TEXT_MSG_WORDS + "noletter"; // Extended global checks. private static final String CHAT_TEXT_GL = CHAT_TEXT + "global."; - public static final String CHAT_TEXT_GL_CHECK = CHAT_TEXT_GL + "active"; + public static final String CHAT_TEXT_GL_CHECK = CHAT_TEXT_GL + SUB_ACTIVE; public static final String CHAT_TEXT_GL_WEIGHT = CHAT_TEXT_GL + "weight"; @GlobalConfig public static final String CHAT_TEXT_GL_WORDS = CHAT_TEXT_GL + "words."; - public static final String CHAT_TEXT_GL_WORDS_CHECK = CHAT_TEXT_GL_WORDS + "active"; + public static final String CHAT_TEXT_GL_WORDS_CHECK = CHAT_TEXT_GL_WORDS + SUB_ACTIVE; @GlobalConfig public static final String CHAT_TEXT_GL_PREFIXES = CHAT_TEXT_GL + "prefixes."; - public static final String CHAT_TEXT_GL_PREFIXES_CHECK = CHAT_TEXT_GL_PREFIXES + "active"; + public static final String CHAT_TEXT_GL_PREFIXES_CHECK = CHAT_TEXT_GL_PREFIXES + SUB_ACTIVE; @GlobalConfig public static final String CHAT_TEXT_GL_SIMILARITY = CHAT_TEXT_GL + "similarity."; - public static final String CHAT_TEXT_GL_SIMILARITY_CHECK = CHAT_TEXT_GL_SIMILARITY + "active"; + public static final String CHAT_TEXT_GL_SIMILARITY_CHECK = CHAT_TEXT_GL_SIMILARITY + SUB_ACTIVE; // Extended per player checks. private static final String CHAT_TEXT_PP = CHAT_TEXT + "player."; - public static final String CHAT_TEXT_PP_CHECK = CHAT_TEXT_PP + "active"; + public static final String CHAT_TEXT_PP_CHECK = CHAT_TEXT_PP + SUB_ACTIVE; public static final String CHAT_TEXT_PP_WEIGHT = CHAT_TEXT_PP + "weight"; @GlobalConfig public static final String CHAT_TEXT_PP_PREFIXES = CHAT_TEXT_PP + "prefixes."; - public static final String CHAT_TEXT_PP_PREFIXES_CHECK = CHAT_TEXT_PP_PREFIXES + "active"; + public static final String CHAT_TEXT_PP_PREFIXES_CHECK = CHAT_TEXT_PP_PREFIXES + SUB_ACTIVE; @GlobalConfig public static final String CHAT_TEXT_PP_WORDS = CHAT_TEXT_PP + "words."; - public static final String CHAT_TEXT_PP_WORDS_CHECK = CHAT_TEXT_PP_WORDS + "active"; + public static final String CHAT_TEXT_PP_WORDS_CHECK = CHAT_TEXT_PP_WORDS + SUB_ACTIVE; @GlobalConfig public static final String CHAT_TEXT_PP_SIMILARITY = CHAT_TEXT_PP + "similarity."; - public static final String CHAT_TEXT_PP_SIMILARITY_CHECK = CHAT_TEXT_PP_SIMILARITY + "active"; + public static final String CHAT_TEXT_PP_SIMILARITY_CHECK = CHAT_TEXT_PP_SIMILARITY + SUB_ACTIVE; private static final String CHAT_WARNING = CHAT + "warning."; - public static final String CHAT_WARNING_CHECK = CHAT_WARNING + "active"; + public static final String CHAT_WARNING_CHECK = CHAT_WARNING + SUB_ACTIVE; public static final String CHAT_WARNING_LEVEL = CHAT_WARNING + "level"; public static final String CHAT_WARNING_MESSAGE = CHAT_WARNING + "message"; public static final String CHAT_WARNING_TIMEOUT = CHAT_WARNING + "timeout"; // NOT YET IN USE private static final String CHAT_LOGINS = CHAT + "logins."; - public static final String CHAT_LOGINS_CHECK = CHAT_LOGINS + "active"; + public static final String CHAT_LOGINS_CHECK = CHAT_LOGINS + SUB_ACTIVE; public static final String CHAT_LOGINS_PERWORLDCOUNT = CHAT_LOGINS + "perworldcount"; public static final String CHAT_LOGINS_SECONDS = CHAT_LOGINS + "seconds"; public static final String CHAT_LOGINS_LIMIT = CHAT_LOGINS + "limit"; @@ -391,7 +392,7 @@ public abstract class ConfPaths { public static final String CHAT_LOGINS_STARTUPDELAY = CHAT_LOGINS + "startupdelay"; private static final String CHAT_RELOG = CHAT + "relog."; - public static final String CHAT_RELOG_CHECK = CHAT_RELOG + "active"; + public static final String CHAT_RELOG_CHECK = CHAT_RELOG + SUB_ACTIVE; public static final String CHAT_RELOG_KICKMESSAGE = CHAT_RELOG + "kickmessage"; public static final String CHAT_RELOG_TIMEOUT = CHAT_RELOG + "timeout"; private static final String CHAT_RELOG_WARNING = CHAT_RELOG + "warning."; @@ -406,15 +407,15 @@ public abstract class ConfPaths { public static final String COMBINED = CHECKS + "combined."; private static final String COMBINED_BEDLEAVE = COMBINED + "bedleave."; - public static final String COMBINED_BEDLEAVE_CHECK = COMBINED_BEDLEAVE + "active"; + public static final String COMBINED_BEDLEAVE_CHECK = COMBINED_BEDLEAVE + SUB_ACTIVE; public static final String COMBINED_BEDLEAVE_ACTIONS = COMBINED_BEDLEAVE + "actions"; private static final String COMBINED_ENDERPEARL = COMBINED + "enderpearl."; - public static final String COMBINED_ENDERPEARL_CHECK = COMBINED_ENDERPEARL + "active"; + public static final String COMBINED_ENDERPEARL_CHECK = COMBINED_ENDERPEARL + SUB_ACTIVE; public static final String COMBINED_ENDERPEARL_PREVENTCLICKBLOCK = COMBINED_ENDERPEARL + "preventclickblock"; private static final String COMBINED_IMPROBABLE = COMBINED + "improbable."; - public static final String COMBINED_IMPROBABLE_CHECK = COMBINED_IMPROBABLE + "active"; + public static final String COMBINED_IMPROBABLE_CHECK = COMBINED_IMPROBABLE + SUB_ACTIVE; public static final String COMBINED_IMPROBABLE_LEVEL = COMBINED_IMPROBABLE + "level"; // private static final String COMBINED_IMPROBABLE_CHECKS = COMBINED_IMPROBABLE + "options."; @@ -423,7 +424,7 @@ public abstract class ConfPaths { public static final String COMBINED_IMPROBABLE_ACTIONS = COMBINED_IMPROBABLE + "actions"; private static final String COMBINED_INVULNERABLE = COMBINED + "invulnerable."; - public static final String COMBINED_INVULNERABLE_CHECK = COMBINED_INVULNERABLE + "active"; + public static final String COMBINED_INVULNERABLE_CHECK = COMBINED_INVULNERABLE + SUB_ACTIVE; private static final String COMBINED_INVULNERABLE_INITIALTICKS = COMBINED_INVULNERABLE + "initialticks."; public static final String COMBINED_INVULNERABLE_INITIALTICKS_JOIN = COMBINED_INVULNERABLE_INITIALTICKS + "join"; public static final String COMBINED_INVULNERABLE_IGNORE = COMBINED_INVULNERABLE + "ignore"; @@ -433,7 +434,7 @@ public abstract class ConfPaths { public static final String COMBINED_INVULNERABLE_TRIGGERS_FALLDISTANCE = COMBINED_INVULNERABLE_TRIGGERS + "falldistance"; public static final String COMBINED_MUNCHHAUSEN = COMBINED + "munchhausen."; - public static final String COMBINED_MUNCHHAUSEN_CHECK = COMBINED_MUNCHHAUSEN + "active"; + public static final String COMBINED_MUNCHHAUSEN_CHECK = COMBINED_MUNCHHAUSEN + SUB_ACTIVE; public static final String COMBINED_MUNCHHAUSEN_ACTIONS = COMBINED_MUNCHHAUSEN + "actions"; private static final String COMBINED_YAWRATE = COMBINED + "yawrate."; @@ -452,12 +453,12 @@ public abstract class ConfPaths { public static final String FIGHT_PVP_KNOCKBACKVELOCITY = FIGHT_PVP + "knockbackvelocity"; private static final String FIGHT_ANGLE = FIGHT + "angle."; - public static final String FIGHT_ANGLE_CHECK = FIGHT_ANGLE + "active"; + public static final String FIGHT_ANGLE_CHECK = FIGHT_ANGLE + SUB_ACTIVE; public static final String FIGHT_ANGLE_THRESHOLD = FIGHT_ANGLE + "threshold"; public static final String FIGHT_ANGLE_ACTIONS = FIGHT_ANGLE + "actions"; private static final String FIGHT_CRITICAL = FIGHT + "critical."; - public static final String FIGHT_CRITICAL_CHECK = FIGHT_CRITICAL + "active"; + public static final String FIGHT_CRITICAL_CHECK = FIGHT_CRITICAL + SUB_ACTIVE; private static final String FIGHT_CRITICAL_CANCEL = FIGHT_CRITICAL + "cancel."; public static final String FIGHT_CRITICAL_CANCEL_CANCEL = FIGHT_CRITICAL_CANCEL + "cancel"; public static final String FIGHT_CRITICAL_CANCEL_DIVIDEDAMAGE = FIGHT_CRITICAL_CANCEL + "dividedamage"; @@ -466,29 +467,29 @@ public abstract class ConfPaths { public static final String FIGHT_CRITICAL_ACTIONS = FIGHT_CRITICAL + "actions"; private static final String FIGHT_DIRECTION = FIGHT + "direction."; - public static final String FIGHT_DIRECTION_CHECK = FIGHT_DIRECTION + "active"; + public static final String FIGHT_DIRECTION_CHECK = FIGHT_DIRECTION + SUB_ACTIVE; public static final String FIGHT_DIRECTION_STRICT = FIGHT_DIRECTION + "strict"; public static final String FIGHT_DIRECTION_PENALTY = FIGHT_DIRECTION + "penalty"; public static final String FIGHT_DIRECTION_ACTIONS = FIGHT_DIRECTION + "actions"; private static final String FIGHT_FASTHEAL = FIGHT + "fastheal."; - public static final String FIGHT_FASTHEAL_CHECK = FIGHT_FASTHEAL + "active"; + public static final String FIGHT_FASTHEAL_CHECK = FIGHT_FASTHEAL + SUB_ACTIVE; public static final String FIGHT_FASTHEAL_INTERVAL = FIGHT_FASTHEAL + "interval"; public static final String FIGHT_FASTHEAL_BUFFER = FIGHT_FASTHEAL + "buffer"; public static final String FIGHT_FASTHEAL_ACTIONS = FIGHT_FASTHEAL + "actions"; private static final String FIGHT_GODMODE = FIGHT + "godmode."; - public static final String FIGHT_GODMODE_CHECK = FIGHT_GODMODE + "active"; + public static final String FIGHT_GODMODE_CHECK = FIGHT_GODMODE + SUB_ACTIVE; public static final String FIGHT_GODMODE_LAGMINAGE = FIGHT_GODMODE + "minage"; public static final String FIGHT_GODMODE_LAGMAXAGE = FIGHT_GODMODE + "maxage"; public static final String FIGHT_GODMODE_ACTIONS = FIGHT_GODMODE + "actions"; private static final String FIGHT_NOSWING = FIGHT + "noswing."; - public static final String FIGHT_NOSWING_CHECK = FIGHT_NOSWING + "active"; + public static final String FIGHT_NOSWING_CHECK = FIGHT_NOSWING + SUB_ACTIVE; public static final String FIGHT_NOSWING_ACTIONS = FIGHT_NOSWING + "actions"; private static final String FIGHT_REACH = FIGHT + "reach."; - public static final String FIGHT_REACH_CHECK = FIGHT_REACH + "active"; + public static final String FIGHT_REACH_CHECK = FIGHT_REACH + SUB_ACTIVE; public static final String FIGHT_REACH_SURVIVALDISTANCE = FIGHT_REACH + "survivaldistance"; public static final String FIGHT_REACH_PENALTY = FIGHT_REACH + "penalty"; public static final String FIGHT_REACH_PRECISION = FIGHT_REACH + "precision"; @@ -498,12 +499,12 @@ public abstract class ConfPaths { public static final String FIGHT_REACH_ACTIONS = FIGHT_REACH + "actions"; public static final String FIGHT_SELFHIT = FIGHT + "selfhit."; - public static final String FIGHT_SELFHIT_CHECK = FIGHT_SELFHIT + "active"; + public static final String FIGHT_SELFHIT_CHECK = FIGHT_SELFHIT + SUB_ACTIVE; public static final String FIGHT_SELFHIT_ACTIONS = FIGHT_SELFHIT + "actions"; private static final String FIGHT_SPEED = FIGHT + "speed."; - public static final String FIGHT_SPEED_CHECK = FIGHT_SPEED + "active"; + public static final String FIGHT_SPEED_CHECK = FIGHT_SPEED + SUB_ACTIVE; public static final String FIGHT_SPEED_LIMIT = FIGHT_SPEED + "limit"; private static final String FIGHT_SPEED_BUCKETS = FIGHT_SPEED + "buckets."; @GlobalConfig @@ -517,22 +518,22 @@ public abstract class ConfPaths { public static final String FIGHT_SPEED_ACTIONS = FIGHT_SPEED + "actions"; private static final String FIGHT_WRONGTURN = FIGHT + "wrongturn."; - public static final String FIGHT_WRONGTURN_CHECK = FIGHT_WRONGTURN + "active"; + public static final String FIGHT_WRONGTURN_CHECK = FIGHT_WRONGTURN + SUB_ACTIVE; public static final String FIGHT_WRONGTURN_ACTIONS = FIGHT_WRONGTURN + "actions"; private static final String FIGHT_YAWRATE = FIGHT + "yawrate."; - public static final String FIGHT_YAWRATE_CHECK = FIGHT_YAWRATE + "active"; + public static final String FIGHT_YAWRATE_CHECK = FIGHT_YAWRATE + SUB_ACTIVE; public static final String INVENTORY = CHECKS + "inventory."; private static final String INVENTORY_DROP = INVENTORY + "drop."; - public static final String INVENTORY_DROP_CHECK = INVENTORY_DROP + "active"; + public static final String INVENTORY_DROP_CHECK = INVENTORY_DROP + SUB_ACTIVE; public static final String INVENTORY_DROP_LIMIT = INVENTORY_DROP + "limit"; public static final String INVENTORY_DROP_TIMEFRAME = INVENTORY_DROP + "timeframe"; public static final String INVENTORY_DROP_ACTIONS = INVENTORY_DROP + "actions"; private static final String INVENTORY_FASTCLICK = INVENTORY + "fastclick."; - public static final String INVENTORY_FASTCLICK_CHECK = INVENTORY_FASTCLICK + "active"; + public static final String INVENTORY_FASTCLICK_CHECK = INVENTORY_FASTCLICK + SUB_ACTIVE; public static final String INVENTORY_FASTCLICK_SPARECREATIVE = INVENTORY_FASTCLICK + "sparecreative"; public static final String INVENTORY_FASTCLICK_TWEAKS1_5 = INVENTORY_FASTCLICK + "tweaks1_5"; private static final String INVENTORY_FASTCLICK_LIMIT = INVENTORY_FASTCLICK + "limit."; @@ -541,18 +542,18 @@ public abstract class ConfPaths { public static final String INVENTORY_FASTCLICK_ACTIONS = INVENTORY_FASTCLICK + "actions"; private static final String INVENTORY_FASTCONSUME = INVENTORY + "fastconsume."; - public static final String INVENTORY_FASTCONSUME_CHECK = INVENTORY_FASTCONSUME + "active"; + public static final String INVENTORY_FASTCONSUME_CHECK = INVENTORY_FASTCONSUME + SUB_ACTIVE; public static final String INVENTORY_FASTCONSUME_DURATION = INVENTORY_FASTCONSUME + "duration"; public static final String INVENTORY_FASTCONSUME_WHITELIST = INVENTORY_FASTCONSUME + "whitelist"; public static final String INVENTORY_FASTCONSUME_ITEMS = INVENTORY_FASTCONSUME + "items"; public static final String INVENTORY_FASTCONSUME_ACTIONS = INVENTORY_FASTCONSUME + "actions"; private static final String INVENTORY_GUTENBERG = INVENTORY + "gutenberg."; - public static final String INVENTORY_GUTENBERG_CHECK = INVENTORY_GUTENBERG + "active"; + public static final String INVENTORY_GUTENBERG_CHECK = INVENTORY_GUTENBERG + SUB_ACTIVE; public static final String INVENTORY_GUTENBERG_ACTIONS = INVENTORY_GUTENBERG + "actions"; private static final String INVENTORY_INSTANTBOW = INVENTORY + "instantbow."; - public static final String INVENTORY_INSTANTBOW_CHECK = INVENTORY_INSTANTBOW + "active"; + public static final String INVENTORY_INSTANTBOW_CHECK = INVENTORY_INSTANTBOW + SUB_ACTIVE; public static final String INVENTORY_INSTANTBOW_STRICT = INVENTORY_INSTANTBOW + "strict"; public static final String INVENTORY_INSTANTBOW_DELAY = INVENTORY_INSTANTBOW + "delay"; private static final String INVENTORY_INSTANTBOW_IMPROBABLE = INVENTORY_INSTANTBOW + "improbable."; @@ -562,14 +563,14 @@ public abstract class ConfPaths { public static final String INVENTORY_INSTANTBOW_ACTIONS = INVENTORY_INSTANTBOW + "actions"; private static final String INVENTORY_INSTANTEAT = INVENTORY + "instanteat."; - public static final String INVENTORY_INSTANTEAT_CHECK = INVENTORY_INSTANTEAT + "active"; + public static final String INVENTORY_INSTANTEAT_CHECK = INVENTORY_INSTANTEAT + SUB_ACTIVE; public static final String INVENTORY_INSTANTEAT_ACTIONS = INVENTORY_INSTANTEAT + "actions"; private static final String INVENTORY_ITEMS = INVENTORY + "items."; - public static final String INVENTORY_ITEMS_CHECK = INVENTORY_ITEMS + "active"; + public static final String INVENTORY_ITEMS_CHECK = INVENTORY_ITEMS + SUB_ACTIVE; private static final String INVENTORY_OPEN = INVENTORY + "open."; - public static final String INVENTORY_OPEN_CHECK = INVENTORY_OPEN + "active"; + public static final String INVENTORY_OPEN_CHECK = INVENTORY_OPEN + SUB_ACTIVE; // TODO: close and cancelother on open-section-level are temporary. public static final String INVENTORY_OPEN_CLOSE = INVENTORY_OPEN + "close"; public static final String INVENTORY_OPEN_CANCELOTHER = INVENTORY_OPEN + "cancelother"; @@ -582,14 +583,14 @@ public abstract class ConfPaths { public static final String MOVING = CHECKS + "moving."; private static final String MOVING_CREATIVEFLY = MOVING + "creativefly."; - public static final String MOVING_CREATIVEFLY_CHECK = MOVING_CREATIVEFLY + "active"; + public static final String MOVING_CREATIVEFLY_CHECK = MOVING_CREATIVEFLY + SUB_ACTIVE; public static final String MOVING_CREATIVEFLY_IGNORECREATIVE = MOVING_CREATIVEFLY + "ignorecreative"; public static final String MOVING_CREATIVEFLY_IGNOREALLOWFLIGHT = MOVING_CREATIVEFLY + "ignoreallowflight"; public static final String MOVING_CREATIVEFLY_MODEL = MOVING_CREATIVEFLY + SUB_MODEL + "."; public static final String MOVING_CREATIVEFLY_ACTIONS = MOVING_CREATIVEFLY + "actions"; private static final String MOVING_MOREPACKETS = MOVING + "morepackets."; - public static final String MOVING_MOREPACKETS_CHECK = MOVING_MOREPACKETS + "active"; + public static final String MOVING_MOREPACKETS_CHECK = MOVING_MOREPACKETS + SUB_ACTIVE; public static final String MOVING_MOREPACKETS_SECONDS = MOVING_MOREPACKETS + "seconds"; public static final String MOVING_MOREPACKETS_EPSIDEAL = MOVING_MOREPACKETS + "epsideal"; public static final String MOVING_MOREPACKETS_EPSMAX = MOVING_MOREPACKETS + "epsmax"; @@ -601,7 +602,7 @@ public abstract class ConfPaths { public static final String MOVING_MOREPACKETS_ACTIONS = MOVING_MOREPACKETS + "actions"; private static final String MOVING_NOFALL = MOVING + "nofall."; - public static final String MOVING_NOFALL_CHECK = MOVING_NOFALL + "active"; + public static final String MOVING_NOFALL_CHECK = MOVING_NOFALL + SUB_ACTIVE; public static final String MOVING_NOFALL_DEALDAMAGE = MOVING_NOFALL + "dealdamage"; public static final String MOVING_NOFALL_SKIPALLOWFLIGHT = MOVING_NOFALL + "skipallowflight"; // TODO: A reset section (violation, teleport, vehicle) + @Moved. @@ -612,19 +613,19 @@ public abstract class ConfPaths { public static final String MOVING_NOFALL_ACTIONS = MOVING_NOFALL + "actions"; public static final String MOVING_PASSABLE = MOVING + "passable."; - public static final String MOVING_PASSABLE_CHECK = MOVING_PASSABLE + "active"; + public static final String MOVING_PASSABLE_CHECK = MOVING_PASSABLE + SUB_ACTIVE; //private static final String MOVING_PASSABLE_RAYTRACING = MOVING_PASSABLE + "raytracing."; public static final String MOVING_PASSABLE_ACTIONS = MOVING_PASSABLE + "actions"; private static final String MOVING_PASSABLE_UNTRACKED = MOVING_PASSABLE + "untracked."; private static final String MOVING_PASSABLE_UNTRACKED_TELEPORT = MOVING_PASSABLE_UNTRACKED + "teleport."; - public static final String MOVING_PASSABLE_UNTRACKED_TELEPORT_ACTIVE = MOVING_PASSABLE_UNTRACKED_TELEPORT + "active"; + public static final String MOVING_PASSABLE_UNTRACKED_TELEPORT_ACTIVE = MOVING_PASSABLE_UNTRACKED_TELEPORT + SUB_ACTIVE; private static final String MOVING_PASSABLE_UNTRACKED_CMD = MOVING_PASSABLE_UNTRACKED + "command."; - public static final String MOVING_PASSABLE_UNTRACKED_CMD_ACTIVE = MOVING_PASSABLE_UNTRACKED_CMD + "active"; + public static final String MOVING_PASSABLE_UNTRACKED_CMD_ACTIVE = MOVING_PASSABLE_UNTRACKED_CMD + SUB_ACTIVE; public static final String MOVING_PASSABLE_UNTRACKED_CMD_TRYTELEPORT = MOVING_PASSABLE_UNTRACKED_CMD + "tryteleport"; public static final String MOVING_PASSABLE_UNTRACKED_CMD_PREFIXES = MOVING_PASSABLE_UNTRACKED_CMD + "prefixes"; private static final String MOVING_SURVIVALFLY = MOVING + "survivalfly."; - public static final String MOVING_SURVIVALFLY_CHECK = MOVING_SURVIVALFLY + "active"; + public static final String MOVING_SURVIVALFLY_CHECK = MOVING_SURVIVALFLY + SUB_ACTIVE; public static final String MOVING_SURVIVALFLY_BLOCKINGSPEED = MOVING_SURVIVALFLY + "blockingspeed"; public static final String MOVING_SURVIVALFLY_SNEAKINGSPEED = MOVING_SURVIVALFLY + "sneakingspeed"; public static final String MOVING_SURVIVALFLY_SPEEDINGSPEED = MOVING_SURVIVALFLY + "speedingspeed"; @@ -646,7 +647,7 @@ public abstract class ConfPaths { public static final String MOVING_SURVIVALFLY_ACTIONS = MOVING_SURVIVALFLY + "actions"; private static final String MOVING_SURVIVALFLY_HOVER = MOVING_SURVIVALFLY + "hover."; - public static final String MOVING_SURVIVALFLY_HOVER_CHECK = MOVING_SURVIVALFLY_HOVER + "active"; + public static final String MOVING_SURVIVALFLY_HOVER_CHECK = MOVING_SURVIVALFLY_HOVER + SUB_ACTIVE; @GlobalConfig public static final String MOVING_SURVIVALFLY_HOVER_STEP = MOVING_SURVIVALFLY_HOVER + "step"; public static final String MOVING_SURVIVALFLY_HOVER_TICKS = MOVING_SURVIVALFLY_HOVER + "ticks"; @@ -691,10 +692,10 @@ public abstract class ConfPaths { public static final String MOVING_VEHICLE_SCHEDULESETBACKS = MOVING_VEHICLE + "schedulesetbacks"; public static final String MOVING_VEHICLE_IGNOREDVEHICLES = MOVING_VEHICLE + "ignoredvehicles"; private static final String MOVING_VEHICLE_MOREPACKETS = MOVING_VEHICLE + "morepackets."; - public static final String MOVING_VEHICLE_MOREPACKETS_CHECK = MOVING_VEHICLE_MOREPACKETS + "active"; + public static final String MOVING_VEHICLE_MOREPACKETS_CHECK = MOVING_VEHICLE_MOREPACKETS + SUB_ACTIVE; public static final String MOVING_VEHICLE_MOREPACKETS_ACTIONS = MOVING_VEHICLE_MOREPACKETS + "actions"; private static final String MOVING_VEHICLE_ENVELOPE = MOVING_VEHICLE + "envelope."; - public static final String MOVING_VEHICLE_ENVELOPE_ACTIVE = MOVING_VEHICLE_ENVELOPE + "active"; + public static final String MOVING_VEHICLE_ENVELOPE_ACTIVE = MOVING_VEHICLE_ENVELOPE + SUB_ACTIVE; public static final String MOVING_VEHICLE_ENVELOPE_HSPEEDCAP = MOVING_VEHICLE_ENVELOPE + "hdistcap"; // Section. public static final String MOVING_VEHICLE_ENVELOPE_ACTIONS = MOVING_VEHICLE_ENVELOPE + "actions"; @@ -705,7 +706,7 @@ public abstract class ConfPaths { public static final String NET = CHECKS + "net."; private static final String NET_ATTACKFREQUENCY = NET + "attackfrequency."; - public static final String NET_ATTACKFREQUENCY_ACTIVE = NET_ATTACKFREQUENCY + "active"; + public static final String NET_ATTACKFREQUENCY_ACTIVE = NET_ATTACKFREQUENCY + SUB_ACTIVE; // TODO: Generic config for seconds. public static final String NET_ATTACKFREQUENCY_SECONDS = NET_ATTACKFREQUENCY + "limitforseconds."; public static final String NET_ATTACKFREQUENCY_SECONDS_HALF = NET_ATTACKFREQUENCY_SECONDS + "half"; @@ -716,7 +717,7 @@ public abstract class ConfPaths { public static final String NET_ATTACKFREQUENCY_ACTIONS = NET_ATTACKFREQUENCY + "actions"; private static final String NET_FLYINGFREQUENCY = NET + "flyingfrequency."; - public static final String NET_FLYINGFREQUENCY_ACTIVE = NET_FLYINGFREQUENCY + "active"; + public static final String NET_FLYINGFREQUENCY_ACTIVE = NET_FLYINGFREQUENCY + SUB_ACTIVE; @GlobalConfig public static final String NET_FLYINGFREQUENCY_SECONDS = NET_FLYINGFREQUENCY + "seconds"; @GlobalConfig @@ -724,23 +725,23 @@ public abstract class ConfPaths { public static final String NET_FLYINGFREQUENCY_ACTIONS = NET_FLYINGFREQUENCY + "actions"; // TODO: Reduceredundant has been removed (implement or remove config). private static final String NET_FLYINGFREQUENCY_REDUNDANT = NET_FLYINGFREQUENCY + "reduceredundant."; - public static final String NET_FLYINGFREQUENCY_REDUNDANT_ACTIVE = NET_FLYINGFREQUENCY_REDUNDANT + "active"; + public static final String NET_FLYINGFREQUENCY_REDUNDANT_ACTIVE = NET_FLYINGFREQUENCY_REDUNDANT + SUB_ACTIVE; @GlobalConfig public static final String NET_FLYINGFREQUENCY_REDUNDANT_SECONDS = NET_FLYINGFREQUENCY_REDUNDANT + "seconds"; public static final String NET_FLYINGFREQUENCY_REDUNDANT_ACTIONS = NET_FLYINGFREQUENCY_REDUNDANT + "actions"; private static final String NET_KEEPALIVEFREQUENCY = NET + "keepalivefrequency."; - public static final String NET_KEEPALIVEFREQUENCY_ACTIVE = NET_KEEPALIVEFREQUENCY + "active"; + public static final String NET_KEEPALIVEFREQUENCY_ACTIVE = NET_KEEPALIVEFREQUENCY + SUB_ACTIVE; public static final String NET_KEEPALIVEFREQUENCY_ACTIONS = NET_KEEPALIVEFREQUENCY + "actions"; private static final String NET_PACKETFREQUENCY = NET + "packetfrequency."; - public static final String NET_PACKETFREQUENCY_ACTIVE = NET_PACKETFREQUENCY + "active"; + public static final String NET_PACKETFREQUENCY_ACTIVE = NET_PACKETFREQUENCY + SUB_ACTIVE; public static final String NET_PACKETFREQUENCY_PPS = NET_PACKETFREQUENCY + "limitpersecond"; public static final String NET_PACKETFREQUENCY_SECONDS = NET_PACKETFREQUENCY + "seconds"; public static final String NET_PACKETFREQUENCY_ACTIONS = NET_PACKETFREQUENCY + "actions"; private static final String NET_SOUNDDISTANCE = NET + "sounddistance."; - public static final String NET_SOUNDDISTANCE_ACTIVE = NET_SOUNDDISTANCE + "active"; + public static final String NET_SOUNDDISTANCE_ACTIVE = NET_SOUNDDISTANCE + SUB_ACTIVE; public static final String NET_SOUNDDISTANCE_MAXDISTANCE = NET_SOUNDDISTANCE + "maxdistance"; /** Somehow superseded packets, typically leniency options .*/ @@ -759,13 +760,13 @@ public abstract class ConfPaths { private static final String COMPATIBILITY_EXEMPTIONS_WILDCARD = COMPATIBILITY_EXEMPTIONS + "wildcard."; private static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_DEFAULT = COMPATIBILITY_EXEMPTIONS_WILDCARD + "default."; private static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_DEFAULT_METADATA = COMPATIBILITY_EXEMPTIONS_WILDCARD_DEFAULT + "metadata."; - public static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_DEFAULT_METADATA_ACTIVE = COMPATIBILITY_EXEMPTIONS_WILDCARD_DEFAULT_METADATA + "active"; + public static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_DEFAULT_METADATA_ACTIVE = COMPATIBILITY_EXEMPTIONS_WILDCARD_DEFAULT_METADATA + SUB_ACTIVE; public static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_DEFAULT_METADATA_KEYS = COMPATIBILITY_EXEMPTIONS_WILDCARD_DEFAULT_METADATA + "keys"; private static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC = COMPATIBILITY_EXEMPTIONS_WILDCARD + "npc."; - public static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_ACTIVE = COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC + "active"; + public static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_ACTIVE = COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC + SUB_ACTIVE; public static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_BUKKITINTERFACE = COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC + "bukkitnpc"; private static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_METADATA = COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC + "metadata."; - public static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_METADATA_ACTIVE = COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_METADATA + "active"; + public static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_METADATA_ACTIVE = COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_METADATA + SUB_ACTIVE; public static final String COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_METADATA_KEYS = COMPATIBILITY_EXEMPTIONS_WILDCARD_NPC_METADATA + "keys"; public static final String COMPATIBILITY_EXEMPTIONS_REMOVE_JOIN = COMPATIBILITY_EXEMPTIONS_REMOVE + "join"; public static final String COMPATIBILITY_EXEMPTIONS_REMOVE_LEAVE = COMPATIBILITY_EXEMPTIONS_REMOVE + "leave"; @@ -779,7 +780,7 @@ public abstract class ConfPaths { public static final String COMPATIBILITY_BLOCKS = COMPATIBILITY + "blocks."; public static final String COMPATIBILITY_BLOCKS_CHANGETRACKER = COMPATIBILITY_BLOCKS + "changetracker."; - public static final String COMPATIBILITY_BLOCKS_CHANGETRACKER_ACTIVE = COMPATIBILITY_BLOCKS_CHANGETRACKER + "active"; + public static final String COMPATIBILITY_BLOCKS_CHANGETRACKER_ACTIVE = COMPATIBILITY_BLOCKS_CHANGETRACKER + SUB_ACTIVE; public static final String COMPATIBILITY_BLOCKS_CHANGETRACKER_PISTONS = COMPATIBILITY_BLOCKS_CHANGETRACKER + "pistons"; public static final String COMPATIBILITY_BLOCKS_CHANGETRACKER_MAXAGETICKS = COMPATIBILITY_BLOCKS_CHANGETRACKER + "maxageticks"; private static final String COMPATIBILITY_BLOCKS_CHANGETRACKER_PERWORLD = COMPATIBILITY_BLOCKS_CHANGETRACKER + "perworld."; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfigManager.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfigManager.java index 4641be77..d8bc8b85 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfigManager.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfigManager.java @@ -19,20 +19,27 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.plugin.Plugin; +import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.actions.ActionFactory; import fr.neatmonster.nocheatplus.logging.StaticLog; import fr.neatmonster.nocheatplus.utilities.StringUtil; import fr.neatmonster.nocheatplus.utilities.build.BuildParameters; +import fr.neatmonster.nocheatplus.worlds.IWorldData; +import fr.neatmonster.nocheatplus.worlds.IWorldDataManager; +import fr.neatmonster.nocheatplus.worlds.WorldDataManager; /** * Central location for everything that's described in the configuration file(s).
    @@ -51,9 +58,6 @@ public class ConfigManager { } }; - /** The map containing the configuration files per world. */ - private static Map worldsMap = new LinkedHashMap(); - private static final WorldConfigProvider worldConfigProvider = new WorldConfigProvider() { @Override @@ -68,7 +72,14 @@ public class ConfigManager { @Override public Collection getAllConfigs() { - return ConfigManager.worldsMap.values(); + // Avoid duplicates, which typically should exist. + final Set res = new LinkedHashSet(); + final IWorldDataManager worldMan = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + final Iterator> it = worldMan.getWorldDataIterator(); + while (it.hasNext()) { + res.add(it.next().getValue().getRawConfiguration()); + } + return res; } }; @@ -108,9 +119,12 @@ public class ConfigManager { }; } // Use lazy resetting. - for (final ConfigFile config : worldsMap.values()){ - config.setActionFactory(null); + final IWorldDataManager worldMan = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + final Iterator> it = worldMan.getWorldDataIterator(); + while (it.hasNext()){ + it.next().getValue().getRawConfiguration().setActionFactory(null); } + // TODO: Update WorldData is skipped for now. } public static ActionFactoryFactory getActionFactoryFactory(){ @@ -121,9 +135,12 @@ public class ConfigManager { * Force setting up all configs action factories. */ public static void setAllActionFactories(){ - for (final ConfigFile config : worldsMap.values()){ - config.setActionFactory(); + final IWorldDataManager worldMan = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + final Iterator> it = worldMan.getWorldDataIterator(); + while (it.hasNext()){ + it.next().getValue().getRawConfiguration().setActionFactory(); } + // TODO: Update WorldData is skipped for now. } /** @@ -149,7 +166,7 @@ public class ConfigManager { * @return the configuration file */ public static ConfigFile getConfigFile() { - return worldsMap.get(null); + return NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().getDefaultWorldData().getRawConfiguration(); } /** @@ -170,23 +187,7 @@ public class ConfigManager { * @return the configuration file */ public static ConfigFile getConfigFile(final String worldName) { - final ConfigFile configFile = worldsMap.get(worldName); - if (configFile != null){ - return configFile; - } - // Expensive only once per world, for the rest of the runtime the file is returned fast. - synchronized(ConfigManager.class){ - // Need to check again. - if (worldsMap.containsKey(worldName)){ - return worldsMap.get(worldName); - } - // Copy the whole map with the default configuration set for this world. - final Map newWorldsMap = new LinkedHashMap(ConfigManager.worldsMap); - final ConfigFile globalConfig = newWorldsMap.get(null); - newWorldsMap.put(worldName, globalConfig); - ConfigManager.worldsMap = newWorldsMap; - return globalConfig; - } + return NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().getDefaultWorldData().getRawConfiguration(); } /** @@ -206,7 +207,7 @@ public class ConfigManager { * @param plugin * the instance of NoCheatPlus */ - public static synchronized void init(final Plugin plugin) { + public static synchronized void init(final Plugin plugin, final WorldDataManager worldDataManager) { // (This can lead to minor problems with async checks during reloading.) LinkedHashMap newWorldsMap = new LinkedHashMap(); // Try to obtain and parse the global configuration file. @@ -305,7 +306,7 @@ public class ConfigManager { worldConfig.options().copyDefaults(true); // worldConfig.setActionFactory(); } - ConfigManager.worldsMap = newWorldsMap; + worldDataManager.applyConfiguration(newWorldsMap); isInitialized = true; } @@ -402,27 +403,38 @@ public class ConfigManager { } /** - * Set a property for all configurations. Might use with DataManager.clearConfigs if check-configurations might already be in use. + * Set a property for all configurations. Might use with + * DataManager.clearConfigs if check-configurations might already be in use. + * * @param path * @param value + * @deprecated For activation flags use the WorldDataManager. */ + @Deprecated public static synchronized void setForAllConfigs(String path, Object value){ - final Map newWorldsMap = new LinkedHashMap(ConfigManager.worldsMap); - for (final ConfigFile cfg : newWorldsMap.values()){ - cfg.set(path, value); + final IWorldDataManager worldMan = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + final Iterator> it = worldMan.getWorldDataIterator(); + while (it.hasNext()) { + it.next().getValue().getRawConfiguration().set(path, value); } - ConfigManager.worldsMap = newWorldsMap; + worldMan.updateAllWorldData(); } /** * Check if any config has a boolean set to true for the given path. + *
    + * NOTE: Check activation flags need a query to the WorldDataManager, as + * MAYBE typically means to activate, if the parent is active (checks <- + * check group <- check (<- sub check)). * * @param path * @return True if any config has a boolean set to true for the given path. */ public static boolean isTrueForAnyConfig(String path) { - for (final ConfigFile cfg : worldsMap.values()){ - if (cfg.getBoolean(path, false)) { + final IWorldDataManager worldMan = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + final Iterator> it = worldMan.getWorldDataIterator(); + while (it.hasNext()){ + if (it.next().getValue().getRawConfiguration().getBoolean(path, false)) { return true; } } @@ -432,6 +444,10 @@ public class ConfigManager { /** * Check if any config has the path set to true, or to default in case * decideOptimistically is set, or not set in case trueForNotSet is set. + *
    + * NOTE: Check activation flags need a query to the WorldDataManager, as + * MAYBE typically means to activate, if the parent is active (checks <- + * check group <- check (<- sub check)). * * @param path * @param decideOptimistically @@ -439,8 +455,10 @@ public class ConfigManager { * @return */ public static boolean isAlmostTrueForAnyConfig(String path, boolean decideOptimistically, boolean trueForNotSet) { - for (final ConfigFile cfg : worldsMap.values()){ - if (cfg.getAlmostBoolean(path, decideOptimistically, trueForNotSet)) { + final IWorldDataManager worldMan = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + final Iterator> it = worldMan.getWorldDataIterator(); + while (it.hasNext()){ + if (it.next().getValue().getRawConfiguration().getAlmostBoolean(path, decideOptimistically, trueForNotSet)) { return true; } } @@ -455,8 +473,11 @@ public class ConfigManager { * @return Value or null. */ public static Double getMaxNumberForAllConfigs(final String path){ - Number max = null; - for (final ConfigFile config : worldsMap.values()){ + Number max = null; + final IWorldDataManager worldMan = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + final Iterator> it = worldMan.getWorldDataIterator(); + while (it.hasNext()){ + final ConfigFile config = it.next().getValue().getRawConfiguration(); try{ final Object obj = config.get(path); if (obj instanceof Number){ @@ -482,7 +503,10 @@ public class ConfigManager { */ public static Double getMinNumberForAllConfigs(final String path){ Number min = null; - for (final ConfigFile config : worldsMap.values()){ + final IWorldDataManager worldMan = NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + final Iterator> it = worldMan.getWorldDataIterator(); + while (it.hasNext()){ + final ConfigFile config = it.next().getValue().getRawConfiguration(); try{ final Object obj = config.get(path); if (obj instanceof Number){ diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/ExemptionContext.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/ExemptionContext.java index ea7683cc..462889e6 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/ExemptionContext.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/ExemptionContext.java @@ -1,3 +1,17 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package fr.neatmonster.nocheatplus.hooks; /** diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/ExemptionRegistry.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/ExemptionRegistry.java index 8df66e80..9c091fec 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/ExemptionRegistry.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/ExemptionRegistry.java @@ -1,3 +1,17 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package fr.neatmonster.nocheatplus.hooks; /** diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/NCPExemptionManager.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/NCPExemptionManager.java index 3180761e..a88864f6 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/NCPExemptionManager.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/NCPExemptionManager.java @@ -21,7 +21,7 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** * API for exempting players of checks, checked before calculations are done. @@ -95,7 +95,7 @@ public class NCPExemptionManager { * The check type. */ public static final void exemptPermanently(final UUID id, final CheckType checkType) { - final PlayerData data = DataManager.getPlayerData(id); + final IPlayerData data = DataManager.getPlayerData(id); if (data != null) { data.exempt(checkType); } @@ -140,7 +140,7 @@ public class NCPExemptionManager { * @return If the entity is exempted from checks right now. */ public static final boolean isExempted(final UUID id, final CheckType checkType) { - final PlayerData data = DataManager.getPlayerData(id); + final IPlayerData data = DataManager.getPlayerData(id); return data != null && data.isExempted(checkType); } @@ -192,7 +192,7 @@ public class NCPExemptionManager { * The check type. */ public static final void unexempt(final UUID id, final CheckType checkType) { - final PlayerData data = DataManager.getPlayerData(id); + final IPlayerData data = DataManager.getPlayerData(id); if (data != null) { data.unexempt(checkType); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/permissions/PermissionRegistry.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/permissions/PermissionRegistry.java index 53b36316..18307f92 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/permissions/PermissionRegistry.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/permissions/PermissionRegistry.java @@ -38,6 +38,13 @@ public class PermissionRegistry { // TODO: Suffix permissions, because it's tedious to define constants for them. Might auto register within somewhere else. + /* + * TODO: Per world (rule/proxy) registries, with one central registry for + * ids (per-world registries would proxy id registration, but have their own + * rule settings). THUS, have the rule registry as a common super class, an + * interface for the full thing. + */ + private int nextId; private final Lock lock = new ReentrantLock(); private PermissionSettings settings = new PermissionSettings(null, null, new PermissionPolicy()); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/DataManager.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/DataManager.java index 8fc896cb..4cb9199a 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/DataManager.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/DataManager.java @@ -14,443 +14,59 @@ */ package fr.neatmonster.nocheatplus.players; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.UUID; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.PlayerChangedWorldEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.checks.ViolationHistory; -import fr.neatmonster.nocheatplus.checks.access.CheckConfigFactory; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; -import fr.neatmonster.nocheatplus.checks.access.IRemoveSubCheckData; -import fr.neatmonster.nocheatplus.checks.combined.CombinedData; -import fr.neatmonster.nocheatplus.compat.BridgeMisc; -import fr.neatmonster.nocheatplus.compat.versions.BukkitVersion; -import fr.neatmonster.nocheatplus.compat.versions.GenericVersion; -import fr.neatmonster.nocheatplus.compat.versions.ServerVersion; -import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI; -import fr.neatmonster.nocheatplus.components.data.ICanHandleTimeRunningBackwards; -import fr.neatmonster.nocheatplus.components.registry.ComponentRegistry; -import fr.neatmonster.nocheatplus.components.registry.feature.ComponentWithName; -import fr.neatmonster.nocheatplus.components.registry.feature.ConsistencyChecker; -import fr.neatmonster.nocheatplus.components.registry.feature.IDisableListener; -import fr.neatmonster.nocheatplus.components.registry.feature.IHaveCheckType; -import fr.neatmonster.nocheatplus.components.registry.feature.INeedConfig; -import fr.neatmonster.nocheatplus.components.registry.feature.IRemoveData; -import fr.neatmonster.nocheatplus.components.registry.feature.TickListener; -import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterMethodWithOrder; -import fr.neatmonster.nocheatplus.components.registry.order.SetupOrder; -import fr.neatmonster.nocheatplus.config.ConfPaths; -import fr.neatmonster.nocheatplus.config.ConfigFile; -import fr.neatmonster.nocheatplus.config.ConfigManager; -import fr.neatmonster.nocheatplus.event.mini.MiniListener; -import fr.neatmonster.nocheatplus.logging.StaticLog; -import fr.neatmonster.nocheatplus.logging.Streams; -import fr.neatmonster.nocheatplus.permissions.PermissionPolicy; -import fr.neatmonster.nocheatplus.permissions.PermissionRegistry; -import fr.neatmonster.nocheatplus.permissions.PermissionSettings; -import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; -import fr.neatmonster.nocheatplus.players.PlayerMap.PlayerInfo; -import fr.neatmonster.nocheatplus.utilities.CheckTypeUtil; -import fr.neatmonster.nocheatplus.utilities.IdUtil; -import fr.neatmonster.nocheatplus.utilities.StringUtil; -import fr.neatmonster.nocheatplus.utilities.TickTask; -import fr.neatmonster.nocheatplus.utilities.ds.corw.DualSet; -import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW; + /** - * Central access point for a lot of functionality for managing data, especially - * removing data for cleanup.
    - * Originally intended as temporary or intermediate design, this might help - * reorganizing the API at some point.
    - * 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. - *
    - * ComponentRegistry: - *
  • Supported: IRemoveData
  • + * Static access API remaining from the previous mix of static/non-static. * - * @author mc_dev + * Will be moved or removed. + * + * @author asofold * */ -@SetupOrder(priority = -80) -public class DataManager implements INeedConfig, ComponentRegistry, ComponentWithName, ConsistencyChecker, IDisableListener{ +public class DataManager { + /* + * TODO: Detach (I)PlayerDataManager, DataManager remains (legacy?) static + * API... NCPStatic or so will be the "direct" static API, if at all. + */ // TODO: Should/can some data structures share the same lock? - private static DataManager instance = null; - - // Not static - private int foundInconsistencies = 0; - - /** PlayerData storage. */ - private final HashMapLOW playerData = new HashMapLOW(100); - - /** Primary thread only (no lock for this field): UUIDs to remove upon next bulk removal. */ - private final Set bulkPlayerDataRemoval = new LinkedHashSet(); - - private final DualSet frequentPlayerTasks = new DualSet(); + private static PlayerDataManager instance = null; /** - * Access order for playerName (exact) -> ms time of logout. - *
    - * Later this might hold central player data objects instead of the long - * only. + * Clear all cached CheckConfig instances.
    + * This does not cleanup ConfigManager, i.e. stored yml-versions. */ - private final Map lastLogout = new LinkedHashMap(50, 0.75f, true); - - /** - * Keeping track of online players. Currently id/name mappings are not kept - * on logout, but might be later. - */ - // TODO: Switch to UUIDs as keys, get data by uuid when possible, use PlayerMap for getting the UUID. - private final PlayerMap playerMap; - - /** - * IRemoveData instances. - */ - // TODO: might use a map for those later (extra or not). - private final ArrayList iRemoveData = new ArrayList(); - - /** - * Execution histories of the checks. - */ - // TODO: Move to PlayerData / CheckTypeTree (NodeS). - private final Map> executionHistories = new HashMap>(); - - /** Flag if data expiration is active at all. */ - private boolean doExpireData = false; - - /** - * Duration in milliseconds for expiration of logged off players data. In - * the config minutes are used as unit. - */ - private long durExpireData = 0; - - /** Data and execution history. */ - private boolean deleteData = true; - /** Violation history and execution history. */ - private boolean deleteHistory = false; - - /** - * Reference for passing to PlayerData for handling permission caching and - * policies. - */ - // TODO: Per world registries, update with world change (!). - private final PermissionRegistry permissionRegistry; - - private final TickListener tickListener = new TickListener() { - - private int delayRareTasks = 0; - - @Override - public void onTick(final int tick, final long timeLast) { - if (rareTasks(tick, timeLast)) { - delayRareTasks = 10; + public static void clearConfigs() { + // TODO: general DataManager thing, otherwise it's now a WorldDataManager thing. + final Set factories = new LinkedHashSet(); + for (final CheckType checkType : CheckType.values()) { + final CheckConfigFactory factory = checkType.getConfigFactory(); + if (factory != null) { + factories.add(factory); } - else { - if (delayRareTasks == 0) { - } - else { - delayRareTasks --; - } - } - frequentTasks(tick, timeLast); } - }; - - private final MiniListener[] miniListeners = new MiniListener[] { - /* - * TODO: Constants in a class 'ListenerTags', plus a plan - * (system.data.player.nocheatplus, system.nocheatplus.data ??, - * nocheatplus.system.data.player...). (RegistryTags for other?). - */ - new MiniListener() { - @Override - @EventHandler(priority = EventPriority.MONITOR) - @RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = ".*") - public void onEvent(final PlayerQuitEvent event) { - playerLeaves(event.getPlayer()); - } - }, - new MiniListener() { - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - @RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = ".*") - public void onEvent(final PlayerKickEvent event) { - playerLeaves(event.getPlayer()); - } - }, - new MiniListener() { - @EventHandler(priority = EventPriority.LOWEST) - @RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", beforeTag = ".*") - public void onEvent(final PlayerJoinEvent event) { - playerJoins(event); - } - }, - new MiniListener() { - @EventHandler(priority = EventPriority.LOWEST) - @RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = ".*") - public void onEvent(final PlayerChangedWorldEvent event) { - playerChangedWorld(event); - } - }, - }; - - /** - * Sets the static instance reference. - */ - public DataManager(final PermissionRegistry permissionRegistry) { - instance = this; - if (ServerVersion.isMinecraftVersionUnknown()) { - // True hacks. - BukkitVersion.init(); - } - final String version = ServerVersion.getMinecraftVersion(); - if (GenericVersion.compareVersions(version, "1.8") >= 0 || version.equals("1.7.10") && Bukkit.getServer().getVersion().toLowerCase().indexOf("spigot") != -1) { - // Safe to assume Spigot, don't store Player instances. - playerMap = new PlayerMap(false); - } - else { - // Likely an older version without efficient mapping. - playerMap = new PlayerMap(true); - } - this.permissionRegistry = permissionRegistry; - } - - /** - * Check the logged out players for if any data can be removed.
    - * Currently only "dumb" full removal is performed. Later it is thinkable to - * remove "as much as reasonable". - */ - public void checkExpiration() { - if (!doExpireData || durExpireData <= 0) { - return; - } - final long now = System.currentTimeMillis(); - final Set factories = new LinkedHashSet(); - final Set> entries = lastLogout.entrySet(); - final Iterator> iterator = entries.iterator(); - while (iterator.hasNext()) { - final Entry entry = iterator.next(); - final long ts = entry.getValue(); - if (now - ts <= durExpireData) { - break; - } - final UUID playerId = entry.getKey(); - // TODO: LEGACY handling: switch to UUIDs here for sure. - legacyPlayerDataExpirationRemovalByName(playerId, factories, deleteData); - bulkPlayerDataRemoval.add(playerId); // For bulk removal. - iterator.remove(); - } - // Bulk removal of PlayerData. - if (!bulkPlayerDataRemoval.isEmpty()) { - doBulkPlayerDataRemoval(); // Using this method allows checking for delayed removal etc. + for (final CheckConfigFactory factory : factories) { + factory.removeAllConfigs(); } } - private final void legacyPlayerDataExpirationRemovalByName(final UUID playerId, - final Set factories, final boolean deleteData) { - final String playerName = DataManager.getPlayerName(playerId); - if (playerName == null) { - // TODO: WARN - return; - } - // TODO: Validity of name? - if (deleteData) { - factories.clear(); - for (final CheckType type : CheckType.values()) { - final CheckDataFactory factory = type.getDataFactory(); - if (factory != null) { - factories.add(factory); - } - } - for (final CheckDataFactory factory : factories) { - factory.removeData(playerName); - } - clearComponentData(CheckType.ALL, playerName); - } - if (deleteData || deleteHistory) { - removeExecutionHistory(CheckType.ALL, playerName); - } - if (deleteHistory) { - ViolationHistory.removeHistory(playerName); - } - } - - /** - * Called by the rareTasksListener (OnDemandTickListener). - * @return "Did something" - true if data was removed or similar, i.e. reset the removal delay counter. False if nothing relevant had been done. - */ - private final boolean rareTasks(final int tick, final long timeLast) { - boolean something = false; - if (!bulkPlayerDataRemoval.isEmpty()) { - doBulkPlayerDataRemoval(); - something = true; - } - // TODO: Process rarePlayerTasks - return something; - } - - /** - * On tick. - */ - private final void frequentTasks(final int tick, final long timeLast) { - frequentPlayerTasks.mergePrimaryThread(); - final Iterator it = frequentPlayerTasks.iteratorPrimaryThread(); - while (it.hasNext()) { - final PlayerData pData = getOrCreatePlayerData(it.next(), null, false); - if (pData.processTickFrequent(tick, timeLast)) { - it.remove(); - } - } - } - - /** - * Primary thread only. This checks for if players are/should be online. - */ - private final void doBulkPlayerDataRemoval() { - int size = bulkPlayerDataRemoval.size(); - if (size > 0) { - // Test for online players. - final Iterator it = bulkPlayerDataRemoval.iterator(); - while (it.hasNext()) { - final UUID playerId = it.next(); - boolean skip = !lastLogout.containsKey(playerId); - // TODO: Also remove fake players, thus test for logged in too. - /* - * TODO: Multi stage removal: (1) non essential like permission - * cache, (2) essential like set-back location, (3) all. In - * addition things will get shifty, once we use PlayerData - * during asynchronous login - possibly we'll need parked data - * then, also considering offline servers. - */ - if (skip) { - it.remove(); - size --; - final PlayerData data = playerData.get(playerId); - if (data != null) { - // Should be online, keep essential data. - data.removeData(true); - } - continue; - } - } - // Actually remove data. - if (size > 0) { - playerData.remove(bulkPlayerDataRemoval); - bulkPlayerDataRemoval.clear(); - if (ConfigManager.getConfigFile().getBoolean(ConfPaths.LOGGING_EXTENDED_STATUS)) { - NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.STATUS, "Bulk PlayerData removal: " + size); - } - } - } - } /** * Get the exact player name, stored internally. * @param playerId */ public static String getPlayerName(final UUID playerId) { - final PlayerInfo info = instance.playerMap.getPlayerInfo(playerId); - if (info != null && info.exactName != null) { - return info.exactName; - } - final PlayerData data = instance.playerData.get(playerId); - if (data != null && data.playerName != null) { - return data.playerName; - } - return null; - } - - private void playerJoins(final PlayerJoinEvent event) { - final long timeNow = System.currentTimeMillis(); - final Player player = event.getPlayer(); - final UUID playerId = player.getUniqueId(); - lastLogout.remove(playerId); - final PlayerData pData = getOrCreatePlayerData(playerId, player.getName(), true); - pData.onPlayerJoin(timeNow); - CombinedData.getData(player).lastJoinTime = timeNow; - addOnlinePlayer(player); - } - - /** - * Quit or kick. - * @param player - */ - private void playerLeaves(final Player player) { - final long timeNow = System.currentTimeMillis(); - final UUID playerId = player.getUniqueId(); - lastLogout.put(playerId, timeNow); - final PlayerData pData = playerData.get(playerId); - if (pData != null) { - pData.onPlayerLeave(timeNow); - } - // TODO: put lastLogoutTime to PlayerData ! - CombinedData.getData(player).lastLogoutTime = timeNow; - removeOnlinePlayer(player); - } - - private void playerChangedWorld(final PlayerChangedWorldEvent event) { - final Player player = event.getPlayer(); - final UUID playerId = player.getUniqueId(); - final PlayerData pData = getOrCreatePlayerData(playerId, player.getName(), true); - pData.onPlayerChangedWorld(event.getFrom(), player.getWorld()); - } - - @Override - public void onReload() { - // present. - adjustSettings(); - } - - /** - * Fetch settings from the current default config. - */ - private void adjustSettings() { - final ConfigFile config = ConfigManager.getConfigFile(); - doExpireData = config.getBoolean(ConfPaths.DATA_EXPIRATION_ACTIVE); - durExpireData = config.getLong(ConfPaths.DATA_EXPIRATION_DURATION, 1, 1000000, 60) * 60000L; // in minutes - deleteData = config.getBoolean(ConfPaths.DATA_EXPIRATION_DATA, true); // hidden. - deleteHistory = config.getBoolean(ConfPaths.DATA_EXPIRATION_HISTORY); - // TODO: Per world permission registries: need world configs (...). - Set changedPermissions = null; - try { - // TODO: Only update if changes are there - should have a config-path hash+size thing (+ setting). - changedPermissions = permissionRegistry.updateSettings(PermissionSettings.fromConfig(config, - ConfPaths.PERMISSIONS_POLICY_DEFAULT, ConfPaths.PERMISSIONS_POLICY_RULES)); - } - catch (Exception e) { - StaticLog.logSevere("Failed to read the permissions setup. Relay to ALWAYS policy."); - StaticLog.logSevere(e); - permissionRegistry.updateSettings(new PermissionSettings(null, null, new PermissionPolicy())); - } - // Invalidate all already fetched permissions. - final Iterator> it = playerData.iterator(); - while (it.hasNext()) { - it.next().getValue().adjustSettings(changedPermissions); - } + return instance.getPlayerName(playerId); } /** @@ -459,9 +75,10 @@ public class DataManager implements INeedConfig, ComponentRegistry, * * @param type * @param histories + * @deprecated New implementation pending. */ public static void registerExecutionHistory(CheckType type, Map histories) { - instance.executionHistories.put(type, histories); + instance.registerExecutionHistory(type, histories); } /** @@ -471,13 +88,10 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @param playerName * Exact case for player name. * @return null if not present. + * @deprecated New implementation pending. */ public static ExecutionHistory getExecutionHistory(final CheckType type, final String playerName) { - final Map map = instance.executionHistories.get(type); - if (map != null) { - return map.get(playerName); - } - return null; + return instance.getExecutionHistory(type, playerName); } /** @@ -486,17 +100,10 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @param type * @param playerName * @return + * @deprecated New implementation pending. */ public static boolean removeExecutionHistory(final CheckType type, final String playerName) { - boolean removed = false; - // TODO: design ... - for (final CheckType refType : CheckTypeUtil.getWithDescendants(type)) { - final Map map = instance.executionHistories.get(refType); - if (map != null && map.remove(playerName) != null) { - removed = true; - } - } - return removed; + return instance.removeExecutionHistory(type, playerName); } /** @@ -506,38 +113,7 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @param checkType */ public static void clearData(final CheckType checkType) { - final Set factories = new HashSet(); - for (final CheckType type : CheckTypeUtil.getWithDescendants(checkType)) { - final Map map = instance.executionHistories.get(type); - if (map != null) { - map.clear(); - } - final CheckDataFactory factory = type.getDataFactory(); - if (factory != null) { - factories.add(factory); - } - } - for (final CheckDataFactory factory : factories) { - // TODO: Support precise removal ? - factory.removeAllData(); - } - for (final IRemoveData rmd : instance.iRemoveData) { - if (checkType == CheckType.ALL) { - // Not sure this is really good, though. - rmd.removeAllData(); - } - else if (rmd instanceof IHaveCheckType) { - final CheckType refType = ((IHaveCheckType) rmd).getCheckType(); - if (refType == checkType || CheckTypeUtil.isAncestor(checkType, refType)) { - rmd.removeAllData(); - } - } - } - ViolationHistory.clear(checkType); - if (checkType == CheckType.ALL) { - instance.bulkPlayerDataRemoval.addAll(instance.playerData.getKeys()); - instance.doBulkPlayerDataRemoval(); // Only removes offline player data. - } + instance.clearData(checkType); } /** @@ -547,40 +123,8 @@ public class DataManager implements INeedConfig, ComponentRegistry, * which implement this. */ public static void handleSystemTimeRanBackwards() { - // Collect data factories and clear execution history. - final Set factories = new HashSet(); - for (final CheckType type : CheckTypeUtil.getWithDescendants(CheckType.ALL)) { - final Map map = instance.executionHistories.get(type); - if (map != null) { - map.clear(); - } - final CheckDataFactory factory = type.getDataFactory(); - if (factory != null) { - factories.add(factory); - } - } - for (final CheckDataFactory factory : factories) { - if (factory instanceof ICanHandleTimeRunningBackwards) { - ((ICanHandleTimeRunningBackwards) factory).handleTimeRanBackwards(); - } - else { - factory.removeAllData(); - } - } - for (final IRemoveData rmd : instance.iRemoveData) { - if (rmd instanceof ICanHandleTimeRunningBackwards) { - ((ICanHandleTimeRunningBackwards) rmd).handleTimeRanBackwards(); - } - else { - rmd.removeAllData(); - } - } - ViolationHistory.clear(CheckType.ALL); - // PlayerData - final Iterator> it = instance.playerData.iterator(); - while (it.hasNext()) { - it.next().getValue().handleTimeRanBackwards(); - } + // TODO: Non static call from core plugin ? + instance.handleSystemTimeRanBackwards(); } /** @@ -588,33 +132,11 @@ public class DataManager implements INeedConfig, ComponentRegistry, * corresponding configurations. This only yields the correct result, if the * the data uses the same configuration for initialization which is * registered under the same check type. + * + * @TODO Explain the java-docs at some point. */ public static void restoreDefaultDebugFlags() { - final Player[] players = BridgeMisc.getOnlinePlayers(); - for (final CheckType checkType : CheckType.values()) { - final CheckConfigFactory configFactory = checkType.getConfigFactory(); - if (configFactory == null) { - continue; - } - final CheckDataFactory dataFactory = checkType.getDataFactory(); - if (dataFactory == null) { - continue; - } - for (int i = 0; i < players.length; i++) { - final Player player = players[i]; - final ICheckConfig config = configFactory.getConfig(player); - if (config == null) { - continue; - } - final ICheckData data = dataFactory.getData(player); - if (data == null) { - continue; - } - if (config.getDebug() != data.getDebug()) { - data.setDebug(config.getDebug()); - } - } - } + instance.restoreDefaultDebugFlags(); } /** @@ -628,94 +150,7 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @return If any data was present. */ public static boolean removeData(final String playerName, CheckType checkType) { - - final PlayerData pd = getPlayerData(playerName); - // TODO: Once working, use the most correct name from PlayerData. - final UUID playerId = pd == null ? getUUID(playerName) : pd.playerId; - - if (checkType == null) { - checkType = CheckType.ALL; - } - boolean had = false; - - // Check extended registered components. - // TODO: "System data" might not be wise to erase for online players. - if (clearComponentData(checkType, playerName)) { - had = true; - } - - // Collect factories. - final Set factories = new HashSet(); - for (CheckType otherType : CheckTypeUtil.getWithDescendants(checkType)) { - final CheckDataFactory otherFactory = otherType.getDataFactory(); - if (otherFactory != null) { - factories.add(otherFactory); - } - } - // Remove data. - for (final CheckDataFactory factory : factories) { - if (removeDataPrecisely(playerId, playerName, checkType, factory)) { - had = true; - } - } - - if (checkType == CheckType.ALL) { - // TODO: Fetch/use UUID early, and check validity of name. - if (playerId != null) { - instance.bulkPlayerDataRemoval.add(playerId); - } - } - - return had; - } - - /** - * Attempt to only remove the data, relevant to the given CheckType. - * - * @param playerId - * @param playerName - * @param checkType - * @param factory - * @return If any data has been removed. - */ - private static boolean removeDataPrecisely(final UUID playerId, final String playerName, - final CheckType checkType, final CheckDataFactory factory) { - final ICheckData data = factory.getDataIfPresent(playerId, playerName); - if (data == null) { - return false; - } - else { - // Attempt precise removal. - final boolean debug = data.getDebug(); - String debugText = debug ? "[" + checkType + "] [" + playerName + "] Data removal: " : null; - boolean res = false; - if (data instanceof IRemoveSubCheckData - && ((IRemoveSubCheckData) data).removeSubCheckData(checkType)) { - if (debug) { - debugText += "Removed (sub) check data, keeping the data object."; - } - res = true; - } - else { - // Just remove. - if (factory.removeData(playerName) == null) { - // Is this even possible? - if (debug) { - debugText += "Could not remove data, despite present!"; - } - } - else { - if (debug) { - debugText += "Removed the entire data object."; - } - res = true; - } - } - if (debug) { - NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, debugText); - } - return res; - } + return instance.removeData(playerName, checkType); } /** @@ -728,41 +163,8 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @return If something was removed. */ public static boolean clearComponentData(final CheckType checkType, final String PlayerName) { - boolean removed = false; - for (final IRemoveData rmd : instance.iRemoveData) { - if (checkType == CheckType.ALL) { - // Not sure this is really good, though. - if (rmd.removeData(PlayerName) != null) { - removed = true; - } - } - else if (rmd instanceof IHaveCheckType) { - final CheckType refType = ((IHaveCheckType) rmd).getCheckType(); - if (refType == checkType || CheckTypeUtil.isAncestor(checkType, refType)) { - if (rmd.removeData(PlayerName) != null) { - removed = true; - } - } - } - } - return removed; - } - - /** - * Clear all cached CheckConfig instances.
    - * This does not cleanup ConfigManager, i.e. stored yml-versions. - */ - public static void clearConfigs() { - final Set factories = new LinkedHashSet(); - for (final CheckType checkType : CheckType.values()) { - final CheckConfigFactory factory = checkType.getConfigFactory(); - if (factory != null) { - factories.add(factory); - } - } - for (final CheckConfigFactory factory : factories) { - factory.removeAllConfigs(); - } + // TODO: UUID. + return instance.clearComponentData(checkType, PlayerName); } /** @@ -773,7 +175,7 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @return */ public static Player getPlayerExact(final String playerName) { - return instance.playerMap.getPlayerExact(playerName); + return instance.getPlayerExact(playerName); } /** @@ -785,12 +187,7 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @return */ public static UUID getUUID(final String input) { - // TODO: Use player map. - final Player player = getPlayer(input); - if (player != null) { - return player.getUniqueId(); - } - return IdUtil.UUIDFromStringSafe(input); + return instance.getUUID(input); } /** @@ -800,7 +197,7 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @return */ public static Player getPlayer(final UUID id) { - return instance.playerMap.getPlayer(id); + return instance.getPlayer(id); } /** @@ -811,151 +208,7 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @return */ public static Player getPlayer(final String playerName) { - return instance.playerMap.getPlayer(playerName); - } - - @Override - public boolean addComponent(IRemoveData obj) { - if (iRemoveData.contains(obj)) { - return false; - } - else { - iRemoveData.add((IRemoveData) obj); - return true; - } - } - - @Override - public void removeComponent(IRemoveData obj) { - iRemoveData.remove((IRemoveData) obj); - } - - /** - * Initializing with online players. - */ - public void onEnable() { - TickTask.addTickListener(tickListener); - final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI(); - for (final MiniListener listener : miniListeners) { - api.addComponent(listener, false); - } - for (final Player player : BridgeMisc.getOnlinePlayers()) { - addOnlinePlayer(player); - } - } - - /** - * Cleanup method, removes all data and config, but does not call - * ConfigManager.cleanup. - */ - @Override - public void onDisable() { - // TODO: Process pending set backs etc. -> iterate playerData -> onDisable. - clearData(CheckType.ALL); - playerData.clear(); // Also clear for online players. - iRemoveData.clear(); - clearConfigs(); - lastLogout.clear(); - executionHistories.clear(); - playerMap.clear(); - // Finally alert (summary) if inconsistencies found. - if (foundInconsistencies > 0) { - StaticLog.logWarning("DataMan found " + foundInconsistencies + " inconsistencies (warnings suppressed)."); - foundInconsistencies = 0; - } - } - - /** - * Add mappings for player names variations. - * @param player - */ - private void addOnlinePlayer(final Player player) { - playerMap.updatePlayer(player); - } - - /** - * Remove mappings for player names variations. - * @param player - */ - private void removeOnlinePlayer(final Player player) { - // TODO: Consider to only remove the Player instance? Yes do so... and remove the mapping if the full data expires only. - playerMap.remove(player); - } - - @Override - public String getComponentName() { - return "NoCheatPlus_DataManager"; - } - - @Override - public void checkConsistency(final Player[] onlinePlayers) { - // Check online player tracking consistency. - int missing = 0; - int changed = 0; - for (int i = 0; i < onlinePlayers.length; i++) { - final Player player = onlinePlayers[i]; - final UUID id = player.getUniqueId(); - // if (player.isOnline()) { - // TODO: Add a consistency check method !? - if (!playerMap.hasPlayerInfo(id)) { - missing ++; - // TODO: Add the player [problem: messy NPC plugins?]? - } - if (playerMap.storesPlayerInstances() && player != playerMap.getPlayer(id)) { - changed ++; - // Update the reference. - addOnlinePlayer(player); - // } - } - } - - // TODO: Consider checking lastLogout for too long gone players. - - // TODO: Later the map size will not work, if we keep name/id mappings after logout. Other checking methods are possible. - final int storedSize = this.playerMap.size(); - if (missing != 0 || changed != 0 || onlinePlayers.length != storedSize) { - foundInconsistencies ++; - if (!ConfigManager.getConfigFile().getBoolean(ConfPaths.DATA_CONSISTENCYCHECKS_SUPPRESSWARNINGS)) { - final List details = new LinkedList(); - if (missing != 0) { - details.add("missing online players (" + missing + ")"); - } - if (onlinePlayers.length != storedSize) { - // TODO: Consider checking for not online players and remove them. - details.add("wrong number of online players (" + storedSize + " instead of " + onlinePlayers.length + ")"); - } - if (changed != 0) { - details.add("changed player instances (" + changed + ")"); - } - - StaticLog.logWarning("DataMan inconsistencies: " + StringUtil.join(details, " | ")); - } - } - } - - /** - * GetOrCreate means controlled by a flag in this case. - *
    - * Future may be to get rid of the static methods here, which may exist - * within NCPStaticSomething then. - * - * @param playerId - * @param playerName - * @param create - * Create if not present. - * @return - */ - public PlayerData getOrCreatePlayerData(final UUID playerId, final String playerName, final boolean create) { - final PlayerData data = playerData.get(playerId); - if (!create || data != null) { - return data; - } - else { - // Creating this should be mostly harmless. - final PlayerData newData = new PlayerData(playerId, playerName, permissionRegistry); - final PlayerData oldData = playerData.putIfAbsent(playerId, newData); - return oldData == null ? newData : oldData; - } + return instance.getPlayer(playerName); } /** @@ -966,20 +219,8 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @param player * @return */ - public static PlayerData getPlayerData(final Player player) { - return getPlayerData(player.getUniqueId(), player.getName(), true); - } - - /** - * Get PlayerData instances, controlling if data is created, in case it is - * not present. - * - * @param playerName - * @param create - * @return - */ - public static PlayerData getPlayerData(final UUID playerId, final String playerName, final boolean create) { - return instance.getOrCreatePlayerData(playerId, playerName, create); + public static IPlayerData getPlayerData(final Player player) { + return instance.getPlayerData(player, true); } /** @@ -988,62 +229,48 @@ public class DataManager implements INeedConfig, ComponentRegistry, * @param playerName * @return The PlayerData instance if present, null otherwise. */ - public static PlayerData getPlayerData(final String playerName) { - final UUID playerId = getUUID(playerName); - return playerId == null ? null : instance.playerData.get(playerId); + public static IPlayerData getPlayerData(final String playerName) { + return instance.getPlayerData(playerName); } /** * Get the player data, if present. * - * @param playerID - * @return The PlayerData instance if present, null otherwise. - */ - public static PlayerData getPlayerData(final UUID playerID) { - return instance.playerData.get(playerID); - } - - /** - * Check if player instances are stored for efficiency (legacy). - * - * @return - */ - public boolean storesPlayerInstances() { - return playerMap.storesPlayerInstances(); - } - - /** - * Might yield false negatives, should be reasonable on performance. - * * @param playerId - * @return + * @return The PlayerData instance if present, null otherwise. */ - public static boolean isFrequentPlayerTaskScheduled(final UUID playerId) { - // TODO : Efficient impl / optimized methods? - if (Bukkit.isPrimaryThread()) { - return instance.frequentPlayerTasks.containsPrimaryThread(playerId); - } - else { - return instance.frequentPlayerTasks.containsAsynchronous(playerId); - } + public static IPlayerData getPlayerData(final UUID playerId) { + return instance.getPlayerData(playerId); } - protected static void registerFrequentPlayerTaskPrimaryThread(final UUID playerId) { - instance.frequentPlayerTasks.addPrimaryThread(playerId); + static boolean isFrequentPlayerTaskScheduled(final UUID playerId) { + return instance.isFrequentPlayerTaskScheduled(playerId); } - protected static void registerFrequentPlayerTaskAsynchronous(final UUID playerId) { - instance.frequentPlayerTasks.addAsynchronous(playerId); + static void registerFrequentPlayerTaskPrimaryThread(final UUID playerId) { + instance.registerFrequentPlayerTaskPrimaryThread(playerId); + } + + static void registerFrequentPlayerTaskAsynchronous(final UUID playerId) { + instance.registerFrequentPlayerTaskAsynchronous(playerId); } /** * */ public static void clearAllExemptions() { - final Iterator> it = instance.playerData.iterator(); - while (it.hasNext()) { - it.next().getValue().clearAllExemptions(); - } + instance.clearAllExemptions(); + } + + /** + * Convenience method, allowing to skip fetching PlayerData. + * + * @param player + * @param registeredFor + * @return + */ + public static T getGenericInstance(final Player player, final Class registeredFor) { + return instance.getPlayerData(player).getGenericInstance(registeredFor); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/IPlayerData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/IPlayerData.java new file mode 100644 index 00000000..e36952f9 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/IPlayerData.java @@ -0,0 +1,308 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.players; + +import java.util.UUID; + +import org.bukkit.entity.Player; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; +import fr.neatmonster.nocheatplus.components.data.IData; +import fr.neatmonster.nocheatplus.components.data.checktype.IBaseDataAccess; +import fr.neatmonster.nocheatplus.components.registry.IGetGenericInstance; +import fr.neatmonster.nocheatplus.hooks.ExemptionContext; +import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; +import fr.neatmonster.nocheatplus.worlds.IWorldData; +import fr.neatmonster.nocheatplus.worlds.WorldIdentifier; + +public interface IPlayerData extends IData, IBaseDataAccess, IGetGenericInstance { + + /** + * Get the (supposedly exact) player name, as had been passed at the time of + * object creation. + * + * @return + */ + public String getPlayerName(); + + /** + * Get the player name in lower case, as had been passed at the time of + * object creation. + * + * @return + */ + public String getPlayerNameLowerCase(); + + /** + * Get the unique id for the player. + * + * @return + */ + public UUID getPlayerId(); + + /** + * Get the System.currentTimeMillis() value from player join handling. + * + * @return + */ + public long getLastJoinTime(); + + /** + * Permission check (thread-safe, results and impact of asynchronous queries depends on + * settings +- TBD). + * + * @param registeredPermission Must not be null, must be registered. + * @param player + * May be null (if lucky the permission is set to static/timed + * and/or has already been fetched). + * @return + */ + public boolean hasPermission(final RegisteredPermission registeredPermission, final Player player); + + /** + * Request a permission cache update. + * @param registeredPermission + */ + public void requestPermissionUpdate(final RegisteredPermission registeredPermission); + + /** + * Low priority permission update for check type specific permissions. + * + * @param registeredPermissions + * May be null. + */ + public void requestLazyPermissionUpdate(final RegisteredPermission... registeredPermissions); + + /** + * Mimic legacy behavior (non-nested) - exempt including descendants + * recursively. Note that contexts other than + * ExemptionContext.LEGACY_NON_NESTED will not be touched. + * + * @param checkType + */ + public void exempt(final CheckType checkType); + + /** + * Mimic legacy behavior (non-nested) - unexempt including descendants + * recursively. Note that contexts other than + * ExemptionContext.LEGACY_NON_NESTED will not be touched. + *
    + * Primary thread and asynchronous access are separated and yield different + * results, it's imperative to always unexempt properly for asyncrhonous + * thread contexts, as isExempted reflects a mixture of both. + * + * @param checkType + */ + public void unexempt(final CheckType checkType); + + /** + * Exempt with reference to the given context with descendants recursively. + *
    + * Note that multiple calls to exempt demand multiple calls to + * unexempt(CheckType, ExemptionContext). + *
    + * Primary thread and asynchronous access are separated and yield different + * results, it's imperative to always unexempt properly for asyncrhonous + * thread contexts, as isExempted reflects a mixture of both. + * + * @param checkType + * @param context + */ + public void exempt(final CheckType checkType, final ExemptionContext context); + + /** + * Unexempt once, including descendants recursively.
    + * Note that for multiple calls to exempt with one context, multiple calls + * to unexempt with that context may be necessary to fully unexempt, or call + * unexemptAll for the context. + *
    + * ExemptionContext.LEGACY_NON_NESTED is not automatically calling + * unexemptAll as is done with the legacy signature unexempt(CheckType). + *
    + * Primary thread and asynchronous access are separated and yield different + * results, it's imperative to always unexempt properly for asyncrhonous + * thread contexts, as isExempted reflects a mixture of both. + * + * @param checkType + * @param context + */ + public void unexempt(final CheckType checkType, final ExemptionContext context); + + /** + * Remove all (potentially nested) entries context for the given checkType + * and descendants recursively. + *
    + * Primary thread and asynchronous access are separated and yield different + * results, it's imperative to always unexempt properly for asyncrhonous + * thread contexts, as isExempted reflects a mixture of both. + * + * @param checkType + * @param context + */ + public void unexemptAll(final CheckType checkType, final ExemptionContext context); + + /** + * Test for exemption. + *
    + * Thread-safe read (not synchronized). + * + * @param checkType + * @return + */ + public boolean isExempted(final CheckType checkType); + + /** + * Clear all exemptions, for all thread contexts. + *
    + * Call from the primary thread only. + */ + public void clearAllExemptions(); + + /** + * Clear all exemptions for the given checkType and descendants recursively, + * for all thread contexts. + *
    + * Call from the primary thread only. + * + * @param checkType + */ + public void clearAllExemptions(final CheckType checkType); + + /** + * Will get set on player join and world change. Currently NOT on login. + * + * @return + */ + public WorldIdentifier getCurrentWorldIdentifier(); + + /** + * Get the currently stored IWorldData instance. + * + * @return Might return null, if not initialized - to get the default world + * data in that case, use instead: + * {@link #getCurrentWorldDataSafe()} + */ + public IWorldData getCurrentWorldData(); + + /** + * Convenience method: Return the default world data, if currentWorldData is + * null. + * + * @return + */ + public IWorldData getCurrentWorldDataSafe(); + + /** + * Full activation check (configuration, exemption, permission). + * + * @param checkType + * @param player + * @return + */ + public boolean isCheckActive(final CheckType checkType, final Player player); + + /** + * Full activation check (configuration, exemption, permission). + * + * @param checkType + * @param player + * @param worldData + * @return + */ + public boolean isCheckActive(final CheckType checkType, final Player player, + final IWorldData worldData); + + /** + * Bypass check including exemption and permission. + * + * @param checkType + * @param player + * @return + */ + public boolean hasBypass(final CheckType checkType, final Player player); + + /** + * Reset to the current world data (or the default one). + */ + public void resetDebug(); + + /** + * Reset to the current world data (or the default one). + * + * @param checkType + */ + public void resetDebug(final CheckType checkType); + + /** + * Override debug flags. + * + * @param checkType + * @param active + * @param overrideType + * @param overrideChildren + */ + public void overrideDebug(final CheckType checkType, final AlmostBoolean active, + final OverrideType overrideType, final boolean overrideChildren); + + @Override + public T getGenericInstance(Class registeredFor); + + /** + * Remove data from the cache (not from underlying factories, nor from per + * world storage. + * + * @param registeredFor + */ + public void removeGenericInstance(Class registeredFor); + + /** + * Check if notifications are turned off, this does not bypass permission + * checks. + * + * @return + */ + public boolean getNotifyOff(); + + /** + * Allow or turn off notifications. A player must have the admin.notify + * permission to receive notifications. + * + * @param notifyOff + * set to true to turn off notifications. + */ + public void setNotifyOff(final boolean notifyOff); + + /** + * Let the inventory be updated (run in TickTask). + */ + public void requestUpdateInventory(); + + /** + * Let the player be set back to the location stored in moving data (run in + * TickTask). Only applies if it's set there. + */ + public void requestPlayerSetBack(); + + /** + * Test if it's set to process a player set back on tick. This does not + * check MovingData.hasTeleported(). + * + * @return + */ + public boolean isPlayerSetBackScheduled(); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/IPlayerDataManager.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/IPlayerDataManager.java new file mode 100644 index 00000000..acd93ff4 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/IPlayerDataManager.java @@ -0,0 +1,144 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.players; + +import java.util.UUID; + +import org.bukkit.entity.Player; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.components.registry.ComponentRegistry; +import fr.neatmonster.nocheatplus.components.registry.feature.IRemoveData; + +/** + * Player data specific operations. + *
    + * ComponentRegistry: + *
  • Supported: IRemoveData
  • + * + * @author asofold + * + */ +public interface IPlayerDataManager extends ComponentRegistry { + + // TODO: Complete (...) + + /** + * Fetch a PlayerData instance. If none is present and create is set, a new + * instance will be created. + * + * @param player + * @param create + * @return + */ + public IPlayerData getPlayerData(final Player player, boolean create); + + /** + * Get a PlayerData instance in any case - always creates a PlayerData + * instance, if none is present. This method should be preferred, as it + * hides details. + * + * @param player + * @return + */ + public IPlayerData getPlayerData(final Player player); + + /** + * Get the player data, if present. + * + * @param playerId + * @return The PlayerData instance if present, null otherwise. + */ + public IPlayerData getPlayerData(final UUID playerId); + + /** + * Get the player data, if present. + * + * @param playerName + * @return The PlayerData instance if present, null otherwise. + */ + public IPlayerData getPlayerData(final String playerName); + + /** + * This gets an online player by exact player name or lower-case player name + * only [subject to change]. + * + * @param playerName + * @return + */ + public Player getPlayerExact(final String playerName); + + /** + * Retrieve the UUID for a given input (name or UUID string of with or + * without '-'). Might later also query a cache, if appropriate. Convenience + * method for use with commands. + * + * @param input + * @return + */ + public UUID getUUID(final String input); + + /** + * Get the exact player name, stored internally. + * + * @param playerId + */ + public String getPlayerName(final UUID playerId); + + /** + * Get an online player by UUID. + * + * @param id + * @return + */ + public Player getPlayer(final UUID id); + + /** + * This gets the online player with the exact name, but transforms the input + * to lower case. + * + * @param playerName + * @return + */ + public Player getPlayer(final String playerName); + + /** + * Restore the default debug flags within player data, as given in + * corresponding configurations. This only yields the correct result, if the + * the data uses the same configuration for initialization which is + * registered under the same check type. + */ + public void restoreDefaultDebugFlags(); + + /** + * Remove an instance from the PlayerData-local generic instance storage, + * for all stored PlayerData instances. Factories and proxy-registries are + * not touched. + * + * @param registeredFor + */ + public void removeGenericInstance(Class registeredFor); + + public void clearAllExemptions(); + + /** + * Remove data and history of all players for the given check type and sub + * checks. + * + * @param checkType + */ + public void clearData(final CheckType checkType); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerCheckTypeTree.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerCheckTypeTree.java index 7f4ccae2..9ce6cb98 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerCheckTypeTree.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerCheckTypeTree.java @@ -1,3 +1,17 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package fr.neatmonster.nocheatplus.players; import java.util.Collections; @@ -8,14 +22,20 @@ import java.util.concurrent.locks.Lock; import org.bukkit.Bukkit; import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; +import fr.neatmonster.nocheatplus.components.data.checktype.CheckNodeWithDebug; import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree; -import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree.CheckTypeTreeNode; +import fr.neatmonster.nocheatplus.components.data.checktype.IBaseCheckNode; +import fr.neatmonster.nocheatplus.config.ConfigFile; import fr.neatmonster.nocheatplus.hooks.ExemptionContext; import fr.neatmonster.nocheatplus.players.PlayerCheckTypeTree.PlayerCheckTypeTreeNode; +import fr.neatmonster.nocheatplus.worlds.IWorldCheckNode; +import fr.neatmonster.nocheatplus.worlds.IWorldData; /** *
    - * Exemption and unexemption are handled within two contexts: primary thread and + * Exempting and unexempting are handled within two contexts: primary thread and * asynchronous. Exemption testing may account for both states (without * synchronization). * @@ -34,7 +54,9 @@ public class PlayerCheckTypeTree extends CheckTypeTree{ * @author asofold * */ - static class PlayerCheckTypeTreeNode extends CheckTypeTreeNode { + static class PlayerCheckTypeTreeNode extends CheckNodeWithDebug implements IBaseCheckNode { + + // TODO: Compactify flags? /** * Explicitly exempted by API call (cumulative flag), excludes checking for @@ -169,13 +191,79 @@ public class PlayerCheckTypeTree extends CheckTypeTree{ /** * Primary thread only, must call under lock. */ - public void clearAllExemptions() { + void clearAllExemptions() { exemptedAsynchronous = false; exemptedPrimaryThread = false; exemptionsAsynchronous = null; exemptionsPrimaryThread = null; } + /** + * Set configDebug recursively and then update. + * + * @param worldData + */ + void updateDebug(final IWorldData worldData) { + setDebugNoUpdate(worldData); + updateDebug(worldData.getRawConfiguration()); + } + + /** + * Recursively set configDebug, no update. + * + * @param worldData + */ + private void setDebugNoUpdate(final IWorldData worldData) { + final IWorldCheckNode worldNode = worldData.getCheckNode(getCheckType()); + // Just adjust recursively. + // TODO: Simplicity of interface: hard set to the resulting value. + configDebug.setValue(worldNode.isDebugActive(), worldNode.getOverrideTypeDebug()); + for (final PlayerCheckTypeTreeNode node : getChildren()) { + node.updateDebug(worldData); + } + } + + /** + * Update to given configuration. + * + * @param rawConfiguration + */ + @SuppressWarnings("unchecked") + void updateDebug(ConfigFile rawConfiguration) { + configFlagUpdate(rawConfiguration, true, accessDebug); + } + + /** + * Hard-reset the debug properties to the underlying IWorldData instance. + * + * @param worldData + */ + void resetDebug(final IWorldData worldData) { + resetDebugNoUpdate(worldData); + updateDebug(worldData.getRawConfiguration()); + } + + private void resetDebugNoUpdate(IWorldData worldData) { + final IWorldCheckNode worldNode = worldData.getCheckNode(getCheckType()); + // Just adjust recursively. + // TODO: Simplicity of interface: hard set to the resulting value. + /* + * TODO: Itchy/modeling: A permanent override for a player gets + * reset by a permanent override for a world. + */ + configDebug.resetValue(worldNode.isDebugActive(), worldNode.getOverrideTypeDebug()); + for (final PlayerCheckTypeTreeNode node : getChildren()) { + node.resetDebugNoUpdate(worldData); + } + } + + @SuppressWarnings("unchecked") + void overrideDebug(final ConfigFile rawConfiguration, + final CheckType checkType, final AlmostBoolean active, + final OverrideType overrideType, final boolean overrideChildren) { + configFlagOverride(rawConfiguration, active, overrideType, overrideChildren, accessDebug); + } + } //////////////// diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerData.java index cf9de11f..4b411faf 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerData.java @@ -28,12 +28,14 @@ import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; +import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.moving.util.MovingUtil; import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; import fr.neatmonster.nocheatplus.components.data.ICanHandleTimeRunningBackwards; -import fr.neatmonster.nocheatplus.components.data.IData; import fr.neatmonster.nocheatplus.hooks.ExemptionContext; +import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager; import fr.neatmonster.nocheatplus.permissions.PermissionInfo; import fr.neatmonster.nocheatplus.permissions.PermissionNode; import fr.neatmonster.nocheatplus.permissions.PermissionPolicy.FetchingPolicy; @@ -43,6 +45,9 @@ import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.ds.corw.DualSet; import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW; +import fr.neatmonster.nocheatplus.worlds.IWorldData; +import fr.neatmonster.nocheatplus.worlds.WorldDataManager; +import fr.neatmonster.nocheatplus.worlds.WorldIdentifier; /** * Central player-specific data object. @@ -80,13 +85,9 @@ import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW; * @author asofold * */ -public class PlayerData implements IData, ICanHandleTimeRunningBackwards { +public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards { - /* - * TODO: Still consider interfaces, even if this is the only implementation. - * E.g. for requesting on-tick action, permission-related, (check-) - * data-related. - */ + // TODO: IPlayerData for the more official API. /** Monitor player task load across all players (nanoseconds per server tick). */ private static ActionFrequency taskLoad = new ActionFrequency(6, 7); @@ -128,13 +129,18 @@ public class PlayerData implements IData, ICanHandleTimeRunningBackwards { * uncertain when/how to access. */ /** Unique id of the player. */ - final UUID playerId; + private final UUID playerId; - // TODO: Names should get updated. (In which case) + // TODO: Names could/should get updated. (In which case?) /** Exact case name of the player. */ - final String playerName; + private final String playerName; /** Lower case name of the player. */ - final String lcName; + private final String lcName; + + private long lastJoinTime = 0; + + /** The IWorldData instance of the current world (at least while online). */ + private IWorldData currentWorldData = null; /* * TODO: Flags/counters for (async-login,) login, join, 'online', kick, quit @@ -189,7 +195,7 @@ public class PlayerData implements IData, ICanHandleTimeRunningBackwards { * @param timeLast * @return True, of the listener is to be removed, false otherwise. */ - protected boolean processTickFrequent(final int tick, final long timeLast) { + boolean processTickFrequent(final int tick, final long timeLast) { if (frequentTaskDelayUnregister == 0) { frequentTaskDelayUnregister = frequentTaskUnregisterDefaultDelay; } @@ -243,7 +249,7 @@ public class PlayerData implements IData, ICanHandleTimeRunningBackwards { // Set back. if (requestPlayerSetBack) { requestPlayerSetBack = false; - MovingUtil.processStoredSetBack(player, "Player set back on tick: "); + MovingUtil.processStoredSetBack(player, "Player set back on tick: ", this); } // Inventory update. if (requestUpdateInventory) { @@ -326,16 +332,187 @@ public class PlayerData implements IData, ICanHandleTimeRunningBackwards { return DataManager.isFrequentPlayerTaskScheduled(playerId); } + private PermissionNode getOrCreatePermissionNode(final RegisteredPermission registeredPermission) { + // Optimistic creation (concurrency). + final PermissionNode node = new PermissionNode(permissionRegistry.getPermissionInfo(registeredPermission.getId())); + final PermissionNode oldNode = permissions.putIfAbsent(registeredPermission.getId(), node); + return oldNode == null ? node : oldNode; + } + /** - * Permission check (thread-safe, results and impact of asynchronous queries depends on - * settings +- TBD). + * Fetch the permission hard, no putting to cache, just return the result. + * For off-primary-server-thread access, this will wait for a + * BukkitRunnable/TickTask task to finish, at an extraordinary performance + * penalty. * - * @param registeredPermission Must not be null, must be registered. + * @param registeredPermission * @param player - * May be null (if lucky the permission is set to static/timed - * and/or has already been fetched). - * @return + * @return MAYBE in case permissions could not be fetched or */ + private AlmostBoolean fetchPermission(final RegisteredPermission registeredPermission, Player player) { + if (Bukkit.isPrimaryThread()) { + if (player == null) { + player = DataManager.getPlayer(this.playerId); + if (player == null) { + return AlmostBoolean.MAYBE; + } + } + // Minimal update within the primary thread. + return player.hasPermission(registeredPermission.getBukkitPermission()) ? AlmostBoolean.YES : AlmostBoolean.NO; + } + else { + requestPermissionUpdate(registeredPermission); + /* + * TODO: UNCERTAIN: request related permission right away ? Inefficient in case of exemption. + * + */ + return AlmostBoolean.MAYBE; + } + } + + @Override + public void handleTimeRanBackwards() { + final Iterator> it = permissions.iterator(); + final long timeNow = System.currentTimeMillis(); + while (it.hasNext()) { + final PermissionNode node = it.next().getValue(); + switch (node.getFetchingPolicy()) { + case INTERVAL: + node.invalidate(); + break; + case ONCE: + node.setState(node.getLastState(), timeNow); + break; + default: + // Ignore. + break; + } + } + } + + void requestPermissionUpdatePrimaryThread(final RegisteredPermission registeredPermission) { + // Might throw something :p. + updatePermissions.addPrimaryThread(registeredPermission); + registerFrequentPlayerTaskPrimaryThread(); + } + + void requestPermissionUpdateAsynchronous(final RegisteredPermission registeredPermission) { + updatePermissions.addAsynchronous(registeredPermission); + registerFrequentPlayerTaskAsynchronous(); + } + + private void requestLazyPermissionsUpdateNonEmpty(final RegisteredPermission... registeredPermissions) { + if (Bukkit.isPrimaryThread()) { + requestLazyPermissionUpdatePrimaryThread(registeredPermissions); + } + else { + requestLazyPermissionUpdateAsynchronous(registeredPermissions); + } + } + + void requestLazyPermissionUpdatePrimaryThread(final RegisteredPermission... registeredPermissions) { + // Might throw something :p. + updatePermissionsLazy.addAllPrimaryThread(Arrays.asList(registeredPermissions)); + registerFrequentPlayerTaskPrimaryThread(); + } + + void requestLazyPermissionUpdateAsynchronous(final RegisteredPermission... registeredPermissions) { + updatePermissionsLazy.addAllAsynchronous(Arrays.asList(registeredPermissions)); + registerFrequentPlayerTaskAsynchronous(); + } + + void onPlayerLeave(final long timeNow) { + invalidateOffline(); + } + + /** + * Early adaption on player join. + * + * @param world + * @param timeNow + */ + void onPlayerJoin(final World world, final long timeNow, + final WorldDataManager worldDataManager) { + // Only update world if the data hasn't just been created. + updateCurrentWorld(world, worldDataManager); + invalidateOffline(); + requestLazyPermissionUpdate(permissionRegistry.getPreferKeepUpdatedOffline()); + lastJoinTime = timeNow; + } + + private void updateCurrentWorld(final World world, + final WorldDataManager worldDataManager) { + updateCurrentWorld(worldDataManager.getWorldData(world)); + } + + /** + * Allow direct call from DataManager after object creation. + * + * @param worldData + */ + void updateCurrentWorld(final IWorldData worldData) { + // TODO: Consider storing last world too. + currentWorldData = worldData; + checkTypeTree.getNode(CheckType.ALL).updateDebug(worldData); + } + + private void invalidateOffline() { + final Iterator> it = permissions.iterator(); + // TODO: More efficient: get unmodifiable collection from registry? + while (it.hasNext()) { + final PermissionNode node = it.next().getValue(); + final PermissionInfo info = node.getPermissionInfo(); + if (info.invalidationOffline() + /* + * TODO: world based should only be invalidated with world + * changing. Therefore store the last world info + * (UUID/name?) in PlayerData and use on login for + * comparison. + */ + || info.invalidationWorld()) { + // TODO: Really count leave as world change? + node.invalidate(); + } + } + } + + /** + * Early adaption on world change. + * + * @param oldWorld + * @param newWorld + */ + void onPlayerChangedWorld(final World oldWorld, final World newWorld, + final WorldDataManager worldDataManager) { + updateCurrentWorld(newWorld, worldDataManager); + // TODO: Double-invalidation (previous policy and target world policy) + final Iterator> it = permissions.iterator(); + // TODO: More efficient: get unmodifiable collection from registry? + while (it.hasNext()) { + final PermissionNode node = it.next().getValue(); + final PermissionInfo info = node.getPermissionInfo(); + if (info.invalidationWorld()) { + node.invalidate(); + } + } + requestLazyPermissionUpdate(permissionRegistry.getPreferKeepUpdatedWorld()); + } + + /** + * Called with adjusting to the configuration (enable / config reload). + * @param changedPermissions + */ + public void adjustSettings(final Set changedPermissions) { + final Iterator it = changedPermissions.iterator(); + while (it.hasNext()) { + final PermissionNode node = permissions.get(it.next().getId()); + if (node != null) { + node.invalidate(); + } + } + } + + @Override public boolean hasPermission(final RegisteredPermission registeredPermission, final Player player) { // Check cache and policy. PermissionNode node = permissions.get(registeredPermission.getId()); @@ -378,42 +555,186 @@ public class PlayerData implements IData, ICanHandleTimeRunningBackwards { } } - private PermissionNode getOrCreatePermissionNode(final RegisteredPermission registeredPermission) { - // Optimistic creation (concurrency). - final PermissionNode node = new PermissionNode(permissionRegistry.getPermissionInfo(registeredPermission.getId())); - final PermissionNode oldNode = permissions.putIfAbsent(registeredPermission.getId(), node); - return oldNode == null ? node : oldNode; + + @Override + public void requestPermissionUpdate(final RegisteredPermission registeredPermission) { + if (Bukkit.isPrimaryThread()) { + requestPermissionUpdatePrimaryThread(registeredPermission); + } + else { + requestPermissionUpdateAsynchronous(registeredPermission); + } + } + + @Override + public void requestLazyPermissionUpdate(final RegisteredPermission... registeredPermissions) { + if (registeredPermissions == null || registeredPermissions.length == 0) { + return; + } + else { + requestLazyPermissionsUpdateNonEmpty(registeredPermissions); + } } /** - * Fetch the permission hard, no putting to cache, just return the result. - * For off-primary-server-thread access, this will wait for a - * BukkitRunnable/TickTask task to finish, at an extraordinary performance - * penalty. + * Remove extra stored data, keeping "essential" data if set so. "Essential" + * data can't be recovered once deleted, like set-back locations for players + * who leave in-air (once stored here at all). * - * @param registeredPermission - * @param player - * @return MAYBE in case permissions could not be fetched or + * @param keepEssentialData */ - private AlmostBoolean fetchPermission(final RegisteredPermission registeredPermission, Player player) { - if (Bukkit.isPrimaryThread()) { - if (player == null) { - player = DataManager.getPlayer(this.playerId); - if (player == null) { - return AlmostBoolean.MAYBE; - } - } - // Minimal update within the primary thread. - return player.hasPermission(registeredPermission.getBukkitPermission()) ? AlmostBoolean.YES : AlmostBoolean.NO; + public void removeData(boolean keepEssentialData) { + // TODO: Interface / stages. + permissions.clear(); // Might keep login-related permissions. Implement a 'retain-xy' or 'essential' flag? + updatePermissions.clearPrimaryThread(); + updatePermissionsLazy.clearPrimaryThread(); + } + + @Override + public String getPlayerName() { + return playerName; + } + + @Override + public String getPlayerNameLowerCase() { + return lcName; + } + + @Override + public UUID getPlayerId() { + return playerId; + } + + @Override + public long getLastJoinTime() { + return lastJoinTime; + } + + @Override + public void exempt(final CheckType checkType) { + checkTypeTree.exempt(checkType, ExemptionContext.LEGACY_NON_NESTED); + // TODO: Handlers? + } + + @Override + public void unexempt(final CheckType checkType) { + checkTypeTree.unexemptAll(checkType, ExemptionContext.LEGACY_NON_NESTED); + // TODO: Handlers? + } + + @Override + public void exempt(final CheckType checkType, final ExemptionContext context) { + checkTypeTree.exempt(checkType, context); + } + + @Override + public void unexempt(final CheckType checkType, final ExemptionContext context) { + checkTypeTree.unexempt(checkType, context); + } + + + @Override + public void unexemptAll(final CheckType checkType, final ExemptionContext context) { + checkTypeTree.unexemptAll(checkType, context); + } + + @Override + public boolean isExempted(final CheckType checkType) { + return checkTypeTree.isExempted(checkType); + } + + @Override + public void clearAllExemptions() { + checkTypeTree.clearAllExemptions(); + } + + @Override + public void clearAllExemptions(final CheckType checkType) { + checkTypeTree.clearAllExemptions(checkType); + } + + @Override + public WorldIdentifier getCurrentWorldIdentifier() { + return currentWorldData.getWorldIdentifier(); + } + + @Override + public IWorldData getCurrentWorldData() { + return currentWorldData; + } + + @Override + public IWorldData getCurrentWorldDataSafe() { + return currentWorldData == null + ? NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().getDefaultWorldData() + : currentWorldData; + } + + @Override + public boolean isCheckActive(final CheckType checkType, final Player player) { + // (No consistency checks for player id / world.) + return isCheckActive(checkType, player, getCurrentWorldDataSafe()); + } + + @Override + public boolean isCheckActive(final CheckType checkType, final Player player, + final IWorldData worldData) { + // TODO: Move the implementation of CheckUtils here (efficiency with exemption). + return worldData.isCheckActive(checkType) + && !hasBypass(checkType, player, worldData); + } + + @Override + public boolean hasBypass(final CheckType checkType, final Player player) { + return hasBypass(checkType, player, getCurrentWorldDataSafe()); + } + + /** + * Bypass check including exemption and permission. + * + * @param checkType + * @param player + * @param isPrimaryThread + * @return + */ + public boolean hasBypass(final CheckType checkType, final Player player, + final IWorldData worldData) { + // TODO: Expose or not. + // Exemption check. + // TODO: More efficient implementation, ExemptionSettings per world in worldData. + if (NCPExemptionManager.isExempted(player, checkType)) { + return true; } - else { - requestPermissionUpdate(registeredPermission); - /* - * TODO: UNCERTAIN: request related permission right away ? Inefficient in case of exemption. - * - */ - return AlmostBoolean.MAYBE; + // Check permission policy/cache regardless of the thread context. + final RegisteredPermission permission = checkType.getPermission(); + if (permission != null && hasPermission(permission, player)) { + return true; } + return false; + } + + @Override + public boolean isDebugActive(final CheckType checkType) { + return checkTypeTree.getNode(checkType).isDebugActive(); + } + + @Override + public void resetDebug() { + resetDebug(CheckType.ALL); + } + + @Override + public void resetDebug(final CheckType checkType) { + this.checkTypeTree.getNode(checkType).resetDebug( + currentWorldData == null ? getCurrentWorldDataSafe() : currentWorldData); + } + + @Override + public void overrideDebug(final CheckType checkType, final AlmostBoolean active, + final OverrideType overrideType, final boolean overrideChildren) { + this.checkTypeTree.getNode(CheckType.ALL).overrideDebug( + getCurrentWorldDataSafe().getRawConfiguration(), + checkType, active, overrideType, overrideChildren); } /** @@ -469,316 +790,47 @@ public class PlayerData implements IData, ICanHandleTimeRunningBackwards { } } - /** - * Check if notifications are turned off, this does not bypass permission - * checks. - * - * @return - */ + @Override public boolean getNotifyOff() { return hasTag(TAG_NOTIFY_OFF); } - /** - * Allow or turn off notifications. A player must have the admin.notify - * permission to receive notifications. - * - * @param notifyOff - * set to true to turn off notifications. - */ + @Override public void setNotifyOff(final boolean notifyOff) { setTag(TAG_NOTIFY_OFF, notifyOff); } - /** - * Let the inventory be updated (run in TickTask). - */ + @Override public void requestUpdateInventory() { this.requestUpdateInventory = true; registerFrequentPlayerTask(); } - /** - * Let the player be set back to the location stored in moving data (run in - * TickTask). Only applies if it's set there. - */ + @Override public void requestPlayerSetBack() { this.requestPlayerSetBack = true; registerFrequentPlayerTask(); } - /** - * Test if it's set to process a player set back on tick. This does not - * check MovingData.hasTeleported(). - * - * @return - */ + @Override public boolean isPlayerSetBackScheduled() { return this.requestPlayerSetBack && (frequentPlayerTaskShouldBeScheduled || isFrequentPlayerTaskScheduled()); } @Override - public void handleTimeRanBackwards() { - final Iterator> it = permissions.iterator(); - final long timeNow = System.currentTimeMillis(); - while (it.hasNext()) { - final PermissionNode node = it.next().getValue(); - switch (node.getFetchingPolicy()) { - case INTERVAL: - node.invalidate(); - break; - case ONCE: - node.setState(node.getLastState(), timeNow); - break; - default: - // Ignore. - break; - } - } + public T getGenericInstance(Class registeredFor) { + // TODO: 1. Check for cache (local). + // TODO: 2. Check for registered factory (local) + // 3. Check proxy registry. + // TODO: Explicit registration for proxy registry needed (PlayerDataManager). + // TODO: Store these in the local cache too (override/replace on world change etc registered too). + return getCurrentWorldDataSafe().getGenericInstance(registeredFor); } - /** - * Request a permission cache update. - * @param registeredPermission - */ - public void requestPermissionUpdate(final RegisteredPermission registeredPermission) { - if (Bukkit.isPrimaryThread()) { - requestPermissionUpdatePrimaryThread(registeredPermission); - } - else { - requestPermissionUpdateAsynchronous(registeredPermission); - } - } - - protected void requestPermissionUpdatePrimaryThread(final RegisteredPermission registeredPermission) { - // Might throw something :p. - updatePermissions.addPrimaryThread(registeredPermission); - registerFrequentPlayerTaskPrimaryThread(); - } - - protected void requestPermissionUpdateAsynchronous(final RegisteredPermission registeredPermission) { - updatePermissions.addAsynchronous(registeredPermission); - registerFrequentPlayerTaskAsynchronous(); - } - - /** - * Low priority permission update for check type specific permissions. - * - * @param registeredPermissions - * May be null. - */ - public void requestLazyPermissionUpdate(final RegisteredPermission...registeredPermissions) { - if (registeredPermissions == null || registeredPermissions.length == 0) { - return; - } - if (Bukkit.isPrimaryThread()) { - requestLazyPermissionUpdatePrimaryThread(registeredPermissions); - } - else { - requestLazyPermissionUpdateAsynchronous(registeredPermissions); - } - } - - protected void requestLazyPermissionUpdatePrimaryThread(final RegisteredPermission... registeredPermissions) { - // Might throw something :p. - updatePermissionsLazy.addAllPrimaryThread(Arrays.asList(registeredPermissions)); - registerFrequentPlayerTaskPrimaryThread(); - } - - protected void requestLazyPermissionUpdateAsynchronous(final RegisteredPermission... registeredPermissions) { - updatePermissionsLazy.addAllAsynchronous(Arrays.asList(registeredPermissions)); - registerFrequentPlayerTaskAsynchronous(); - } - - void onPlayerLeave(final long timeNow) { - invalidateOffline(); - } - - void onPlayerJoin(final long timeNow) { - invalidateOffline(); - requestLazyPermissionUpdate(permissionRegistry.getPreferKeepUpdatedOffline()); - } - - private void invalidateOffline() { - final Iterator> it = permissions.iterator(); - // TODO: More efficient: get unmodifiable collection from registry? - while (it.hasNext()) { - final PermissionNode node = it.next().getValue(); - final PermissionInfo info = node.getPermissionInfo(); - if (info.invalidationOffline() - /* - * TODO: world based should only be invalidated with world - * changing. Therefore store the last world info - * (UUID/name?) in PlayerData and use on login for - * comparison. - */ - || info.invalidationWorld()) { - // TODO: Really count leave as world change? - node.invalidate(); - } - } - } - - /** - * Early adaption. - * - * @param oldWorld - * @param newWorld - */ - void onPlayerChangedWorld(final World oldWorld, final World newWorld) { - // TODO: Double-invalidation (previous policy and target world policy) - final Iterator> it = permissions.iterator(); - // TODO: More efficient: get unmodifiable collection from registry? - while (it.hasNext()) { - final PermissionNode node = it.next().getValue(); - final PermissionInfo info = node.getPermissionInfo(); - if (info.invalidationWorld()) { - node.invalidate(); - } - } - requestLazyPermissionUpdate(permissionRegistry.getPreferKeepUpdatedWorld()); - } - - /** - * Called with adjusting to the configuration (enable / config reload). - * @param changedPermissions - */ - public void adjustSettings(final Set changedPermissions) { - final Iterator it = changedPermissions.iterator(); - while (it.hasNext()) { - final PermissionNode node = permissions.get(it.next().getId()); - if (node != null) { - node.invalidate(); - } - } - } - - /** - * Remove extra stored data, keeping "essential" data if set so. "Essential" - * data can't be recovered once deleted, like set-back locations for players - * who leave in-air (once stored here at all). - * - * @param keepEssentialData - */ - public void removeData(boolean keepEssentialData) { - permissions.clear(); // Might keep login-related permissions. Implement a 'retain-xy' or 'essential' flag? - updatePermissions.clearPrimaryThread(); - updatePermissionsLazy.clearPrimaryThread(); - } - - /** - * Mimic legacy behavior (non-nested) - exempt including descendants - * recursively. Note that contexts other than - * ExemptionContext.LEGACY_NON_NESTED will not be touched. - * - * @param checkType - */ - public void exempt(final CheckType checkType) { - checkTypeTree.exempt(checkType, ExemptionContext.LEGACY_NON_NESTED); - // TODO: Handlers? - } - - /** - * Mimic legacy behavior (non-nested) - unexempt including descendants - * recursively. Note that contexts other than - * ExemptionContext.LEGACY_NON_NESTED will not be touched. - *
    - * Primary thread and asynchronous access are separated and yield different - * results, it's imperative to always unexempt properly for asyncrhonous - * thread contexts, as isExempted reflects a mixture of both. - * - * @param checkType - */ - public void unexempt(final CheckType checkType) { - checkTypeTree.unexemptAll(checkType, ExemptionContext.LEGACY_NON_NESTED); - // TODO: Handlers? - } - - /** - * Exempt with reference to the given context with descendants recursively. - *
    - * Note that multiple calls to exempt demand multiple calls to - * unexempt(CheckType, ExemptionContext). - *
    - * Primary thread and asynchronous access are separated and yield different - * results, it's imperative to always unexempt properly for asyncrhonous - * thread contexts, as isExempted reflects a mixture of both. - * - * @param checkType - * @param context - */ - public void exempt(final CheckType checkType, final ExemptionContext context) { - checkTypeTree.exempt(checkType, context); - } - - /** - * Unexempt once, including descendants recursively.
    - * Note that for multiple calls to exempt with one context, multiple calls - * to unexempt with that context may be necessary to fully unexempt, or call - * unexemptAll for the context. - *
    - * ExemptionContext.LEGACY_NON_NESTED is not automatically calling - * unexemptAll as is done with the legacy signature unexempt(CheckType). - *
    - * Primary thread and asynchronous access are separated and yield different - * results, it's imperative to always unexempt properly for asyncrhonous - * thread contexts, as isExempted reflects a mixture of both. - * - * @param checkType - * @param context - */ - public void unexempt(final CheckType checkType, final ExemptionContext context) { - checkTypeTree.unexempt(checkType, context); - } - - - /** - * Remove all (potentially nested) entries context for the given checkType - * and descendants recursively. - *
    - * Primary thread and asynchronous access are separated and yield different - * results, it's imperative to always unexempt properly for asyncrhonous - * thread contexts, as isExempted reflects a mixture of both. - * - * @param checkType - * @param context - */ - public void unexemptAll(final CheckType checkType, final ExemptionContext context) { - checkTypeTree.unexemptAll(checkType, context); - } - - /** - * Test for exemption. - *
    - * Thread-safe read (not synchronized). - * - * @param checkType - * @return - */ - public boolean isExempted(final CheckType checkType) { - return checkTypeTree.isExempted(checkType); - } - - /** - * Clear all exemptions, for all thread contexts. - *
    - * Call from the primary thread only. - */ - public void clearAllExemptions() { - checkTypeTree.clearAllExemptions(); - } - - /** - * Clear all exemptions for the given checkType and descendants recursively, - * for all thread contexts. - *
    - * Call from the primary thread only. - * - * @param checkType - */ - public void clearAllExemptions(final CheckType checkType) { - checkTypeTree.clearAllExemptions(checkType); + @Override + public void removeGenericInstance(Class registeredFor) { + // TODO: implement } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerDataManager.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerDataManager.java new file mode 100644 index 00000000..367f8736 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerDataManager.java @@ -0,0 +1,992 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.players; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import fr.neatmonster.nocheatplus.NCPAPIProvider; +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.checks.ViolationHistory; +import fr.neatmonster.nocheatplus.checks.access.ICheckData; +import fr.neatmonster.nocheatplus.checks.access.IRemoveSubCheckData; +import fr.neatmonster.nocheatplus.checks.combined.CombinedData; +import fr.neatmonster.nocheatplus.compat.BridgeMisc; +import fr.neatmonster.nocheatplus.compat.versions.BukkitVersion; +import fr.neatmonster.nocheatplus.compat.versions.GenericVersion; +import fr.neatmonster.nocheatplus.compat.versions.ServerVersion; +import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI; +import fr.neatmonster.nocheatplus.components.data.ICanHandleTimeRunningBackwards; +import fr.neatmonster.nocheatplus.components.registry.FactoryOneRegistry; +import fr.neatmonster.nocheatplus.components.registry.TypeSetRegistry; +import fr.neatmonster.nocheatplus.components.registry.feature.ComponentWithName; +import fr.neatmonster.nocheatplus.components.registry.feature.ConsistencyChecker; +import fr.neatmonster.nocheatplus.components.registry.feature.IDisableListener; +import fr.neatmonster.nocheatplus.components.registry.feature.IHaveCheckType; +import fr.neatmonster.nocheatplus.components.registry.feature.INeedConfig; +import fr.neatmonster.nocheatplus.components.registry.feature.IRemoveData; +import fr.neatmonster.nocheatplus.components.registry.feature.TickListener; +import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterMethodWithOrder; +import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterWithOrder; +import fr.neatmonster.nocheatplus.config.ConfPaths; +import fr.neatmonster.nocheatplus.config.ConfigFile; +import fr.neatmonster.nocheatplus.config.ConfigManager; +import fr.neatmonster.nocheatplus.event.mini.MiniListener; +import fr.neatmonster.nocheatplus.logging.StaticLog; +import fr.neatmonster.nocheatplus.logging.Streams; +import fr.neatmonster.nocheatplus.permissions.PermissionPolicy; +import fr.neatmonster.nocheatplus.permissions.PermissionRegistry; +import fr.neatmonster.nocheatplus.permissions.PermissionSettings; +import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; +import fr.neatmonster.nocheatplus.players.PlayerMap.PlayerInfo; +import fr.neatmonster.nocheatplus.utilities.CheckTypeUtil; +import fr.neatmonster.nocheatplus.utilities.CheckUtils; +import fr.neatmonster.nocheatplus.utilities.IdUtil; +import fr.neatmonster.nocheatplus.utilities.StringUtil; +import fr.neatmonster.nocheatplus.utilities.TickTask; +import fr.neatmonster.nocheatplus.utilities.ds.corw.DualSet; +import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW; +import fr.neatmonster.nocheatplus.worlds.IWorldData; +import fr.neatmonster.nocheatplus.worlds.WorldDataManager; + +/** + * Player data storage. May contain functionality of the DataManager, which + * isn't intended to be in a PlayerDataManager (refactoring stage). + * + * @author asofold + * + */ +// TODO: RegisterWithOrder still relevant ? +@RegisterWithOrder(tag = "system.nocheatplus.datamanager", beforeTag = "(^feature.*)", basePriority = "-80") +public class PlayerDataManager implements IPlayerDataManager, ComponentWithName, INeedConfig, ConsistencyChecker, IDisableListener { + + ///////////////////// + // Instance + ///////////////////// + + private int foundInconsistencies = 0; + + /** PlayerData storage. */ + private final HashMapLOW playerData = new HashMapLOW(100); + + /** Primary thread only (no lock for this field): UUIDs to remove upon next bulk removal. */ + private final Set bulkPlayerDataRemoval = new LinkedHashSet(); + + private final DualSet frequentPlayerTasks = new DualSet(); + + /** + * Access order for playerName (exact) -> ms time of logout. + *
    + * Later this might hold central player data objects instead of the long + * only. + */ + private final Map lastLogout = new LinkedHashMap(50, 0.75f, true); + + /** + * Keeping track of online players. Currently id/name mappings are not kept + * on logout, but might be later. + */ + // TODO: Switch to UUIDs as keys, get data by uuid when possible, use PlayerMap for getting the UUID. + private final PlayerMap playerMap; + + /** + * IRemoveData instances. + */ + // TODO: might use a map for those later (extra or not). + private final ArrayList iRemoveData = new ArrayList(); + + /** + * Execution histories of the checks. + */ + // TODO: Move to PlayerData / CheckTypeTree (NodeS). + private final Map> executionHistories = new HashMap>(); + + /** Flag if data expiration is active at all. */ + private boolean doExpireData = false; + + /** + * Duration in milliseconds for expiration of logged off players data. In + * the config minutes are used as unit. + */ + private long durExpireData = 0; + + /** Data and execution history. */ + private boolean deleteData = true; + /** Violation history and execution history. */ + private boolean deleteHistory = false; + + /** + * Reference for passing to PlayerData for handling permission caching and + * policies. + */ + /* + * TODO: Per world (rule/proxy) registries, with one central registry for + * ids (per-world registries would proxy id registration, but have their own + * rule settings). + */ + private final PermissionRegistry permissionRegistry; + + private WorldDataManager worldDataManager; + + private final Lock lock = new ReentrantLock(); + // TODO: Consider same lock for some registry parts (deadlocking possibilities with exposed API). + private final FactoryOneRegistry factoryRegistry = new FactoryOneRegistry( + lock, CheckUtils.primaryServerThreadContextTester); + /** + * Grouped types to have a faster way of iterating data types stored in the + * PlayerData cache. + */ + private final TypeSetRegistry groupedTypes = new TypeSetRegistry(lock); + + private final TickListener tickListener = new TickListener() { + + private int delayRareTasks = 0; + + @Override + public void onTick(final int tick, final long timeLast) { + if (rareTasks(tick, timeLast)) { + delayRareTasks = 10; + } + else { + if (delayRareTasks == 0) { + } + else { + delayRareTasks --; + } + } + frequentTasks(tick, timeLast); + } + }; + + private final MiniListener[] miniListeners = new MiniListener[] { + /* + * TODO: Constants in a class 'ListenerTags', plus a plan + * (system.data.player.nocheatplus, system.nocheatplus.data ??, + * nocheatplus.system.data.player...). (RegistryTags for other?). + */ + new MiniListener() { + @Override + @EventHandler(priority = EventPriority.MONITOR) + @RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = ".*") + public void onEvent(final PlayerQuitEvent event) { + playerLeaves(event.getPlayer()); + } + }, + new MiniListener() { + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + @RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = ".*") + public void onEvent(final PlayerKickEvent event) { + playerLeaves(event.getPlayer()); + } + }, + new MiniListener() { + @EventHandler(priority = EventPriority.LOWEST) + @RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", beforeTag = ".*") + public void onEvent(final PlayerJoinEvent event) { + playerJoins(event); + } + }, + new MiniListener() { + @EventHandler(priority = EventPriority.LOWEST) + @RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = ".*") + public void onEvent(final PlayerChangedWorldEvent event) { + playerChangedWorld(event); + } + }, + }; + + + /** + * Sets the static instance reference. + * @param worldDataManager + */ + public PlayerDataManager(final WorldDataManager worldDataManager, final PermissionRegistry permissionRegistry) { + DataManager.instance = this; // TODO: Let NoCheatPlus do this, DataManager returns an ILockable. + if (ServerVersion.isMinecraftVersionUnknown()) { + // True hacks. + BukkitVersion.init(); + } + final String version = ServerVersion.getMinecraftVersion(); + if (GenericVersion.compareVersions(version, "1.8") >= 0 || version.equals("1.7.10") && Bukkit.getServer().getVersion().toLowerCase().indexOf("spigot") != -1) { + // Safe to assume Spigot, don't store Player instances. + playerMap = new PlayerMap(false); + } + else { + // Likely an older version without efficient mapping. + playerMap = new PlayerMap(true); + } + this.permissionRegistry = permissionRegistry; + this.worldDataManager = worldDataManager; + } + + /** + * Check the logged out players for if any data can be removed.
    + * Currently only "dumb" full removal is performed. Later it is thinkable to + * remove "as much as reasonable". + */ + public void checkExpiration() { + if (!doExpireData || durExpireData <= 0) { + return; + } + final long now = System.currentTimeMillis(); + final Set factories = new LinkedHashSet(); + final Set> entries = lastLogout.entrySet(); + final Iterator> iterator = entries.iterator(); + while (iterator.hasNext()) { + final Entry entry = iterator.next(); + final long ts = entry.getValue(); + if (now - ts <= durExpireData) { + break; + } + final UUID playerId = entry.getKey(); + // TODO: LEGACY handling: switch to UUIDs here for sure. + legacyPlayerDataExpirationRemovalByName(playerId, factories, deleteData); + bulkPlayerDataRemoval.add(playerId); // For bulk removal. + iterator.remove(); + } + // Bulk removal of PlayerData. + if (!bulkPlayerDataRemoval.isEmpty()) { + doBulkPlayerDataRemoval(); // Using this method allows checking for delayed removal etc. + } + } + + private final void legacyPlayerDataExpirationRemovalByName(final UUID playerId, + final Set factories, final boolean deleteData) { + final String playerName = DataManager.getPlayerName(playerId); + if (playerName == null) { + // TODO: WARN + return; + } + // TODO: Validity of name? + if (deleteData) { + factories.clear(); + for (final CheckType type : CheckType.values()) { + final CheckDataFactory factory = type.getDataFactory(); + if (factory != null) { + factories.add(factory); + } + } + for (final CheckDataFactory factory : factories) { + factory.removeData(playerName); + } + clearComponentData(CheckType.ALL, playerName); + } + if (deleteData || deleteHistory) { + removeExecutionHistory(CheckType.ALL, playerName); + } + if (deleteHistory) { + ViolationHistory.removeHistory(playerName); + } + } + + /** + * Called by the rareTasksListener (OnDemandTickListener). + * @return "Did something" - true if data was removed or similar, i.e. reset the removal delay counter. False if nothing relevant had been done. + */ + private final boolean rareTasks(final int tick, final long timeLast) { + boolean something = false; + if (!bulkPlayerDataRemoval.isEmpty()) { + doBulkPlayerDataRemoval(); + something = true; + } + // TODO: Process rarePlayerTasks + return something; + } + + /** + * On tick. + */ + private final void frequentTasks(final int tick, final long timeLast) { + frequentPlayerTasks.mergePrimaryThread(); + final Iterator it = frequentPlayerTasks.iteratorPrimaryThread(); + while (it.hasNext()) { + final PlayerData pData = getPlayerData(it.next(), null, false, null); + if (pData.processTickFrequent(tick, timeLast)) { + it.remove(); + } + } + } + + /** + * Primary thread only. This checks for if players are/should be online. + */ + private final void doBulkPlayerDataRemoval() { + int size = bulkPlayerDataRemoval.size(); + if (size > 0) { + // Test for online players. + final Iterator it = bulkPlayerDataRemoval.iterator(); + while (it.hasNext()) { + final UUID playerId = it.next(); + boolean skip = !lastLogout.containsKey(playerId); + // TODO: Also remove fake players, thus test for logged in too. + /* + * TODO: Multi stage removal: (1) non essential like permission + * cache, (2) essential like set-back location, (3) all. In + * addition things will get shifty, once we use PlayerData + * during asynchronous login - possibly we'll need parked data + * then, also considering offline servers. + */ + if (skip) { + it.remove(); + size --; + final PlayerData data = playerData.get(playerId); + if (data != null) { + // Should be online, keep essential data. + data.removeData(true); + } + continue; + } + } + // Actually remove data. + if (size > 0) { + playerData.remove(bulkPlayerDataRemoval); + bulkPlayerDataRemoval.clear(); + if (ConfigManager.getConfigFile().getBoolean(ConfPaths.LOGGING_EXTENDED_STATUS)) { + NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.STATUS, "Bulk PlayerData removal: " + size); + } + } + } + } + + /** + * Remove the player data for a given player and a given check type. + * CheckType.ALL and null will be interpreted as removing all data.
    + * + * @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 boolean removeData(final String playerName, CheckType checkType) { + + final PlayerData pd = getPlayerData(playerName); + // TODO: Once working, use the most correct name from PlayerData. + final UUID playerId = pd == null ? getUUID(playerName) : pd.getPlayerId(); + + if (checkType == null) { + checkType = CheckType.ALL; + } + boolean had = false; + + // Check extended registered components. + // TODO: "System data" might not be wise to erase for online players. + if (clearComponentData(checkType, playerName)) { + had = true; + } + + // Collect factories. + final Set factories = new HashSet(); + for (CheckType otherType : CheckTypeUtil.getWithDescendants(checkType)) { + final CheckDataFactory otherFactory = otherType.getDataFactory(); + if (otherFactory != null) { + factories.add(otherFactory); + } + } + // Remove data. + for (final CheckDataFactory factory : factories) { + if (removeDataPrecisely(playerId, playerName, checkType, factory)) { + had = true; + } + } + + // TODO: Multi stage removal, other API + // TODO: Maintain a shouldBeOnline flag for fast skipping? + if (pd != null && checkType == CheckType.ALL) { + // TODO: Fetch/use UUID early, and check validity of name. + if (playerId != null) { + bulkPlayerDataRemoval.add(playerId); + } + } + + return had; + } + + /** + * Attempt to only remove the data, relevant to the given CheckType. + * + * @param playerId + * @param playerName + * @param checkType + * @param factory + * @return If any data has been removed. + */ + private boolean removeDataPrecisely(final UUID playerId, final String playerName, + final CheckType checkType, final CheckDataFactory factory) { + // TODO: Use PlayerData if present. + final ICheckData data = factory.getDataIfPresent(playerId, playerName); + if (data == null) { + return false; + } + else { + // Attempt precise removal. + final boolean debug = data.getDebug(); + String debugText = debug ? "[" + checkType + "] [" + playerName + "] Data removal: " : null; + boolean res = false; + if (data instanceof IRemoveSubCheckData + && ((IRemoveSubCheckData) data).removeSubCheckData(checkType)) { + if (debug) { + debugText += "Removed (sub) check data, keeping the data object."; + } + res = true; + } + else { + // Just remove. + if (factory.removeData(playerName) == null) { + // Is this even possible? + if (debug) { + debugText += "Could not remove data, despite present!"; + } + } + else { + if (debug) { + debugText += "Removed the entire data object."; + } + res = true; + } + } + if (debug) { + NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, debugText); + } + return res; + } + } + + /** + * Check if player instances are stored for efficiency (legacy). + * + * @return + */ + public boolean storesPlayerInstances() { + return playerMap.storesPlayerInstances(); + } + + @Override + public boolean addComponent(IRemoveData obj) { + if (iRemoveData.contains(obj)) { + return false; + } + else { + iRemoveData.add((IRemoveData) obj); + return true; + } + } + + @Override + public void removeComponent(IRemoveData obj) { + iRemoveData.remove((IRemoveData) obj); + } + + /** + * Initializing with online players. + */ + public void onEnable() { + TickTask.addTickListener(tickListener); + final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI(); + for (final MiniListener listener : miniListeners) { + api.addComponent(listener, false); + } + for (final Player player : BridgeMisc.getOnlinePlayers()) { + addOnlinePlayer(player); + } + } + + /** + * Cleanup method, removes all data and config, but does not call + * ConfigManager.cleanup. + */ + @Override + public void onDisable() { + // TODO: Process pending set backs etc. -> iterate playerData -> onDisable. + clearData(CheckType.ALL); + playerData.clear(); // Also clear for online players. + iRemoveData.clear(); + DataManager.clearConfigs(); // TODO: Cleaning up the WorldDataManager is up to the WorldDataManager. + lastLogout.clear(); + executionHistories.clear(); + playerMap.clear(); + // Finally alert (summary) if inconsistencies found. + if (foundInconsistencies > 0) { + StaticLog.logWarning("DataMan found " + foundInconsistencies + " inconsistencies (warnings suppressed)."); + foundInconsistencies = 0; + } + } + + /** + * Add mappings for player names variations. + * @param player + */ + private void addOnlinePlayer(final Player player) { + playerMap.updatePlayer(player); + } + + /** + * Remove mappings for player names variations. + * @param player + */ + private void removeOnlinePlayer(final Player player) { + // TODO: Consider to only remove the Player instance? Yes do so... and remove the mapping if the full data expires only. + playerMap.remove(player); + } + + private void playerJoins(final PlayerJoinEvent event) { + final long timeNow = System.currentTimeMillis(); + final Player player = event.getPlayer(); + final UUID playerId = player.getUniqueId(); + // + lastLogout.remove(playerId); + addOnlinePlayer(player); + // + final PlayerData pData = getPlayerData(player, true); + /* + * TODO: Now we update the world already with getPlayerData, in case + * it's just been created... + */ + pData.onPlayerJoin(player.getWorld(), timeNow, worldDataManager); + pData.getGenericInstance(CombinedData.class).lastJoinTime = timeNow; + } + + /** + * Quit or kick. + * @param player + */ + private void playerLeaves(final Player player) { + final long timeNow = System.currentTimeMillis(); + final UUID playerId = player.getUniqueId(); + lastLogout.put(playerId, timeNow); + final PlayerData pData = playerData.get(playerId); + if (pData != null) { + pData.onPlayerLeave(timeNow); + } + // TODO: put lastLogoutTime to PlayerData ! + pData.getGenericInstance(CombinedData.class).lastLogoutTime = timeNow; + removeOnlinePlayer(player); + } + + private void playerChangedWorld(final PlayerChangedWorldEvent event) { + final Player player = event.getPlayer(); + final PlayerData pData = getPlayerData(player, true); + pData.onPlayerChangedWorld(event.getFrom(), player.getWorld(), worldDataManager); + } + + /** + * Fetch settings from the current default config. + */ + private void adjustSettings() { + final ConfigFile config = ConfigManager.getConfigFile(); + doExpireData = config.getBoolean(ConfPaths.DATA_EXPIRATION_ACTIVE); + durExpireData = config.getLong(ConfPaths.DATA_EXPIRATION_DURATION, 1, 1000000, 60) * 60000L; // in minutes + deleteData = config.getBoolean(ConfPaths.DATA_EXPIRATION_DATA, true); // hidden. + deleteHistory = config.getBoolean(ConfPaths.DATA_EXPIRATION_HISTORY); + // TODO: Per world permission registries: need world configs (...). + Set changedPermissions = null; + try { + // TODO: Only update if changes are there - should have a config-path hash+size thing (+ setting). + changedPermissions = permissionRegistry.updateSettings(PermissionSettings.fromConfig(config, + ConfPaths.PERMISSIONS_POLICY_DEFAULT, ConfPaths.PERMISSIONS_POLICY_RULES)); + } + catch (Exception e) { + StaticLog.logSevere("Failed to read the permissions setup. Relay to ALWAYS policy."); + StaticLog.logSevere(e); + permissionRegistry.updateSettings(new PermissionSettings(null, null, new PermissionPolicy())); + } + // Invalidate all already fetched permissions. + for(final Entry entry : playerData.iterable()) { + entry.getValue().adjustSettings(changedPermissions); + } + } + + @Override + public void onReload() { + // present. + adjustSettings(); + } + + @Override + public String getComponentName() { + return "NoCheatPlus_DataManager"; + } + + @Override + public void checkConsistency(final Player[] onlinePlayers) { + // Check online player tracking consistency. + int missing = 0; + int changed = 0; + for (int i = 0; i < onlinePlayers.length; i++) { + final Player player = onlinePlayers[i]; + final UUID id = player.getUniqueId(); + // if (player.isOnline()) { + // TODO: Add a consistency check method !? + if (!playerMap.hasPlayerInfo(id)) { + missing ++; + // TODO: Add the player [problem: messy NPC plugins?]? + } + if (playerMap.storesPlayerInstances() && player != playerMap.getPlayer(id)) { + changed ++; + // Update the reference. + addOnlinePlayer(player); + // } + } + } + + // TODO: Consider checking lastLogout for too long gone players. + + // TODO: Later the map size will not work, if we keep name/id mappings after logout. Other checking methods are possible. + final int storedSize = this.playerMap.size(); + if (missing != 0 || changed != 0 || onlinePlayers.length != storedSize) { + foundInconsistencies ++; + if (!ConfigManager.getConfigFile().getBoolean(ConfPaths.DATA_CONSISTENCYCHECKS_SUPPRESSWARNINGS)) { + final List details = new LinkedList(); + if (missing != 0) { + details.add("missing online players (" + missing + ")"); + } + if (onlinePlayers.length != storedSize) { + // TODO: Consider checking for not online players and remove them. + details.add("wrong number of online players (" + storedSize + " instead of " + onlinePlayers.length + ")"); + } + if (changed != 0) { + details.add("changed player instances (" + changed + ")"); + } + + StaticLog.logWarning("DataMan inconsistencies: " + StringUtil.join(details, " | ")); + } + } + } + + void registerFrequentPlayerTaskPrimaryThread(final UUID playerId) { + frequentPlayerTasks.addPrimaryThread(playerId); + } + + void registerFrequentPlayerTaskAsynchronous(final UUID playerId) { + frequentPlayerTasks.addAsynchronous(playerId); + } + + /** + * Might yield false negatives, should be reasonable on performance. + * + * @param playerId + * @return + */ + boolean isFrequentPlayerTaskScheduled(final UUID playerId) { + // TODO : Efficient impl / optimized methods? + if (Bukkit.isPrimaryThread()) { + return frequentPlayerTasks.containsPrimaryThread(playerId); + } + else { + return frequentPlayerTasks.containsAsynchronous(playerId); + } + } + + /** + * Clear player related data, only for registered components (not execution + * history, violation history, normal check data).
    + * That should at least go for chat engine data. + * + * @param CheckType + * @param PlayerName + * @return If something was removed. + */ + public boolean clearComponentData(final CheckType checkType, final String PlayerName) { + // TODO: UUID. + boolean removed = false; + for (final IRemoveData rmd : iRemoveData) { + if (checkType == CheckType.ALL) { + // Not sure this is really good, though. + if (rmd.removeData(PlayerName) != null) { + removed = true; + } + } + else if (rmd instanceof IHaveCheckType) { + final CheckType refType = ((IHaveCheckType) rmd).getCheckType(); + if (refType == checkType || CheckTypeUtil.isAncestor(checkType, refType)) { + if (rmd.removeData(PlayerName) != null) { + removed = true; + } + } + } + } + return removed; + } + + /** + * Adjust to the system time having run backwards. This is much like + * clearData(CheckType.ALL), with the exception of calling + * ICanHandleTimeRunningBackwards.handleTimeRanBackwards for data instances + * which implement this. + */ + public void handleSystemTimeRanBackwards() { + // Collect data factories and clear execution history. + final Set factories = new HashSet(); + for (final CheckType type : CheckTypeUtil.getWithDescendants(CheckType.ALL)) { + final Map map = executionHistories.get(type); + if (map != null) { + map.clear(); + } + final CheckDataFactory factory = type.getDataFactory(); + if (factory != null) { + factories.add(factory); + } + } + for (final CheckDataFactory factory : factories) { + if (factory instanceof ICanHandleTimeRunningBackwards) { + ((ICanHandleTimeRunningBackwards) factory).handleTimeRanBackwards(); + } + else { + factory.removeAllData(); + } + } + for (final IRemoveData rmd : iRemoveData) { + if (rmd instanceof ICanHandleTimeRunningBackwards) { + ((ICanHandleTimeRunningBackwards) rmd).handleTimeRanBackwards(); + } + else { + rmd.removeAllData(); + } + } + ViolationHistory.clear(CheckType.ALL); + // PlayerData + for (final Entry entry : playerData.iterable()){ + entry.getValue().handleTimeRanBackwards(); + } + } + + /** + * Fetch a PlayerData instance. If none is present and create is set, a new + * instance will be created. + * + * @param playerId + * @param playerName + * Exact player name (rather). + * @param create + * @param worldData + * WorldData is only used for creating new instances, in which + * case it must not be null. + * @return + */ + PlayerData getPlayerData(final UUID playerId, + final String playerName, final boolean create, + final IWorldData worldData) { + final PlayerData data = playerData.get(playerId); + if (!create || data != null) { + return data; + } + else { + // Creating this should be mostly harmless. + // TODO: Might want to lock still (same lock as used within the + // playerData map). + final PlayerData newData = new PlayerData(playerId, playerName, + permissionRegistry); + final PlayerData oldData = playerData.putIfAbsent(playerId, + newData); + final PlayerData usedData = oldData == null ? newData : oldData; + usedData.updateCurrentWorld( + worldData == null ? worldDataManager.getDefaultWorldData() + : worldData); + return usedData; + } + } + + @Override + public PlayerData getPlayerData(final Player player, boolean create) { + return getPlayerData(player.getUniqueId(), player.getName(), + create, create ? worldDataManager.getWorldDataSafe(player) : null); + } + + @Override + public PlayerData getPlayerData(final Player player) { + return getPlayerData(player, true); + } + + @Override + public PlayerData getPlayerData(final String playerName) { + final UUID playerId = DataManager.getUUID(playerName); + return playerId == null ? null : playerData.get(playerId); + } + + @Override + public PlayerData getPlayerData(final UUID playerId) { + return playerData.get(playerId); + } + + @Override + public Player getPlayerExact(final String playerName) { + return playerMap.getPlayerExact(playerName); + } + + @Override + public UUID getUUID(final String input) { + // TODO: Use player map. + final Player player = getPlayer(input); + if (player != null) { + return player.getUniqueId(); + } + return IdUtil.UUIDFromStringSafe(input); + } + + @Override + public String getPlayerName(final UUID playerId) { + final PlayerInfo info = playerMap.getPlayerInfo(playerId); + if (info != null && info.exactName != null) { + return info.exactName; + } + final PlayerData data = playerData.get(playerId); + if (data != null) { + return data.getPlayerName(); + } + return null; + } + + @Override + public Player getPlayer(final UUID id) { + return playerMap.getPlayer(id); + } + + @Override + public Player getPlayer(final String playerName) { + return playerMap.getPlayer(playerName); + } + + @Override + public void restoreDefaultDebugFlags() { + // (Note that WorldData is resetting differently, and before this.) + for (final Entry entry : playerData.iterable()) { + entry.getValue().resetDebug(); + } + } + + @Override + public void clearAllExemptions() { + final Iterator> it = playerData.iterator(); + while (it.hasNext()) { + it.next().getValue().clearAllExemptions(); + } + } + + @Override + public void removeGenericInstance(Class registeredFor) { + // TODO: Really needs OfflinePlayerData for more frequent data removal. + for (final Entry entry : playerData.iterable()) { + entry.getValue().removeGenericInstance(registeredFor); + } + } + + @Override + public void clearData(final CheckType checkType) { + // TODO: WorldDataManager: clear player related data there (registered in PlayerDataManager!?). + final Set factories = new HashSet(); + for (final CheckType type : CheckTypeUtil.getWithDescendants(checkType)) { + final Map map = executionHistories.get(type); + if (map != null) { + map.clear(); + } + final CheckDataFactory factory = type.getDataFactory(); + if (factory != null) { + factories.add(factory); + } + } + for (final CheckDataFactory factory : factories) { + // TODO: Support precise removal ? + factory.removeAllData(); + } + for (final IRemoveData rmd : iRemoveData) { + if (checkType == CheckType.ALL) { + // Not sure this is really good, though. + rmd.removeAllData(); + } + else if (rmd instanceof IHaveCheckType) { + final CheckType refType = ((IHaveCheckType) rmd).getCheckType(); + if (refType == checkType || CheckTypeUtil.isAncestor(checkType, refType)) { + rmd.removeAllData(); + } + } + } + ViolationHistory.clear(checkType); + if (checkType == CheckType.ALL) { + bulkPlayerDataRemoval.addAll(playerData.getKeys()); + doBulkPlayerDataRemoval(); // Only removes offline player data. + } + } + + /** + * Used by checks to register the history for external access.
    + * NOTE: This method is not really meant to be used from outside NCP. + * + * @param type + * @param histories + * @deprecated New implementation pending. + */ + public void registerExecutionHistory(CheckType type, Map histories) { + executionHistories.put(type, histories); + } + + /** + * Access method to the the execution history for check type for a player. + * + * @param type + * @param playerName + * Exact case for player name. + * @return null if not present. + * @deprecated New implementation pending. + */ + public ExecutionHistory getExecutionHistory(final CheckType type, final String playerName) { + final Map map = executionHistories.get(type); + if (map != null) { + return map.get(playerName); + } + return null; + } + + /** + * Remove the execution history for a player for the given check type. + * + * @param type + * @param playerName + * @return + * @deprecated New implementation pending. + */ + public boolean removeExecutionHistory(final CheckType type, final String playerName) { + boolean removed = false; + // TODO: design ... + for (final CheckType refType : CheckTypeUtil.getWithDescendants(type)) { + final Map map = executionHistories.get(refType); + if (map != null && map.remove(playerName) != null) { + removed = true; + } + } + return removed; + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerFactoryArgument.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerFactoryArgument.java new file mode 100644 index 00000000..b65bd6fd --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerFactoryArgument.java @@ -0,0 +1,36 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.players; + +import fr.neatmonster.nocheatplus.worlds.IWorldData; + +/** + * Arguments for factories for types applicable for PlayerData generic instance + * storage. + * + * @author asofold + * + */ +public class PlayerFactoryArgument { + + public final IPlayerData playerData; + public final IWorldData worldData; + + public PlayerFactoryArgument(final IPlayerData playerData, IWorldData worldData) { + this.playerData = playerData; + this.worldData = worldData; + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerMap.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerMap.java index ab9e9f01..2f085578 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerMap.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/players/PlayerMap.java @@ -238,9 +238,9 @@ public final class PlayerMap { return Bukkit.getPlayer(id); } else { // HACKS - final PlayerData pData = DataManager.getPlayerData(id); - if (pData != null && pData.playerName != null) { - return getPlayer(pData.playerName); + final IPlayerData pData = DataManager.getPlayerData(id); + if (pData != null) { + return getPlayer(pData.getPlayerName()); } else { // Backwards compatibility. diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/CheckUtils.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/CheckUtils.java index 7012df1e..48899f85 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/CheckUtils.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/CheckUtils.java @@ -23,19 +23,15 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.checks.access.ICheckConfig; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.checks.blockbreak.BlockBreakData; import fr.neatmonster.nocheatplus.checks.combined.CombinedData; import fr.neatmonster.nocheatplus.checks.fight.FightData; import fr.neatmonster.nocheatplus.checks.inventory.InventoryData; import fr.neatmonster.nocheatplus.checks.moving.MovingConfig; -import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager; +import fr.neatmonster.nocheatplus.components.concurrent.IPrimaryThreadContextTester; import fr.neatmonster.nocheatplus.logging.StaticLog; import fr.neatmonster.nocheatplus.logging.Streams; -import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; -import fr.neatmonster.nocheatplus.players.PlayerData; -import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; +import fr.neatmonster.nocheatplus.players.IPlayerData; /** @@ -45,16 +41,42 @@ import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency; */ public class CheckUtils { + public static final IPrimaryThreadContextTester primaryServerThreadContextTester = new IPrimaryThreadContextTester() { + + @Override + public boolean isPrimaryThread() { + return Bukkit.isPrimaryThread(); + } + }; + /** - * Improper API access. + * Improper API access: Log once a message with the checkType and the + * current stack trace. The stack trace is only logged once on repeated access. * * @param checkType * the check type */ - private static void improperAPIAccess(final CheckType checkType) { + public static void improperAsynchronousAPIAccess(final CheckType checkType) { // TODO: Log once + examine stack (which plugins/things are involved). final String trace = Arrays.toString(Thread.currentThread().getStackTrace()); - StaticLog.logOnce(Streams.STATUS, Level.SEVERE, "Off primary thread call to hasByPass for " + checkType, trace); + StaticLog.logOnce(Streams.STATUS, Level.SEVERE, "Off primary thread processing for " + checkType, trace); + } + + /** + * Quick test and log error, if this is called off the primary thread + * context. + * + * @param checkType + * @return True if this is the primary thread. + */ + public static boolean demandPrimaryThread(final CheckType checkType) { + if (Bukkit.isPrimaryThread()) { + return true; + } + else { + improperAsynchronousAPIAccess(checkType); + return false; + } } /** @@ -83,23 +105,24 @@ public class CheckUtils { * @return Return timestamp or Long.MIN_VALUE if not possible or beyond * maxAge. */ - public static final long guessKeepAliveTime(final Player player, final long now, final long maxAge){ + public static final long guessKeepAliveTime(final Player player, + final long now, final long maxAge, final IPlayerData pData){ final int tick = TickTask.getTick(); long ref = Long.MIN_VALUE; // Estimate last fight action time (important for gode modes). - final FightData fData = FightData.getData(player); + final FightData fData = pData.getGenericInstance(FightData.class); ref = Math.max(ref, fData.speedBuckets.lastUpdate()); ref = Math.max(ref, now - 50L * (tick - fData.lastAttackTick)); // Ignore lag. // Health regain (not unimportant). ref = Math.max(ref, fData.regainHealthTime); // Move time. - ref = Math.max(ref, CombinedData.getData(player).lastMoveTime); + ref = Math.max(ref, pData.getGenericInstance(CombinedData.class).lastMoveTime); // Inventory. - final InventoryData iData = InventoryData.getData(player); + final InventoryData iData = pData.getGenericInstance(InventoryData.class); ref = Math.max(ref, iData.lastClickTime); ref = Math.max(ref, iData.instantEatInteract); // BlcokBreak/interact. - final BlockBreakData bbData = BlockBreakData.getData(player); + final BlockBreakData bbData = pData.getGenericInstance(BlockBreakData.class); ref = Math.max(ref, bbData.frequencyBuckets.lastUpdate()); ref = Math.max(ref, bbData.fastBreakfirstDamage); // TODO: More, less ... @@ -109,99 +132,6 @@ public class CheckUtils { return ref; } - /** - * Check for config flag and exemption (hasBypass). Meant thread-safe. - * - * @param checkType - * the check type - * @param player - * the player - * @param data - * If data is null, the data factory will be used for the given - * check type. - * @param cc - * If config is null, the config factory will be used for the - * given check type. - * @return true, if is enabled - */ - public static boolean isEnabled(final CheckType checkType, final Player player, - final ICheckConfig cc, final PlayerData pData) { - if (cc == null) { - if (!checkType.isEnabled(player)) { - return false; - } - } - else if (!cc.isEnabled(checkType)) { - return false; - } - return !hasBypass(checkType, player, pData); - } - - /** - * Check for exemption by permissions, API access, possibly other. Meant - * thread-safe. - * - * @see #hasBypass(CheckType, Player, ICheckData, boolean) - * - * @param checkType - * the check type - * @param player - * the player - * @param pData - * Must not be null. - * @return true, if successful - */ - public static boolean hasBypass(final CheckType checkType, final Player player, final PlayerData pData) { - // TODO: Checking for the thread might be a temporary measure. - return hasBypass(checkType, player, pData, Bukkit.isPrimaryThread()); - } - - /** - * Check for exemption by permissions, API access, possibly other. Meant - * thread-safe. - * - * @param checkType - * the check type - * @param player - * the player - * @param pData - * Must not be null. - * @param isPrimaryThread - * If set to true, this must be the primary server thread as - * returned by Bukkit.isPrimaryThread(). - * @return true, if successful - */ - public static boolean hasBypass(final CheckType checkType, final Player player, final PlayerData pData, - final boolean isPrimaryThread) { - // TODO: Thread testing should be removed, once thread-safe read is implemented for exemption too. - /* - * TODO: Thread context information may be part of a CheckPipeline - * object later on (alongside PlayerData and other policy stuff), - * replacing some of the arguments (IsPrimaryThread must be rock solid - * information.). - */ - - // TODO: Refine this error message +- put in place where it needs to be. - if (!isPrimaryThread && !CheckTypeUtil.needsSynchronization(checkType)) { - /* - * Checking for exemption can't cause harm anymore, however even - * fetching data or configuration might still lead to everything - * exploding. - */ - improperAPIAccess(checkType); - } - // Exemption check. - if (NCPExemptionManager.isExempted(player, checkType)) { - return true; - } - // Check permission policy/cache regardless of the thread context. - final RegisteredPermission permission = checkType.getPermission(); - if (permission != null && pData.hasPermission(permission, player)) { - return true; - } - return false; - } - /** * Static relay for the check-specific convenience methods, logging with * standard format ([check_type] [player_name] ...). @@ -240,40 +170,9 @@ public class CheckUtils { * * @return the random */ + // TODO: Move official stuff to some static direct access API. public static Random getRandom() { return NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Random.class); } - /** - * Update and then reduce all given ActionFrequency instances by the given - * amount, capped at a maximum of 0 for the resulting first bucket score. - * - * @param amount - * The amount to subtract. - * @param freqs - */ - public static void reduce(final long time, final float amount, final ActionFrequency... freqs) { - for (int i = 0; i < freqs.length; i++) { - final ActionFrequency freq = freqs[i]; - freq.update(time); - freq.setBucket(0, Math.max(0f, freq.bucketScore(0) - amount)); - } - } - - /** - * Update and then reduce all given ActionFrequency instances by the given - * amount, without capping the result. - * - * @param amount - * The amount to subtract. - * @param freqs - */ - public static void subtract(final long time, final float amount, final ActionFrequency... freqs) { - for (int i = 0; i < freqs.length; i++) { - final ActionFrequency freq = freqs[i]; - freq.update(time); - freq.setBucket(0, freq.bucketScore(0) - amount); - } - } - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/TickTask.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/TickTask.java index 9a2a443a..348e71e6 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/TickTask.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/TickTask.java @@ -155,7 +155,8 @@ public class TickTask implements Runnable { for (final Entry entry : updateMap.entrySet()) { final Player player = DataManager.getPlayer(entry.getKey()); if (player != null) { - Improbable.feed(player, entry.getValue().addLevel, System.currentTimeMillis()); + Improbable.feed(player, entry.getValue().addLevel, + System.currentTimeMillis(), DataManager.getPlayerData(player)); } // TODO: else: offline update or warn? } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/entity/PassengerUtil.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/entity/PassengerUtil.java index eff53efe..6e28130d 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/entity/PassengerUtil.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/entity/PassengerUtil.java @@ -30,6 +30,8 @@ import fr.neatmonster.nocheatplus.checks.workaround.WRPT; import fr.neatmonster.nocheatplus.compat.BridgeMisc; import fr.neatmonster.nocheatplus.components.entity.IEntityAccessVehicle; import fr.neatmonster.nocheatplus.components.registry.event.IHandle; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.CheckUtils; import fr.neatmonster.nocheatplus.utilities.location.LocUtil; import fr.neatmonster.nocheatplus.utilities.location.TrigUtil; @@ -167,11 +169,12 @@ public class PassengerUtil { * @param debug * the debug */ - public void teleportWithPassengers(final Entity vehicle, final Player player, final Location location, - final boolean debug) { + public void teleportWithPassengers(final Entity vehicle, final Player player, + final Location location, final boolean debug, final IPlayerData pData) { final List originalPassengers = handleVehicle.getHandle().getEntityPassengers(vehicle); teleportWithPassengers(vehicle, player, location, debug, - originalPassengers.toArray(new Entity[originalPassengers.size()]), false); + originalPassengers.toArray(new Entity[originalPassengers.size()]), + false, pData); } /** @@ -192,13 +195,14 @@ public class PassengerUtil { * @param CheckPassengers Set to true to compare current with original passengers. */ public void teleportWithPassengers(final Entity vehicle, final Player player, final Location location, - final boolean debug, final Entity[] originalPassengers, final boolean checkPassengers) { + final boolean debug, final Entity[] originalPassengers, final boolean checkPassengers, + final IPlayerData pData) { // TODO: Rubber band issue needs synchronizing with packet level and ignore certain incoming ones? // TODO: This handling could conflict with WorldGuard region flags. // TODO: Account for nested passengers and inconsistencies. // TODO: Conception: Restore the passengers at the time of setting the vehicle set back? - final MovingData data = MovingData.getData(player); + final MovingData data = pData.getGenericInstance(MovingData.class); data.isVehicleSetBack = true; int otherPlayers = 0; boolean playerIsOriginalPassenger = false; @@ -208,7 +212,8 @@ public class PassengerUtil { break; } else if (originalPassengers[i] instanceof Player) { - MovingData.getData((Player) originalPassengers[i]).isVehicleSetBack = true; + DataManager.getGenericInstance((Player) originalPassengers[i], + MovingData.class).isVehicleSetBack = true; otherPlayers ++; } } @@ -228,7 +233,7 @@ public class PassengerUtil { // } // } if (!playerIsOriginalPassenger) { - if (data.debug) { + if (debug) { CheckUtils.debug(player, CheckType.MOVING_VEHICLE, "Vehicle set back: This player is not an original passenger."); } // redoPassengers = true; @@ -271,7 +276,8 @@ public class PassengerUtil { // Add the player first, if not an original passenger (special case, idk, replaced by squids perhaps). if (!playerIsOriginalPassenger) { // (Not sure: always add first, until another case is needed.) - teleportPlayerPassenger(player, vehicle, location, vehicleTeleported, data); + teleportPlayerPassenger(player, vehicle, location, vehicleTeleported, + data, debug); } // Add all other original passengers in a generic way, distinguish players. for (int i = 0; i < originalPassengers.length; i++) { @@ -279,8 +285,10 @@ public class PassengerUtil { if (passenger.isValid() && !passenger.isDead()) { // Cross world cases? if (passenger instanceof Player) { - if (teleportPlayerPassenger((Player) passenger, vehicle, location, vehicleTeleported, - MovingData.getData((Player) passenger))) { + if (teleportPlayerPassenger((Player) passenger, + vehicle, location, vehicleTeleported, + DataManager.getGenericInstance((Player) passenger, MovingData.class), + debug)) { if (player.equals(passenger)) { playerTeleported = true; } @@ -323,7 +331,8 @@ public class PassengerUtil { * @return */ private final boolean teleportPlayerPassenger(final Player player, final Entity vehicle, - final Location location, final boolean vehicleTeleported, final MovingData data) { + final Location location, final boolean vehicleTeleported, final MovingData data, + final boolean debug) { final boolean playerTeleported; if (player.isOnline() && !player.isDead()) { // Mask player teleport as a set back. @@ -345,7 +354,7 @@ public class PassengerUtil { // TODO: Set backs get invalidated somewhere, likely on an extra unknown TP. Use data.isVehicleSetBack in MovingListener/teleport. if (data.vehicleSetBacks.getFirstValidEntry(location) == null) { // At least ensure one of the entries has to match the location we teleported the vehicle to. - if (data.debug) { + if (debug) { CheckUtils.debug(player, CheckType.MOVING_VEHICLE, "No set back is matching the vehicle location that it has just been set back to. Reset all lazily to: " + location); } data.vehicleSetBacks.resetAllLazily(location); @@ -354,7 +363,7 @@ public class PassengerUtil { final VehicleMoveData firstPastMove = data.vehicleMoves.getFirstPastMove(); if (!firstPastMove.valid || firstPastMove.toIsValid || !TrigUtil.isSamePos(firstPastMove.from, location)) { - final MovingConfig cc = MovingConfig.getConfig(player); + final MovingConfig cc = DataManager.getGenericInstance(player, MovingConfig.class); NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(AuxMoving.class).resetVehiclePositions(vehicle, location, data, cc); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/IWorldCheckNode.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/IWorldCheckNode.java new file mode 100644 index 00000000..b3cd305f --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/IWorldCheckNode.java @@ -0,0 +1,41 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.worlds; + +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; +import fr.neatmonster.nocheatplus.components.data.checktype.IConfigCheckNode; + +/** + * Per world per check type node for most efficient direct access. + * + * @author asofold + * + */ +public interface IWorldCheckNode extends IConfigCheckNode { + + /** + * Get the override type for the debug flag. + * + * @return + */ + public OverrideType getOverrideTypeDebug(); + + /** + * Server side lag detection - migth also do different things - subject to + * rename / change. + */ + public boolean shouldAdjustToLag(); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/IWorldData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/IWorldData.java new file mode 100644 index 00000000..d6a54b2d --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/IWorldData.java @@ -0,0 +1,66 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.worlds; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.components.data.checktype.IConfigDataAccess; +import fr.neatmonster.nocheatplus.components.registry.IGetGenericInstance; +import fr.neatmonster.nocheatplus.components.registry.IGetGenericInstanceHandle; + +/** + * Public access interface for per-world data. + * + * @author asofold + * + */ +public interface IWorldData extends IConfigDataAccess, IGetGenericInstance, IGetGenericInstanceHandle { + + + /** + * Overridden to provide extra per-world functionality. See: + * {@link fr.neatmonster.nocheatplus.components.data.checktype.IConfigDataAccess} + */ + @Override + public IWorldCheckNode getCheckNode(CheckType checkType); + + /** + * Retrieve the world name this instance has been registered for. To prevent + * issues with misspelling on commands and configuration, the lower case + * variant is the main identifier. + * + * @return + */ + public String getWorldNameLowerCase(); + + /** + * Get an object containing exact case name and UUID. + * + * @return In case the world hasn't been loaded, null will be returned. + */ + public WorldIdentifier getWorldIdentifier(); + + /** + * Server side lag adaption flag - subject to rename / change. + * + * @param checkType + * @return + */ + public boolean shouldAdjustToLag(CheckType checkType); + + // TODO: Generic data (includes config) storage. + + // TODO: isDebugActive(CheckType checkType); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/IWorldDataManager.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/IWorldDataManager.java new file mode 100644 index 00000000..7da493c6 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/IWorldDataManager.java @@ -0,0 +1,143 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.worlds; + +import java.util.Iterator; +import java.util.Map.Entry; + +import org.bukkit.World; +import org.bukkit.entity.Player; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; + +public interface IWorldDataManager { + + /** + * Get the default world data, which applies for all worlds for which no + * specific raw configuration exists. + *
    + * Thread-safe. + *
    + * + * @return + */ + public IWorldData getDefaultWorldData(); + + /** + * Get the world data for a specific world name (case insensitive!). Creates + * a new (inherited from default) WorlData instance, if none is set yet. + *
    + * Thread-safe. + *
    + * + * @param worldName + * @return + */ + public IWorldData getWorldData(String worldName); + + /** + * Bukkit specific convenience method. Further see: + * {@link #getWorldData(String)} + *
    + * The touched plugin internals are thread-safe, the thread-safety depends + * on the Bukkit world methods getName() and getUID(). If the world instance + * is present, this likely is no problem - in order to be sure to fetch the + * appropriate (existing) world data for proxy Player instances that don't + * support worlds, use + * PlayerData.getWorldIdentifier().getLowerCaseWorldName(). + *
    + * + * @param newWorld + * @return + */ + public IWorldData getWorldData(World world); + + /** + * Thread-safe read-only iterator, see: + * {@link fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW#iterator()} + * + * @return + */ + public Iterator> getWorldDataIterator(); + + /** + * Thread-safe Iterable, see: + * {@link fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW#iterator()} + * + * @return + */ + public Iterable> getWorldDataIterable(); + + /** + * Update with the underlying raw configurations as reference (stored + * instances). + *
    + * Thread-safety uncertain: better regard as registry functionality, thus + * primary thread only. + *
    + */ + public void updateAllWorldData(); + + /** + * Override check activation for all stored configurations. It's not + * necessary to call updateAllWorldData afterwards. + *
    + * Assume to be typical registry functionality, thus primary thread only. + *
    + * + * @param checkType + * @param active + * MAYBE means that the super type is checked for activation. + * @param overrideType + * Set to CUSTOM or PERMANENT to prevent any resetting with + * reloading the configuration. Use VOLATILE to ensure it's reset + * the next time an update is done on that node. + * @param overrideChildren + * If set to true, all children will be attempted to be + * overridden too. If set to false, children will just be + * updated. + * @throws IllegalArgumentException + * If the configuration path for the activation flag of the + * given check type is not set explicitly. + */ + public void overrideCheckActivation(CheckType type, AlmostBoolean active, + OverrideType overrideType, boolean overrideChildren); + + /** + * Test if the check is activated in any stored world data. + *
    + * TBD: This includes data for already unloaded worlds. + *
    + * Thread-safe. + *
    + * + * @param checkType + * @return + */ + public boolean isActiveAnywhere(CheckType checkType); + + /** + * Some implementations throw an UnsupportedOperationException for + * {@link org.bukkit.entity.Player#getWorld()}. - this does not check for + * IWorldData instances already stored within PlayerData. + * + * @param player + * @return + */ + public IWorldData getWorldDataSafe(Player player); + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/WorldData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/WorldData.java new file mode 100644 index 00000000..5375093d --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/WorldData.java @@ -0,0 +1,394 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.worlds; + +import java.util.Collection; +import java.util.LinkedHashSet; + +import org.bukkit.World; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.AlmostBooleanWithOverride; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; +import fr.neatmonster.nocheatplus.components.data.checktype.CheckNodeWithDebug; +import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree; +import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree.CheckTypeTreeNodeFactory; +import fr.neatmonster.nocheatplus.components.registry.DefaultGenericInstanceRegistry; +import fr.neatmonster.nocheatplus.components.registry.GenericInstanceRegistry; +import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle; +import fr.neatmonster.nocheatplus.config.ConfigFile; + +/** + * Data stored per world. + * + * @author asofold + * + */ +public class WorldData implements IWorldData { + + private static class WorldCheckTypeTreeNode extends CheckNodeWithDebug implements IWorldCheckNode { + + private static class AccessActive implements IConfigFlagAccess { + + @Override + public AlmostBooleanWithOverride getConfigState(WorldCheckTypeTreeNode node) { + return node.configActivation; + } + + @Override + public boolean getState(WorldCheckTypeTreeNode node) { + return node.active; + } + + @Override + public void setState(WorldCheckTypeTreeNode node, boolean state) { + node.active = state; + } + + @Override + public String getConfigPath(WorldCheckTypeTreeNode node) { + return node.getCheckType().getConfigPathActive(); + } + + }; + + private static class AccessLag implements IConfigFlagAccess { + + @Override + public AlmostBooleanWithOverride getConfigState(WorldCheckTypeTreeNode node) { + return node.configLag; + } + + @Override + public boolean getState(WorldCheckTypeTreeNode node) { + return node.lag; + } + + @Override + public void setState(WorldCheckTypeTreeNode node, boolean state) { + node.lag = state; + } + + @Override + public String getConfigPath(WorldCheckTypeTreeNode node) { + return node.getCheckType().getConfigPathLag(); + } + + }; + + @SuppressWarnings("rawtypes") + private static AccessActive accessActive = new AccessActive(); + + @SuppressWarnings("rawtypes") + private static AccessLag accessLag = new AccessLag(); + + /** The configuration value, featuring overriding. */ + private final AlmostBooleanWithOverride configActivation = new AlmostBooleanWithOverride(); + /** The pulled down actual state, may include parent nodes. */ + private boolean active = true; + + /** The configuration value, featuring overriding. */ + private final AlmostBooleanWithOverride configLag = new AlmostBooleanWithOverride(); + /** The pulled down actual state, may include parent nodes. */ + private boolean lag = false; + + WorldCheckTypeTreeNode(CheckType checkType, + WorldCheckTypeTreeNode parent, + CheckTypeTreeNodeFactory factory) { + super(checkType, parent, factory); + } + + /** + * Set recursively. + * @param configOverrideType + */ + void setConfigOverrideType(final OverrideType configOverrideType) { + this.configOverrideType = configOverrideType; + for (final WorldCheckTypeTreeNode child: getChildren()) { + child.setConfigOverrideType(configOverrideType); + } + } + + /** + * Non-recursive in-place adjustments, no calls to update. Excludes + * configOverrideType. Inherit overrides. + * + * @param parentNode + */ + void adjustToParent(final WorldCheckTypeTreeNode parentNode) { + configOverrideType = OverrideType.DEFAULT; + // Activation - replace SPECIFIC by DEFAULT, as this node inherits from a default. + if (configActivation.setValue(parentNode.configActivation.getValue(), configOverrideType)) { + active = parentNode.active; + } + if (configDebug.setValue(parentNode.configDebug.getValue(), configOverrideType)) { + debug = parentNode.debug; + } + } + + /** + * General update to a potentially changed configuration. + * + * @param rawConfiguration + */ + void update(final ConfigFile rawConfiguration) { + // TODO: A multi update method walking all nodes only once. + updateActivation(rawConfiguration, true); + updateDebug(rawConfiguration, true); + updateLag(rawConfiguration, true); + // TODO: contained configurations. + } + + @SuppressWarnings("unchecked") + private void updateLag(final ConfigFile rawConfiguration, + final boolean forceUpdateChildren) { + configFlagUpdate(rawConfiguration, forceUpdateChildren, accessLag); + } + + @SuppressWarnings("unchecked") + void overrideCheckActivation(final ConfigFile rawConfiguration, + final AlmostBoolean active, final OverrideType overrideType, + final boolean overrideChildren) { + configFlagOverride(rawConfiguration, active, + overrideType, overrideChildren, accessActive); + } + + /** + * Just update the check activation property. + * + * @param rawConfiguration + * @param forceUpdateChildren + * If set to true, children activation state will be + * force-updated recursively. Otherwise, children will only + * be updated, if their activation depends on the parent. + */ + @SuppressWarnings("unchecked") + void updateActivation(final ConfigFile rawConfiguration, + final boolean forceUpdateChildren) { + + configFlagUpdate(rawConfiguration, forceUpdateChildren, accessActive); + } + + @Override + public boolean isCheckActive() { + return active; + } + + @Override + public OverrideType getOverrideTypeDebug() { + return configDebug.getOverrideType(); + } + + @Override + public boolean shouldAdjustToLag() { + return lag; + } + + } + + private static class WorldCheckTypeTree extends CheckTypeTree { + + private OverrideType configOverrideType = OverrideType.DEFAULT; + + @Override + protected WorldCheckTypeTreeNode newNode(CheckType checkType, + WorldCheckTypeTreeNode parent, + CheckTypeTreeNodeFactory factory) { + return new WorldCheckTypeTreeNode(checkType, parent, factory); + } + + void setConfigOverrideType(OverrideType configOverrideType) { + if (this.configOverrideType != configOverrideType) { + this.configOverrideType = configOverrideType; + getNode(CheckType.ALL).setConfigOverrideType(configOverrideType); + } + } + + } + + /////////////////// + // Instance. + /////////////////// + + // /** World wide lock ;). */ + // private final Lock lock = new ReentrantLock(); + + WorldData parent = null; + private final Collection children = new LinkedHashSet(); + private final GenericInstanceRegistry dataRegistry = new DefaultGenericInstanceRegistry(); + + private ConfigFile rawConfiguration = null; + + private final WorldCheckTypeTree checkTypeTree = new WorldCheckTypeTree(); + + private final String worldNameLowerCase; + private WorldIdentifier worldIdentifier = null; + + WorldData(String worldName) { + this(worldName, null); + } + + WorldData(String worldName, WorldData parent) { + // TODO: ILockable ? + this.parent = parent; + this.worldNameLowerCase = worldName.toLowerCase(); // Locale.ENGLISH ? + if (parent == null) { + checkTypeTree.setConfigOverrideType(OverrideType.SPECIFIC); + } + else { + adjustToParent(parent); + } + } + + /** + * Adjust specific overrides and update. + * + * @param parent + */ + void adjustToParent(final WorldData parent) { + // This may be called during runtime. + this.parent = parent; + this.rawConfiguration = parent.rawConfiguration; + checkTypeTree.setConfigOverrideType(OverrideType.DEFAULT); + for (final CheckType checkType : CheckType.values()) { + checkTypeTree.getNode(checkType).adjustToParent( + parent.checkTypeTree.getNode(checkType)); + } + // Force update. + checkTypeTree.getNode(CheckType.ALL).update(rawConfiguration); + // TODO: What if children exist? + } + + /** + * Must be under external lock for now. + * @param childData + */ + void addChild(WorldData childData) { + /* + * TODO: Locking or not. -> if we never call WorldDataManager.something + * from in here. extra lock is feasible anyway. + */ + this.children.add(childData); + } + + /** + * Must be under external lock for now. + * @param childData + */ + void removeChild(WorldData childData) { + /* + * TODO: Locking or not. -> if we never call WorldDataManager.something + * from in here. extra lock is feasible anyway. + */ + this.children.remove(childData); + } + + /** + * Must be under external lock for now. + */ + void clearChildren() { + // Change to specific configuration. + this.children.clear(); + } + + @Override + public ConfigFile getRawConfiguration() { + return rawConfiguration; + } + + void update(final ConfigFile rawConfiguration) { + // TODO: Locking ? + this.rawConfiguration = rawConfiguration; + if (this.parent != null && rawConfiguration != this.parent.rawConfiguration) { + this.parent = null; + this.parent.removeChild(this); + this.checkTypeTree.getNode(CheckType.ALL).setConfigOverrideType(OverrideType.SPECIFIC); + } + this.update(); + } + + void update() { + // TODO: Locking ? + checkTypeTree.getNode(CheckType.ALL).update(rawConfiguration); + } + + @Override + public boolean isCheckActive(final CheckType checkType) { + return checkTypeTree.getNode(checkType).active; + } + + @Override + public boolean isDebugActive(final CheckType checkType) { + return getCheckNode(checkType).isDebugActive(); + } + + @Override + public void overrideCheckActivation(final CheckType checkType, + final AlmostBoolean active, final OverrideType overrideType, + final boolean overrideChildren) { + // TODO: Concept for locking. + checkTypeTree.getNode(checkType).overrideCheckActivation(rawConfiguration, active, overrideType, overrideChildren); + } + + @Override + public IWorldCheckNode getCheckNode(final CheckType checkType) { + return checkTypeTree.getNode(checkType); + } + + @Override + public T getGenericInstance(final Class registeredFor) { + // TODO: Factories. + return dataRegistry.getGenericInstance(registeredFor); + } + + @Override + public IGenericInstanceHandle getGenericInstanceHandle(final Class registeredFor) { + // TODO: Factories. + return dataRegistry.getGenericInstanceHandle(registeredFor); + } + + @Override + public String getWorldNameLowerCase() { + return worldNameLowerCase; + } + + public void updateWorldIdentifier(final WorldIdentifier worldIdentifier) { + if (this.worldNameLowerCase.equals(worldIdentifier.lowerCaseName)) { + // Prefer to keep the initial instance. + if (this.worldIdentifier == null || !this.worldIdentifier.equals(worldIdentifier)) { + this.worldIdentifier = worldIdentifier; + } + } + else { + throw new IllegalArgumentException("Lower case names must match."); + } + } + + public void updateWorldIdentifier(final World world) { + updateWorldIdentifier(new WorldIdentifier(world.getName(), world.getUID())); + } + + @Override + public WorldIdentifier getWorldIdentifier() { + return worldIdentifier; + } + + @Override + public boolean shouldAdjustToLag(CheckType checkType) { + return getCheckNode(checkType).shouldAdjustToLag(); + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/WorldDataManager.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/WorldDataManager.java new file mode 100644 index 00000000..b0093e09 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/WorldDataManager.java @@ -0,0 +1,331 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.worlds; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Player; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; +import fr.neatmonster.nocheatplus.config.ConfigFile; +import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW; + +public class WorldDataManager implements IWorldDataManager { + + static class IWorldDataEntry implements Entry { + + private final Entry entry; + + IWorldDataEntry(Entry entry) { + this.entry = entry; + } + + @Override + public String getKey() { + return entry.getKey(); + } + + @Override + public IWorldData getValue() { + return entry.getValue(); + } + + @Override + public IWorldData setValue(IWorldData value) { + throw new UnsupportedOperationException(); + } + + } + + static class IWorldDataIterator implements Iterator> { + + private final Iterator> iterator; + + IWorldDataIterator(Iterator> iterator) { + this.iterator = iterator; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public Entry next() { + return new IWorldDataEntry(iterator.next()); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + // TODO: debug flags like activation? + // TODO: Factory registration. + + /** Global access lock for this registry. Also used for ConfigFile editing. */ + private final Lock lock = new ReentrantLock(); + + /** Exact case name to WorldData map. */ + // TODO: ID-name pairs / mappings? + private final HashMapLOW worldDataMap = new HashMapLOW(lock, 10); + private Map rawConfigurations = new HashMap(); // COW + + public WorldDataManager() { + // TODO: ILockable + // TODO: Create a default node with some basic settings. + createDefaultWorldData(); + } + + @Override + public IWorldData getDefaultWorldData() { + return internalGetDefaultWorldData(); + } + + @Override + public IWorldData getWorldData(final String worldName) { + return internalGetWorldData(worldName.toLowerCase()); + } + + @Override + public IWorldData getWorldData(final World world) { + final WorldData worldData = internalGetWorldData(world.getName().toLowerCase()); + if (worldData.getWorldIdentifier() == null) { + worldData.updateWorldIdentifier(world); + } + return worldData; + } + + /** + * Internal get or create for the lower case world name. + * + * @param lowerCaseWorldName + * In case of the default WorldData, null is used internally. + * @return + */ + private WorldData internalGetWorldData(final String lowerCaseWorldName) { + final WorldData worldData = worldDataMap.get(lowerCaseWorldName); + if (worldData != null) { + return worldData; + } + else { + return createWorldData(lowerCaseWorldName); + } + } + + private WorldData internalGetDefaultWorldData() { + // TODO: Store the instance extra to the map. + return worldDataMap.get(null); + } + + private void createDefaultWorldData() { + createWorldData(null); + } + + /** + * Create if not present (check under lock). + * @param worldName + * @return + */ + private WorldData createWorldData(final String worldName) { + return updateWorldData(worldName, getDefaultWorldData().getRawConfiguration()); + } + + @Override + public Iterator> getWorldDataIterator() { + return new IWorldDataIterator(worldDataMap.iterator()); + } + + @Override + public Iterable> getWorldDataIterable() { + final Iterator> iterator = getWorldDataIterator(); + return new Iterable>() { + @Override + public Iterator> iterator() { + return iterator; + } + }; + } + + /** + * The given ConfigFile instances are stored within WorldData. + * + * @param rawWorldConfigs + */ + public void applyConfiguration(final Map rawWorldConfigs) { + // TODO: ILockable + /* + * Minimal locking is used, to prevent deadlocks, in case WorldData + * instances will hold individual locks. + */ + lock.lock(); + final Map rawConfigurations = new LinkedHashMap(rawWorldConfigs.size()); + for (final Entry entry : rawWorldConfigs.entrySet()) { + rawConfigurations.put(entry.getKey().toLowerCase(), entry.getValue()); + } + final ConfigFile defaultConfig = this.rawConfigurations.get(null); + final WorldData defaultWorldData = internalGetDefaultWorldData(); // Always the same instance. + this.rawConfigurations = rawConfigurations; + defaultWorldData.update(defaultConfig); + lock.unlock(); // From here on, new instances have a proper config set. + // Update all given + for (final Entry entry : rawConfigurations.entrySet()) { + final String worldName = entry.getKey(); + if (worldName != null) { + /* + * Children adding and removal for defaultWorldData is handled + * in updateWorldData. + */ + updateWorldData(worldName, entry.getValue()); + } + } + // Update all that are not contained and don't point to the default configuration. + // TODO: Consider deleting world nodes, unless the world is actually loaded. + for (final Entry entry : worldDataMap.iterable()) { + if (!rawConfigurations.containsKey(entry.getKey())) { + final WorldData ref = entry.getValue(); + if (ref.getRawConfiguration() != defaultConfig) { + lock.lock(); + defaultWorldData.addChild(ref); // Redundant calls are ok. + ref.adjustToParent(defaultWorldData); // Inherit specific overrides and more. + lock.unlock(); + } + } + } + } + + /** + * Remove world data that is inherited from default, but for which no world + * is loaded. Note that calling this may conflict with external plugins + * preparing settings for just not yet loaded worlds. Intended to be called + * with rare tasks rather. + *
    + * Primary thread only. + *
    + */ + public void removeOfflineInheritedWorldData() { + final Set worldNames = new HashSet(); + for (World world : Bukkit.getWorlds()) { + worldNames.add(world.getName().toLowerCase()); + } + final List remove = new LinkedList(); + for (final Entry entry : worldDataMap.iterable()) { + final String lcName = entry.getKey(); + if (!rawConfigurations.containsKey(lcName) && ! worldNames.contains(lcName)) { + remove.add(lcName); + } + } + worldDataMap.remove(remove); // Same lock is used (where necessary). + } + + @Override + public void updateAllWorldData() { + // TODO: ILockable / move to an access object ? + lock.lock(); + final WorldData defaultWorldData = internalGetDefaultWorldData(); + defaultWorldData.update(); + for (final Entry entry : worldDataMap.iterable()) { + final WorldData ref = entry.getValue(); + if (ref != defaultWorldData) { + ref.update(); + } + } + lock.unlock(); + } + + /** + * Create if not existent (under lock). In any case simply call + * WorldData.update (under lock). Updates children and parent relation with + * the default WorldData instance. + * + * @param worldName + * @param rawConfiguration + * @return + */ + private WorldData updateWorldData(final String worldName, final ConfigFile rawConfiguration) { + final WorldData defaultWorldData = internalGetDefaultWorldData(); + lock.lock(); // TODO: Might lock outside (pro/con). + final String lcName = worldName.toLowerCase(); + WorldData data = worldDataMap.get(lcName); + if (data == null) { + data = new WorldData(worldName, defaultWorldData); + worldDataMap.put(worldName.toLowerCase(), data); + defaultWorldData.addChild(data); + } + data.update(rawConfiguration); // Parent/child state is updated here. + lock.unlock(); + return data; + } + + @Override + public void overrideCheckActivation(final CheckType checkType, final AlmostBoolean active, + final OverrideType overrideType, final boolean overrideChildren) { + + // TODO: Implement changed signature + // + lock.lock(); + // Override flags. + // TODO: If not under lock, default WorldData needs to be done first. + // TODO: If possible, skip derived from default, once default data is done first. + for (final Entry entry : worldDataMap.iterable()) { + final WorldData worldData = entry.getValue(); + // TODO: default visibility method including overrideChildWorldDatas (here: false). + worldData.overrideCheckActivation(checkType, active, overrideType, overrideChildren); + } + lock.unlock(); + } + + @Override + public boolean isActiveAnywhere(final CheckType checkType) { + for (final Entry entry : worldDataMap.iterable()) { + if (entry.getValue().isCheckActive(checkType)) { + return true; + } + } + return false; + } + + public void updateWorldIdentifier(World world) { + internalGetWorldData(world.getName().toLowerCase()).updateWorldIdentifier(world); + } + + @Override + public IWorldData getWorldDataSafe(Player player) { + // (Hope the JIT specializes for odd impl.) + try { + return getWorldData(player.getWorld()); + } + catch (UnsupportedOperationException e) { + // Proxy/Fake/Packet. + return getDefaultWorldData(); + } + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/WorldIdentifier.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/WorldIdentifier.java new file mode 100644 index 00000000..6239bfed --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/worlds/WorldIdentifier.java @@ -0,0 +1,56 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.worlds; + +import java.util.UUID; + +public class WorldIdentifier { + + public final String lowerCaseName; + public final String exactName; + public final UUID id; + + public WorldIdentifier(String exactName, UUID id) { + this.lowerCaseName = exactName.toLowerCase(); + this.exactName = exactName; + this.id = id; + } + + @Override + public int hashCode() { + return exactName.hashCode() ^ id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + else if (obj instanceof WorldIdentifier) { + final WorldIdentifier other = (WorldIdentifier) obj; + return exactName.equals(other.exactName) && id.equals(other.id); + } + else if (obj instanceof String) { + return lowerCaseName.equalsIgnoreCase((String) obj); + } + else if (obj instanceof UUID) { + return id.equals((UUID) obj); + } + else { + return false; + } + } + +} diff --git a/NCPCore/src/test/java/fr/neatmonster/nocheatplus/test/TestBasicLockable.java b/NCPCore/src/test/java/fr/neatmonster/nocheatplus/test/TestBasicLockable.java index e4d65d54..72d8c215 100644 --- a/NCPCore/src/test/java/fr/neatmonster/nocheatplus/test/TestBasicLockable.java +++ b/NCPCore/src/test/java/fr/neatmonster/nocheatplus/test/TestBasicLockable.java @@ -1,3 +1,17 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package fr.neatmonster.nocheatplus.test; import static org.junit.Assert.fail; diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/NoCheatPlus.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/NoCheatPlus.java index 194c19af..8e70739a 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/NoCheatPlus.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/NoCheatPlus.java @@ -32,6 +32,7 @@ import java.util.Set; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Player; @@ -44,6 +45,7 @@ import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permission; import org.bukkit.plugin.PluginDescriptionFile; @@ -120,7 +122,9 @@ import fr.neatmonster.nocheatplus.permissions.PermissionUtil.CommandProtectionEn import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; import fr.neatmonster.nocheatplus.players.DataManager; -import fr.neatmonster.nocheatplus.players.PlayerData; +import fr.neatmonster.nocheatplus.players.IPlayerDataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; +import fr.neatmonster.nocheatplus.players.PlayerDataManager; import fr.neatmonster.nocheatplus.players.PlayerMessageSender; import fr.neatmonster.nocheatplus.stats.Counters; import fr.neatmonster.nocheatplus.utilities.ColorUtil; @@ -131,6 +135,8 @@ import fr.neatmonster.nocheatplus.utilities.TickTask; import fr.neatmonster.nocheatplus.utilities.entity.PassengerUtil; import fr.neatmonster.nocheatplus.utilities.map.BlockCache; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; +import fr.neatmonster.nocheatplus.worlds.IWorldDataManager; +import fr.neatmonster.nocheatplus.worlds.WorldDataManager; /** * This is the main class of NoCheatPlus. The commands, events listeners and tasks are registered here. @@ -170,9 +176,12 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { // /** Is a new update available? */ // private boolean updateAvailable = false; + // TODO: per world permission registry (!). private final PermissionRegistry permissionRegistry = new PermissionRegistry(10000); - /** Player data. */ - private final DataManager dataMan = new DataManager(permissionRegistry); + /** Per world data. */ + private final WorldDataManager worldDataManager = new WorldDataManager(); + /** Player data / general data manager +- soon to be legacy static API. */ + private final PlayerDataManager pDataMan = new PlayerDataManager(worldDataManager, permissionRegistry); private int dataManTaskId = -1; @@ -261,6 +270,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { } /** Access point for thread safe message queuing. */ + // TODO: Replace by access point for message sending in general (relay to asynchronous depending on settings). private final PlayerMessageSender playerMessageSender = new PlayerMessageSender(); private boolean clearExemptionsOnJoin = true; @@ -383,7 +393,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { if (sender instanceof Player) { // Use the permission caching feature. final Player player = (Player) sender; - final PlayerData data = DataManager.getPlayerData(player); + final IPlayerData data = DataManager.getPlayerData(player); if (data.getNotifyOff() || !data.hasPermission(Permissions.NOTIFY, player)) { continue; } @@ -838,7 +848,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { } // Configuration. if (!ConfigManager.isInitialized()) { - ConfigManager.init(this); + ConfigManager.init(this, worldDataManager); // Basic setup for exemption (uses CheckType). This is redundant, but should not hurt. NCPExemptionManager.setExemptionSettings(new ExemptionSettings(ConfigManager.getConfigFile())); } @@ -891,7 +901,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { if (Bugs.shouldPvpKnockBackVelocity()) { addFeatureTags("defaults", Arrays.asList("pvpKnockBackVelocity")); } - if (dataMan.storesPlayerInstances()) { + if (pDataMan.storesPlayerInstances()) { addFeatureTags("defaults", Arrays.asList("storePlayers")); } @@ -917,6 +927,11 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { registerGenericInstance(new Random(System.currentTimeMillis() ^ ((long) this.hashCode() * (long) eventRegistry.hashCode() * (long) logManager.hashCode()))); addComponent(new BridgeCrossPlugin()); + // World data init (basic). + for (final World world : Bukkit.getWorlds()) { + onWorldPresent(world); + } + // Initialize MCAccess. initMCAccess(config); @@ -924,7 +939,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { initBlockProperties(config); // Initialize data manager. - dataMan.onEnable(); + pDataMan.onEnable(); // Register components. @SetupOrder(priority = - 100) @@ -941,7 +956,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { getCoreListener(), // Put ReloadListener first, because Checks could also listen to it. new ReloadHook(), - dataMan, + pDataMan, new AuxMoving(), }) { addComponent(obj); @@ -998,13 +1013,13 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { this.dataManTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new Runnable() { @Override public void run() { - dataMan.checkExpiration(); + pDataMan.checkExpiration(); } }, 1207, 1207); // Ensure dataMan is first on disableListeners. - disableListeners.remove(dataMan); - disableListeners.add(0, dataMan); + disableListeners.remove(pDataMan); + disableListeners.add(0, pDataMan); // Set up consistency checking. scheduleConsistencyCheckers(); @@ -1083,9 +1098,11 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { logManager.severe(Streams.INIT, "Failed to apply command protection: " + t.getClass().getSimpleName()); logManager.severe(Streams.INIT, t); } + // TODO: This should be a registered handler. for (final Player player : onlinePlayers) { + final IPlayerData pData = DataManager.getPlayerData(player); if (player.isSleeping()) { - CombinedData.getData(player).wasInBed = true; + pData.getGenericInstance(CombinedData.class).wasInBed = true; } } if (onlinePlayers.length > 0) { @@ -1278,12 +1295,30 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { public void onPlayerQuit(final PlayerQuitEvent event) { onLeave(event.getPlayer()); } + + @EventHandler(priority = EventPriority.MONITOR) + public void onWorldLoad(final WorldLoadEvent event) { + NoCheatPlus.this.onWorldLoad(event); + } }; } + private void onWorldLoad(final WorldLoadEvent event) { + onWorldPresent(event.getWorld()); + } + + /** + * Called for all worlds we encounter (onEnable, WorldLoadEvent). + * + * @param world + */ + private void onWorldPresent(final World world) { + worldDataManager.updateWorldIdentifier(world); + } + private void onJoinLow(final Player player) { final String playerName = player.getName(); - final PlayerData data = DataManager.getPlayerData(player); + final IPlayerData data = DataManager.getPlayerData(player); if (data.hasPermission(Permissions.NOTIFY, player)) { // Updates the cache. // Login notifications... // // Update available. @@ -1473,4 +1508,14 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI { return permissionRegistry; } + @Override + public IWorldDataManager getWorldDataManager() { + return worldDataManager; + } + + @Override + public IPlayerDataManager getPlayerDataManager() { + return pDataMan; + } + } diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/compat/registry/MCAccessFactory.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/compat/registry/MCAccessFactory.java index 994f29c9..f45f8d58 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/compat/registry/MCAccessFactory.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/compat/registry/MCAccessFactory.java @@ -33,7 +33,7 @@ import fr.neatmonster.nocheatplus.logging.StaticLog; public class MCAccessFactory { private final String[] updateLocs = new String[] { - " Check for updates and support at BukkitDev: https://dev.bukkit.org/server-mods/nocheatplus/", + " Check for updates and support at BukkitDev: https://dev.bukkit.org/projects/nocheatplus/", " Development builds (unsupported by the Bukkit Staff, use at your own risk): https://ci.md-5.net/job/NoCheatPlus/changes", }; diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/hooks/allviolations/AllViolationsHook.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/hooks/allviolations/AllViolationsHook.java index bef1d522..20c9c36a 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/hooks/allviolations/AllViolationsHook.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/hooks/allviolations/AllViolationsHook.java @@ -24,8 +24,6 @@ import org.bukkit.entity.Player; import fr.neatmonster.nocheatplus.NCPAPIProvider; import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.checks.CheckType; -import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; -import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.checks.access.IViolationInfo; import fr.neatmonster.nocheatplus.hooks.ILast; import fr.neatmonster.nocheatplus.hooks.IStats; @@ -33,6 +31,8 @@ import fr.neatmonster.nocheatplus.hooks.NCPHook; import fr.neatmonster.nocheatplus.hooks.NCPHookManager; import fr.neatmonster.nocheatplus.logging.LogManager; import fr.neatmonster.nocheatplus.logging.Streams; +import fr.neatmonster.nocheatplus.players.DataManager; +import fr.neatmonster.nocheatplus.players.IPlayerData; import fr.neatmonster.nocheatplus.utilities.StringUtil; /** @@ -106,23 +106,14 @@ public class AllViolationsHook implements NCPHook, ILast, IStats { } boolean debugSet = false; if (config.debugOnly || config.debug) { - // TODO: Better mix the debug flag into IViolationInfo, for best performance. - final CheckDataFactory factory = checkType.getDataFactory(); - if (config.debugOnly && factory == null) { + // TODO: Better mix the debug flag into IViolationInfo, for best performance AND consistency. + // TODO: (If debug is not in IViolationInfo, switch to PlayerData.isDebug(CheckType).) + final IPlayerData pData = DataManager.getPlayerData(player); + debugSet = pData.isDebugActive(checkType); + if (config.debugOnly && !debugSet) { return false; - } else { - final ICheckData data = factory.getData(player); - if (data == null) { - if (config.debugOnly) { - return false; - } - } else { - debugSet = data.getDebug(); - if (config.debugOnly && !debugSet) { - return false; - } - } } + } log(checkType, player, info, config.allToTrace || debugSet, config.allToNotify); return false; diff --git a/NCPPlugin/src/main/resources/plugin.yml b/NCPPlugin/src/main/resources/plugin.yml index fb1541be..fbc93a6b 100644 --- a/NCPPlugin/src/main/resources/plugin.yml +++ b/NCPPlugin/src/main/resources/plugin.yml @@ -104,6 +104,8 @@ permissions: default: false nocheatplus.checks.fight.speed.silent: default: false + nocheatplus.checks.fight.wrongturn.silent: + default: false nocheatplus.checks.inventory.drop.silent: default: false nocheatplus.checks.inventory.fastclick.silent: @@ -248,6 +250,8 @@ permissions: description: Allow the player to bypass the SelfHit check. nocheatplus.checks.fight.speed: description: Allow the player to bypass the Speed check. + nocheatplus.checks.fight.wrongturn: + description: Allow the player to bypass the WrongTurn check. nocheatplus.checks.inventory: description: Allow the player to bypass all Inventory checks. children: diff --git a/NCPPlugin/src/test/java/fr/neatmonster/nocheatplus/PluginTests.java b/NCPPlugin/src/test/java/fr/neatmonster/nocheatplus/PluginTests.java index f6e8de42..d5618f84 100644 --- a/NCPPlugin/src/test/java/fr/neatmonster/nocheatplus/PluginTests.java +++ b/NCPPlugin/src/test/java/fr/neatmonster/nocheatplus/PluginTests.java @@ -31,6 +31,8 @@ import fr.neatmonster.nocheatplus.logging.StaticLog; import fr.neatmonster.nocheatplus.permissions.PermissionRegistry; import fr.neatmonster.nocheatplus.permissions.Permissions; import fr.neatmonster.nocheatplus.permissions.RegisteredPermission; +import fr.neatmonster.nocheatplus.players.IPlayerDataManager; +import fr.neatmonster.nocheatplus.worlds.WorldDataManager; public class PluginTests { @@ -44,6 +46,7 @@ public class PluginTests { */ public static class UnitTestNoCheatPlusAPI implements NoCheatPlusAPI { + private final WorldDataManager worldDataManager = new WorldDataManager(); private final DefaultGenericInstanceRegistry genericInstanceRegistry = new DefaultGenericInstanceRegistry(); private final PermissionRegistry permissionRegistry = new PermissionRegistry(10000); @@ -181,6 +184,16 @@ public class PluginTests { return permissionRegistry; } + @Override + public WorldDataManager getWorldDataManager() { + return worldDataManager; + } + + @Override + public IPlayerDataManager getPlayerDataManager() { + throw new UnsupportedOperationException(); + } + } public static void setUnitTestNoCheatPlusAPI(boolean force) { diff --git a/NCPPlugin/src/test/java/fr/neatmonster/nocheatplus/test/TestWorldDataManager.java b/NCPPlugin/src/test/java/fr/neatmonster/nocheatplus/test/TestWorldDataManager.java new file mode 100644 index 00000000..5b3840ed --- /dev/null +++ b/NCPPlugin/src/test/java/fr/neatmonster/nocheatplus/test/TestWorldDataManager.java @@ -0,0 +1,132 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.test; + +import static org.junit.Assert.fail; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.junit.Test; + +import fr.neatmonster.nocheatplus.NCPAPIProvider; +import fr.neatmonster.nocheatplus.PluginTests; +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.compat.AlmostBoolean; +import fr.neatmonster.nocheatplus.components.config.value.OverrideType; +import fr.neatmonster.nocheatplus.config.ConfPaths; +import fr.neatmonster.nocheatplus.config.ConfigFile; +import fr.neatmonster.nocheatplus.config.DefaultConfig; +import fr.neatmonster.nocheatplus.worlds.WorldDataManager; + +public class TestWorldDataManager { + + private WorldDataManager getWorldDataManager() { + PluginTests.setUnitTestNoCheatPlusAPI(false); + return (WorldDataManager) NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager(); + } + + /** + * Set in the config taken from the map - create if not yet existent. + * + * @param map + * @param worldName + * @param key + * @param value + */ + void set(Map map, String worldName, String key, Object value) { + ConfigFile cfg = map.get(worldName); + if (cfg == null) { + cfg = new DefaultConfig(); + map.put(worldName, cfg); + } + cfg.set(key, value); + } + + @Test + public void BasicTests() { + + + WorldDataManager worldMan = getWorldDataManager(); + + final Map rawWorldConfigs = new LinkedHashMap(); + + // (Implicitly create configurations via set). + // Default. + set(rawWorldConfigs, null, ConfPaths.COMBINED + ConfPaths.SUB_ACTIVE, "yes"); + set(rawWorldConfigs, null, ConfPaths.COMBINED_MUNCHHAUSEN_CHECK, "default"); + + // Exist1 + set(rawWorldConfigs, "Exist1", ConfPaths.COMBINED + ConfPaths.SUB_ACTIVE, "no"); + + // Exist2 + set(rawWorldConfigs, "Exist2", ConfPaths.COMBINED_MUNCHHAUSEN_CHECK, false); + + // (Might set some particularly interesting values here.) + + worldMan.applyConfiguration(rawWorldConfigs); + + if (!worldMan.getWorldData("notExist1").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) { + fail("Inherited from default: COMBINED_MUNCHHAUSEN should be active (-> COMBINED is)"); + } + + if (!worldMan.getDefaultWorldData().isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) { + fail("Default: COMBINED_MUNCHHAUSEN should be active (-> COMBINED is)"); + } + + if (worldMan.getWorldData("Exist1").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) { + fail("Specific: COMBINED_MUNCHHAUSEN should not be active (-> COMBINED is not)"); + } + + if (worldMan.getWorldData("Exist2").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) { + fail("Specific: COMBINED_MUNCHHAUSEN should not be active (directly set)"); + } + + // Override via config "reload": + set(rawWorldConfigs, "Exist2", ConfPaths.COMBINED_MUNCHHAUSEN_CHECK, true); + worldMan.applyConfiguration(rawWorldConfigs); + if (!worldMan.getWorldData("Exist2").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) { + fail("Specific: COMBINED_MUNCHHAUSEN should be active (directly set)"); + } + + // Specific override (mild / reset with reload). + worldMan.overrideCheckActivation(CheckType.COMBINED, AlmostBoolean.NO, + OverrideType.SPECIFIC, true); + if (worldMan.getWorldData("notExist2").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) { + fail("Overridden (inherited from default): COMBINED_MUNCHHAUSEN should not be active (-> COMBINED is)"); + } + worldMan.applyConfiguration(rawWorldConfigs); + if (!worldMan.getWorldData("notExist2").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) { + fail("Inherited from default: COMBINED_MUNCHHAUSEN should be active (-> COMBINED is)"); + } + + worldMan.getWorldData("NotExist3").overrideCheckActivation(CheckType.COMBINED_MUNCHHAUSEN, + AlmostBoolean.NO, OverrideType.SPECIFIC, false); + if (worldMan.getWorldData("notExist3").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) { + fail("Overridden (SPECIFIC): COMBINED_MUNCHHAUSEN should not be active (-directly set)"); + } + worldMan.applyConfiguration(rawWorldConfigs); + if (worldMan.getWorldData("notExist3").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) { + fail("Overridden (SPECIFIC): COMBINED_MUNCHHAUSEN should not be active after reload (directly set)"); + } + + // TODO: "Reload with special cases" + // TODO: overriding + + + + } + +} diff --git a/NoCheatPlus/pom.xml b/NoCheatPlus/pom.xml index be20835e..955af86b 100644 --- a/NoCheatPlus/pom.xml +++ b/NoCheatPlus/pom.xml @@ -8,7 +8,7 @@ NoCheatPlus 3.16.1-SNAPSHOT Detect and fight the exploitation of various flaws/bugs in Minecraft. - https://dev.bukkit.org/server-mods/nocheatplus + https://dev.bukkit.org/projects/nocheatplus jar diff --git a/README.md b/README.md index 5b90c6f7..9bc6eee0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ NoCheatPlus --------- -NoCheatPlus is a fork of the famous anti-cheat plugin [NoCheat](https://dev.bukkit.org/server-mods/nocheat/) created by [Evenprime](https://github.com/Evenprime). NoCheatPlus attempts to enforce "vanilla Minecraft" mechanics, as well as preventing players from abusing weaknesses in Minecraft or its protocol, making your server more safe. Organized in different sections, various checks are performed to test players doing, covering a wide range including flying and speeding, fighting hacks, fast block breaking and nukers, inventory hacks, chat spam and other types of malicious behaviour. For a more complete list have a look at the always outdated [Features Page](https://github.com/NoCheatPlus/Docs/wiki/Features). +NoCheatPlus is a fork of the famous anti-cheat plugin [NoCheat](https://dev.bukkit.org/projects/nocheat/) created by [Evenprime](https://github.com/Evenprime). NoCheatPlus attempts to enforce "vanilla Minecraft" mechanics, as well as preventing players from abusing weaknesses in Minecraft or its protocol, making your server more safe. Organized in different sections, various checks are performed to test players doing, covering a wide range including flying and speeding, fighting hacks, fast block breaking and nukers, inventory hacks, chat spam and other types of malicious behaviour. For a more complete list have a look at the always outdated [Features Page](https://github.com/NoCheatPlus/Docs/wiki/Features). Installation --------- @@ -14,17 +14,17 @@ Hints * Be sure that your Spigot/CraftBukkit and NoCheatPlus versions match together. The latest version of NCP is compatible with a wide range of CraftBukkit/Spigot versions ([See the notable builds page for a quick overview.]()). * Don't use tabs in the config.yml file. * Use [ProtocolLib](https://dev.bukkit.org/bukkit-plugins/protocollib) for full efficiency of the fight checks and other. Using a version of ProtocolLib that is supported by NCP is essential, as otherwise some checks will be disabled. -* For compatibility with other plugins such as mcMMO, citizens and more check out [CompatNoCheatPlus](https://dev.bukkit.org/server-mods/compatnocheatplus-cncp/). +* For compatibility with other plugins such as mcMMO, citizens and more check out [CompatNoCheatPlus](https://dev.bukkit.org/projects/compatnocheatplus-cncp/). Links --------- ###### Project * [NoCheatPlus at SpigotMC](https://www.spigotmc.org/resources/nocheatplus2015-07-25.26/) -* [NoCheatPlus at BukkitDev](https://dev.bukkit.org/server-mods/nocheatplus/) +* [NoCheatPlus at BukkitDev](https://dev.bukkit.org/projects/nocheatplus/) ###### Download -* [BukkitDev (approved by staff)](https://dev.bukkit.org/server-mods/nocheatplus/files/) +* [BukkitDev (approved by staff)](https://dev.bukkit.org/projects/nocheatplus/files/) * [SpigotMC (not inspected by staff)](https://www.spigotmc.org/resources/nocheatplus2015-07-25.26/updates) * [Jenkins (all builds including development versions)](https://ci.md-5.net/job/NoCheatPlus/) @@ -42,7 +42,7 @@ Links ###### Related Plugins * [ProtocolLib at BukkitDev](https://dev.bukkit.org/bukkit-plugins/protocollib) -* [CompatNoCheatPlus at BukkitDev](https://dev.bukkit.org/projects/compatnocheatplus-cncp) +* [CompatNoCheatPlus at BukkitDev](https://dev.bukkit.org/projects/compatnocheatplus-cncp/) ###### Obtain a build of Spigot * [Get the latest BuildTools.jar](https://hub.spigotmc.org/jenkins/job/BuildTools/) diff --git a/pom.xml b/pom.xml index d9d9a83d..b72ee1ba 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ pom 1.1-SNAPSHOT NoCheatPlus Parent - https://dev.bukkit.org/server-mods/nocheatplus + https://dev.bukkit.org/projects/nocheatplus UTF-8 yyyy_MM_dd-HH_mm