[BREAKING] Enable more precise sub check data removal (see details).

[BREAKING]
* Due to adding a method to CheckDataFactory.
* Might alter data removal (less is removed, might've overlooked
something).

For MOVING, FIGHT, COMBINED, data removal for sub checks now is
possible, allowing for more precise resetting via commands. Other check
groups may follow on request / randomly.

Data removal for check data is logged now (only CheckData, not
IRemoveData in general), in case the debug flag is set in the data.

Later, a more flexible method may get implemented, accepting a String
id, so not only check type related data, but also any type of special
data can be removed (e.g. moving.locationtrace would not be a check
type, but allow resetting the location trace of a player).
This commit is contained in:
asofold 2017-04-14 14:30:34 +02:00
parent f5d2cbc880
commit 23f9ac5689
12 changed files with 303 additions and 12 deletions

View File

@ -14,27 +14,41 @@
*/
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.
* 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.
* 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(final Player player);
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(final String playerName);
public ICheckData removeData(String playerName);
}

View File

@ -0,0 +1,26 @@
package fr.neatmonster.nocheatplus.checks.access;
import fr.neatmonster.nocheatplus.checks.CheckType;
/**
* Extension for CheckData, enabling disable spell checking removal of sub check
* data.
*
* @author asofold
*
*/
public interface IRemoveSubCheckData {
/**
* Remove the sub check data of the given CheckType.
*
* @param checkType
* @return True, if the sub check type has been contained <i>and the
* implementation is capable of removing it in general.</i> False,
* if the implementation is not capable of removing that type of
* data, or if the check type doesn't qualify for a sub check at
* all. If false is returned, the entire check group data (or super
* check data) might get removed, in order to ensure data removal.
*/
public boolean removeSubCheckData(CheckType checkType);
}

View File

@ -16,6 +16,7 @@ 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;
@ -41,6 +42,11 @@ public class BlockBreakData extends ACheckData {
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);

View File

@ -16,6 +16,7 @@ package fr.neatmonster.nocheatplus.checks.blockinteract;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Material;
import org.bukkit.block.Block;
@ -39,6 +40,11 @@ public class BlockInteractData extends ACheckData {
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);

View File

@ -16,6 +16,7 @@ package fr.neatmonster.nocheatplus.checks.blockplace;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.entity.Player;
@ -36,6 +37,11 @@ public class BlockPlaceData extends ACheckData {
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);

View File

@ -16,6 +16,7 @@ package fr.neatmonster.nocheatplus.checks.chat;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.entity.Player;
@ -36,6 +37,11 @@ public class ChatData extends AsyncCheckData {
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);

View File

