[Blind] Prepare removal of sub-check data (so far: fight.selfhit).

This will probably not be pulled through for all checks, because
the overall design does not support to do this in an efficient way.

Some checks will be added to allow pinpointing data removal,
mainly to allow  compatibility tweaks, e.g. with actions.
This commit is contained in:
asofold 2014-01-26 13:14:46 +01:00
parent 0bab69e1ac
commit 9810abff81
4 changed files with 155 additions and 7 deletions

View File

@ -87,7 +87,7 @@ public enum CheckType {
FIGHT_KNOCKBACK(FIGHT, Permissions.FIGHT_KNOCKBACK),
FIGHT_NOSWING(FIGHT, Permissions.FIGHT_NOSWING),
FIGHT_REACH(FIGHT, Permissions.FIGHT_REACH),
FIGHT_SELFHIT(FIGHT, Permissions.FIGHT_SELFHIT),
FIGHT_SELFHIT(FIGHT, Permissions.FIGHT_SELFHIT, FightConfig.factory, FightData.selfHitDataFactory),
FIGHT_SPEED(FIGHT, Permissions.FIGHT_SPEED),
INVENTORY(InventoryConfig.factory, InventoryData.factory, Permissions.INVENTORY),
@ -156,7 +156,7 @@ public enum CheckType {
}
/**
* Root constructor.
* General constructor (usually used for root check groups).
* @param parent Super check type (usually the group).
* @param permission Bypass permission.
* @param configFactory Check config factory.

View File

@ -0,0 +1,91 @@
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<D extends ICheckData> 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.<br>
* This method might change "a lot" with time.
* @return
*/
protected abstract Collection<String> 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.<br>
* 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);
}

View File

@ -1,5 +1,6 @@
package fr.neatmonster.nocheatplus.checks.fight;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
@ -7,9 +8,12 @@ import java.util.TreeMap;
import org.bukkit.Location;
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.SubCheckDataFactory;
import fr.neatmonster.nocheatplus.hooks.APIUtils;
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
/*
@ -26,9 +30,13 @@ import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
* Player specific data for the fight checks.
*/
public class FightData extends ACheckData {
/** The factory creating data. */
public static final CheckDataFactory factory = new CheckDataFactory() {
public static class FightDataFactory implements CheckDataFactory {
protected FightDataFactory() {
// Discourage creation here.
};
@Override
public final ICheckData getData(final Player player) {
return FightData.getData(player);
@ -43,10 +51,59 @@ public class FightData extends ACheckData {
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<FightData>(CheckType.FIGHT, factory) {
@Override
protected FightData getData(String playerName) {
return playersMap.get(playerName);
}
@Override
protected Collection<String> 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 && !APIUtils.isParent(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. */
private static final Map<String, FightData> playersMap = new HashMap<String, FightData>();
protected static final Map<String, FightData> playersMap = new HashMap<String, FightData>(); // Not sure about visibility (selfhit).
/**
* Gets the data of a specified player.

View File

@ -12,7 +12,7 @@ public interface IRemoveData {
/**
* Remove the data of one player.
* @param playerName
* @return IData instance, if it was present.
* @return IData instance if something was changed. Note that this should also return an existing data instance, if it is only partially cleared and not actually removed.
*/
public IData removeData(String playerName);