@ -16,16 +16,19 @@ 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 {
public class CombinedData extends ACheckData implements IRemoveSubCheckData {
/** The factory creating data. */
public static final CheckDataFactory factory = new CheckDataFactory() {
@ -34,6 +37,11 @@ public class CombinedData extends ACheckData {
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);
@ -99,4 +107,28 @@ public class CombinedData extends ACheckData {
super(config);
}
@Override
public boolean removeSubCheckData(final CheckType checkType) {
switch(checkType) {
// TODO: case COMBINED:
case COMBINED_IMPROBABLE:
improbableVL = 0;
improbableCount.clear(System.currentTimeMillis()); // TODO: Document there, which to use.
return true;
case COMBINED_YAWRATE:
yawFreq.clear(System.currentTimeMillis()); // TODO: Document there, which to use.
return true;
case COMBINED_BEDLEAVE:
bedLeaveVL = 0;
wasInBed = false; // wasInBed is probably better kept?
return true;
case COMBINED_MUNCHHAUSEN:
munchHausenVL = 0;
return true;
default:
return false;
}
}
}

View File

@ -18,6 +18,7 @@ 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;
@ -25,6 +26,7 @@ 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.hooks.APIUtils;
import fr.neatmonster.nocheatplus.utilities.PenaltyTime;
@ -33,7 +35,7 @@ import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency;
/**
* Player specific data for the fight checks.
*/
public class FightData extends ACheckData {
public class FightData extends ACheckData implements IRemoveSubCheckData {
public static class FightDataFactory implements CheckDataFactory {
@ -46,6 +48,11 @@ public class FightData extends ACheckData {
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);
@ -55,6 +62,7 @@ public class FightData extends ACheckData {
public void removeAllData() {
clear();
}
}
@ -69,6 +77,11 @@ public class FightData extends ACheckData {
return playersMap.get(playerName);
}
@Override
public ICheckData getDataIfPresent(UUID playerId, String playerName) {
return playersMap.get(playerName);
}
@Override
protected Collection<String> getPresentData() {
return playersMap.keySet();
@ -192,7 +205,7 @@ public class FightData extends ACheckData {
public boolean noSwingArmSwung;
// Data of the reach check.
public double reachMod = 1;
public double reachMod = 1.0;
// Data of the SelfHit check.
public ActionFrequency selfHitVL = new ActionFrequency(6, 5000);
@ -217,6 +230,57 @@ public class FightData extends ACheckData {
fastHealBuffer = config.fastHealBuffer;
}
@Override
public boolean removeSubCheckData(final CheckType checkType) {
switch(checkType) {
// TODO: case FIGHT: ...
case FIGHT_DIRECTION:
directionVL = 0;
return true;
case FIGHT_REACH:
reachVL = 0;
reachMod = 1.0;
return true;
case FIGHT_ANGLE:
angleVL = 0;
angleHits.clear();
return true;
case FIGHT_SPEED:
speedVL = 0;
speedBuckets.clear(System.currentTimeMillis());
speedShortTermCount = 0;
speedShortTermTick = 0;
return true;
case FIGHT_FASTHEAL:
fastHealVL = 0;
fastHealRefTime = 0;
fastHealBuffer = 0;
regainHealthTime = 0;
return true;
case FIGHT_GODMODE:
godModeVL = 0;
godModeBuffer = 0;
godModeAcc = 0;
godModeLastTime = 0;
godModeLastAge = 0;
lastNoDamageTicks = 0; // Not sure here, possibly a shared thing.
// godModeHealth / ...
return true;
case FIGHT_CRITICAL:
criticalVL = 0;
return true;
case FIGHT_NOSWING:
noSwingVL = 0;
// Not reset time, for leniency rather.
return true;
case FIGHT_SELFHIT:
selfHitVL.clear(System.currentTimeMillis());
return true;
default:
return false;
}
}
public void onWorldChange() {
angleHits.clear();
lastAttackedX = Double.MAX_VALUE;

View File

@ -16,6 +16,7 @@ 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;
@ -37,6 +38,11 @@ public class InventoryData extends ACheckData {
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);

View File

@ -16,6 +16,7 @@ package fr.neatmonster.nocheatplus.checks.moving;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import org.bukkit.Location;
@ -28,6 +29,7 @@ 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;
import fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace.TraceEntryPool;
@ -60,7 +62,7 @@ import fr.neatmonster.nocheatplus.workaround.IWorkaroundRegistry.WorkaroundSet;
/**
* Player specific data for the moving checks.
*/
public class MovingData extends ACheckData {
public class MovingData extends ACheckData implements IRemoveSubCheckData {
public static final class MovingDataFactory implements CheckDataFactory, ICanHandleTimeRunningBackwards {
@Override
@ -68,6 +70,11 @@ public class MovingData extends ACheckData {
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);
@ -369,6 +376,59 @@ public class MovingData extends ACheckData {
}
@Override
public boolean removeSubCheckData(final CheckType checkType) {
// TODO: LocationTrace stays (leniency for other players!).
// TODO: Likely more fields left to change.
switch (checkType) {
/*
* TODO: case MOVING: // Remove all in-place (future: data might
* stay as long as the player is online).
*/
case MOVING_SURVIVALFLY:
survivalFlyVL = 0;
clearFlyData();
resetSetBack(); // TODO: Not sure this is really best for compatibility.
// TODO: other?
return true;
case MOVING_CREATIVEFLY:
creativeFlyVL = 0;
clearFlyData();
resetSetBack(); // TODO: Not sure this is really best for compatibility.
// TODO: other?
return true;
case MOVING_NOFALL:
noFallVL = 0;
clearNoFallData();
return true;
case MOVING_MOREPACKETS:
morePacketsVL = 0;
clearPlayerMorePacketsData();
morePacketsSetback = null;
morePacketsSetBackResetTime = 0;
return true;
case MOVING_PASSABLE:
passableVL = 0;
return true;
case MOVING_VEHICLE:
vehicleEnvelopeVL = 0;
vehicleMorePacketsVL = 0;
clearVehicleData();
return true;
case MOVING_VEHICLE_ENVELOPE:
vehicleEnvelopeVL = 0;
vehicleMoves.invalidate();
vehicleSetBacks.invalidateAll(); // Also invalidates morepackets set back.
return true;
case MOVING_VEHICLE_MOREPACKETS:
vehicleMorePacketsVL = 0;
clearVehicleMorePacketsData();
return true;
default:
return false;
}
}
/**
* Clear fly and more packets check data for both vehicles and players.
*/

View File

@ -15,12 +15,14 @@
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;
@ -50,6 +52,11 @@ public class NetDataFactory implements CheckDataFactory, ICanHandleTimeRunningBa
}
}
@Override
public ICheckData getDataIfPresent(UUID playerId, String playerName) {
return dataMap.get(playerName);
}
@Override
public NetData removeData(String playerName) {
return dataMap.remove(playerName);

View File

@ -36,12 +36,14 @@ 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;
@ -61,6 +63,7 @@ import fr.neatmonster.nocheatplus.config.ConfigFile;
import fr.neatmonster.nocheatplus.config.ConfigManager;
import fr.neatmonster.nocheatplus.hooks.APIUtils;
import fr.neatmonster.nocheatplus.logging.StaticLog;
import fr.neatmonster.nocheatplus.logging.Streams;
import fr.neatmonster.nocheatplus.utilities.IdUtil;
import fr.neatmonster.nocheatplus.utilities.StringUtil;
import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW;
@ -317,6 +320,7 @@ public class DataManager implements Listener, INeedConfig, ComponentRegistry<IRe
}
}
for (final CheckDataFactory factory : factories) {
// TODO: Support precise removal ?
factory.removeAllData();
}
for (final IRemoveData rmd : instance.iRemoveData) {
@ -420,6 +424,12 @@ public class DataManager implements Listener, INeedConfig, ComponentRegistry<IRe
* @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;
}
@ -439,8 +449,8 @@ public class DataManager implements Listener, INeedConfig, ComponentRegistry<IRe
}
}
// Remove data.
for (final CheckDataFactory otherFactory : factories) {
if (otherFactory.removeData(playerName) != null) {
for (final CheckDataFactory factory : factories) {
if (removeDataPrecisely(playerId, playerName, checkType, factory)) {
had = true;
}
}
@ -448,7 +458,6 @@ public class DataManager implements Listener, INeedConfig, ComponentRegistry<IRe
if (checkType == CheckType.ALL) {
// TODO: Don't remove PlayerData for online players.
// TODO: Fetch/use UUID early, and check validity of name.
final UUID playerId = getUUID(playerName);
if (playerId != null) {
instance.playerData.remove(playerId);
}
@ -457,6 +466,55 @@ public class DataManager implements Listener, INeedConfig, ComponentRegistry<IRe
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 = "[" + checkType + "] [" + playerName + "] Data removal: " ;
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;
}
}
/**
* Clear player related data, only for registered components (not execution
* history, violation history, normal check data).<br>