[BLEEDING][BREAKING][BROKEN] Continue data registry + API. (+)
Likely incomplete/broken somewhere. Implement/extend/use/fix new data caches and factories. (+) Fixes related to recent commits (e.g. log listener exceptions properly, fight.wrongturn). Missing: * Debug logging (registry), consider a registry log file. * Proper naming/tags for listeners. * Consistency: ICheckData should probably be used with removeData(CheckType)? Registration is arbitrary though. * Consistency: clearData() vs clearData(CheckType.ALL) - should check type related data be ICheckData only ? * Data expiration stages and PlayerOfflineData - impact on memory... * (...) Further: * WorldData inheritance issue: implement passing on changes to children. (Current line of thought: rather extend IWorldDataManager to allow change default+inherited only.) * Shrink exposed API - uncertain: rather have a registration context object or expose individual methods for factory registration and grouping types? * (...) * Planned breakage: Project + package organization redone: move stuff where it is best for having an API (components -> split to top level or name it api, utilities ... parts belong into API, and the like..., possibly split project further: commons, api(+-bukkit), core/checks, plugin-bukkit).
This commit is contained in:
parent
350908cb47
commit
82d6f94230
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.utilities;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Misc {
|
||||
|
@ -36,4 +37,11 @@ public class Misc {
|
|||
return res;
|
||||
}
|
||||
|
||||
public static <T> void putFirst(T item, List<T> list) {
|
||||
if (list.contains(item)) {
|
||||
list.remove(item);
|
||||
}
|
||||
list.add(0, item);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -705,6 +705,8 @@ public class HashMapLOW <K, V> {
|
|||
* Get an iterator reflecting this 'stage of resetting'. During iteration,
|
||||
* entries may get removed or added, values changed. Concurrent modification
|
||||
* will not let the iteration fail.
|
||||
* <hr>
|
||||
* This operation does not use locking.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.utilities.ds.map;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/**
|
||||
* Mapping Class<T> to <? extends T> for arbitrary T, aiming at simple generic
|
||||
* caches.
|
||||
* <hr/>
|
||||
* Until as specialized implementation is present, see {@link HashMapLOW} for
|
||||
* reference.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public class InstanceMapLOW {
|
||||
|
||||
/*
|
||||
* TODO: Optimized implementation possible (performance/JIT)? Buckets and
|
||||
* entries could support the type relation.
|
||||
*/
|
||||
private final HashMapLOW<Class<?>, Object> map;
|
||||
|
||||
public InstanceMapLOW(final Lock lock, int initialSize) {
|
||||
map = new HashMapLOW<Class<?>, Object>(lock, 12);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, I extends T> T put(final Class<T> key, final I value) {
|
||||
return (T) map.put(key, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, I extends T> T putIfAbsent(final Class<T> key, final I value) {
|
||||
return (T) map.putIfAbsent(key, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(Class<T> key) {
|
||||
return (T) map.get(key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getLocked(Class<T> key) {
|
||||
return (T) map.getLocked(key);
|
||||
}
|
||||
|
||||
public boolean containsKey(final Class<?> key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
public boolean containsKeyLocked(final Class<?> key) {
|
||||
return map.containsKeyLocked(key);
|
||||
}
|
||||
|
||||
public Collection<Class<?>> getKeys() {
|
||||
return map.getKeys();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T remove(final Class<T> key) {
|
||||
return (T) map.remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* (Note that all contained keys should be different classes.)
|
||||
*
|
||||
* @param keys
|
||||
*/
|
||||
public void remove(final Collection<Class<?>> keys) {
|
||||
map.remove(keys);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
}
|
|
@ -65,7 +65,8 @@ public class FastConsume extends Check implements Listener, INotifyReload {
|
|||
// TODO: Do this kind of thing via registries later on.
|
||||
//ConfigManager.setForAllConfigs(ConfPaths.INVENTORY_INSTANTEAT_CHECK, false);
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().overrideCheckActivation(
|
||||
this.type, AlmostBoolean.NO, OverrideType.PERMANENT, true);
|
||||
CheckType.INVENTORY_INSTANTEAT, AlmostBoolean.NO,
|
||||
OverrideType.PERMANENT, true);
|
||||
StaticLog.logInfo("Inventory checks: FastConsume is available, disabled InstantEat.");
|
||||
}
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ public enum CheckType {
|
|||
}
|
||||
|
||||
private String guessConfigPathRoot() {
|
||||
return name().toLowerCase().replace('_', '.') + ".";
|
||||
return "checks." + name().toLowerCase().replace('_', '.') + ".";
|
||||
}
|
||||
|
||||
public CheckTypeType getType() {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.access;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.config.ICheckConfig;
|
||||
import fr.neatmonster.nocheatplus.worlds.IWorldData;
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.access;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
|
||||
/**
|
||||
* Abstract implementation to do nothing.
|
||||
*
|
||||
|
|
|
@ -24,6 +24,8 @@ import fr.neatmonster.nocheatplus.actions.ParameterHolder;
|
|||
*/
|
||||
public interface IViolationInfo extends ParameterHolder {
|
||||
|
||||
// TODO: Move to components or to the appropriate API location (next iteration(s)).
|
||||
|
||||
/**
|
||||
* Get the violation level just added by this violation.
|
||||
*
|
||||
|
|
|
@ -19,6 +19,8 @@ import org.bukkit.block.Block;
|
|||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.access.ACheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnReload;
|
||||
import fr.neatmonster.nocheatplus.components.registry.IGetGenericInstance;
|
||||
import fr.neatmonster.nocheatplus.stats.Timings;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
||||
|
@ -26,7 +28,7 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
|||
/**
|
||||
* Player specific data for the block break checks.
|
||||
*/
|
||||
public class BlockBreakData extends ACheckData {
|
||||
public class BlockBreakData extends ACheckData implements IDataOnReload {
|
||||
|
||||
// Violation levels.
|
||||
public double directionVL;
|
||||
|
@ -118,4 +120,10 @@ public class BlockBreakData extends ACheckData {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dataOnReload(IGetGenericInstance dataAccess) {
|
||||
// Remove on reload for now.
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,13 +41,19 @@ import fr.neatmonster.nocheatplus.checks.net.FlyingQueueHandle;
|
|||
import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying;
|
||||
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
|
||||
import fr.neatmonster.nocheatplus.compat.Bridge1_9;
|
||||
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
|
||||
import fr.neatmonster.nocheatplus.permissions.Permissions;
|
||||
import fr.neatmonster.nocheatplus.players.DataManager;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Central location to listen to events that are relevant for the block break checks.
|
||||
|
@ -82,8 +88,36 @@ public class BlockBreakListener extends CheckListener {
|
|||
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
|
||||
private final Location useLoc = new Location(null, 0, 0, 0);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BlockBreakListener(){
|
||||
super(CheckType.BLOCKBREAK);
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
// Register config and data.
|
||||
api.register(api.newRegistrationContext()
|
||||
// BlockBreakConfig
|
||||
.registerConfigWorld(BlockBreakConfig.class)
|
||||
.factory(new IFactoryOne<WorldFactoryArgument, BlockBreakConfig>() {
|
||||
@Override
|
||||
public BlockBreakConfig getNewInstance(WorldFactoryArgument arg) {
|
||||
return new BlockBreakConfig(arg.worldData);
|
||||
}
|
||||
})
|
||||
.registerConfigTypesPlayer(CheckType.BLOCKBREAK, true)
|
||||
.context() //
|
||||
// BlockBreakData
|
||||
.registerDataPlayer(BlockBreakData.class)
|
||||
.factory(new IFactoryOne<PlayerFactoryArgument, BlockBreakData>() {
|
||||
@Override
|
||||
public BlockBreakData getNewInstance(
|
||||
PlayerFactoryArgument arg) {
|
||||
return new BlockBreakData(
|
||||
arg.playerData.getGenericInstance(BlockBreakConfig.class));
|
||||
}
|
||||
})
|
||||
// (Complete data removal for now.)
|
||||
.addToGroups(CheckType.BLOCKBREAK, true, IData.class, ICheckData.class)
|
||||
.context() //
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,14 +37,20 @@ 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.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.players.DataManager;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
|
||||
import fr.neatmonster.nocheatplus.utilities.InventoryUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Central location to listen to events that are relevant for the block interact checks.
|
||||
|
@ -99,8 +105,33 @@ public class BlockInteractListener extends CheckListener {
|
|||
private final int idInteractLookFlyingFirst = counters.registerKey("block.interact.look.flying.first");
|
||||
private final int idInteractLookFlyingOther = counters.registerKey("block.interact.look.flying.other");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BlockInteractListener() {
|
||||
super(CheckType.BLOCKINTERACT);
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
api.register(api.newRegistrationContext() //
|
||||
// BlockInteractConfig
|
||||
.registerConfigWorld(BlockInteractConfig.class)
|
||||
.factory(new IFactoryOne<WorldFactoryArgument, BlockInteractConfig>() {
|
||||
@Override
|
||||
public BlockInteractConfig getNewInstance(WorldFactoryArgument arg) {
|
||||
return new BlockInteractConfig(arg.worldData);
|
||||
}
|
||||
})
|
||||
.registerConfigTypesPlayer(CheckType.BLOCKINTERACT, true)
|
||||
.context() //
|
||||
// BlockinteractData
|
||||
.registerDataPlayer(BlockInteractData.class)
|
||||
.factory(new IFactoryOne<PlayerFactoryArgument, BlockInteractData>() {
|
||||
@Override
|
||||
public BlockInteractData getNewInstance(
|
||||
PlayerFactoryArgument arg) {
|
||||
return new BlockInteractData();
|
||||
}
|
||||
})
|
||||
.addToGroups(CheckType.BLOCKINTERACT, true, IData.class, ICheckData.class)
|
||||
.context() //
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,14 +47,20 @@ import fr.neatmonster.nocheatplus.checks.net.FlyingQueueHandle;
|
|||
import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying;
|
||||
import fr.neatmonster.nocheatplus.compat.Bridge1_9;
|
||||
import fr.neatmonster.nocheatplus.compat.BridgeMisc;
|
||||
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.permissions.Permissions;
|
||||
import fr.neatmonster.nocheatplus.players.DataManager;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
import fr.neatmonster.nocheatplus.utilities.InventoryUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Central location to listen to events that are relevant for the block place checks.
|
||||
|
@ -115,8 +121,33 @@ public class BlockPlaceListener extends CheckListener {
|
|||
private final Class<?> blockMultiPlaceEvent = ReflectionUtil.getClass("org.bukkit.event.block.BlockMultiPlaceEvent");
|
||||
private final boolean hasGetReplacedState = ReflectionUtil.getMethodNoArgs(BlockPlaceEvent.class, "getReplacedState", BlockState.class) != null;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BlockPlaceListener() {
|
||||
super(CheckType.BLOCKPLACE);
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
api.register(api.newRegistrationContext()
|
||||
// BlockPlaceConfig
|
||||
.registerConfigWorld(BlockPlaceConfig.class)
|
||||
.factory(new IFactoryOne<WorldFactoryArgument, BlockPlaceConfig>() {
|
||||
@Override
|
||||
public BlockPlaceConfig getNewInstance(WorldFactoryArgument arg) {
|
||||
return new BlockPlaceConfig(arg.worldData);
|
||||
}
|
||||
})
|
||||
.registerConfigTypesPlayer()
|
||||
.context() //
|
||||
// BlockPlaceData
|
||||
.registerDataPlayer(BlockPlaceData.class)
|
||||
.factory(new IFactoryOne<PlayerFactoryArgument, BlockPlaceData>() {
|
||||
@Override
|
||||
public BlockPlaceData getNewInstance(
|
||||
PlayerFactoryArgument arg) {
|
||||
return new BlockPlaceData();
|
||||
}
|
||||
})
|
||||
.addToGroups(CheckType.BLOCKPLACE, true, IData.class, ICheckData.class)
|
||||
.context() //
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,6 +34,10 @@ import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
|
|||
import fr.neatmonster.nocheatplus.checks.moving.util.MovingUtil;
|
||||
import fr.neatmonster.nocheatplus.command.CommandUtil;
|
||||
import fr.neatmonster.nocheatplus.compat.BridgeMisc;
|
||||
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.INotifyReload;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.JoinLeaveListener;
|
||||
import fr.neatmonster.nocheatplus.config.ConfPaths;
|
||||
|
@ -42,8 +46,10 @@ import fr.neatmonster.nocheatplus.config.ConfigManager;
|
|||
import fr.neatmonster.nocheatplus.logging.Streams;
|
||||
import fr.neatmonster.nocheatplus.players.DataManager;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
import fr.neatmonster.nocheatplus.utilities.StringUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.SimpleCharPrefixTree;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Central location to listen to events that are relevant for the chat checks.
|
||||
|
@ -86,11 +92,33 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe
|
|||
/** Set world to null after use, primary thread only. */
|
||||
private final Location useLoc = new Location(null, 0, 0, 0);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChatListener() {
|
||||
super(CheckType.CHAT);
|
||||
ConfigFile config = ConfigManager.getConfigFile();
|
||||
initFilters(config);
|
||||
// (text inits in constructor.)
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
api.register(api.newRegistrationContext()
|
||||
.registerConfigWorld(ChatConfig.class)
|
||||
.factory(new IFactoryOne<WorldFactoryArgument, ChatConfig>() {
|
||||
@Override
|
||||
public ChatConfig getNewInstance(WorldFactoryArgument arg) {
|
||||
return new ChatConfig(arg.worldData);
|
||||
}
|
||||
})
|
||||
.registerConfigTypesPlayer()
|
||||
.context() //
|
||||
.registerDataPlayer(ChatData.class)
|
||||
.factory(new IFactoryOne<PlayerFactoryArgument, ChatData>() {
|
||||
@Override
|
||||
public ChatData getNewInstance(PlayerFactoryArgument arg) {
|
||||
return new ChatData();
|
||||
}
|
||||
})
|
||||
.addToGroups(CheckType.CHAT, true, IData.class, ICheckData.class)
|
||||
.context() //
|
||||
);
|
||||
}
|
||||
|
||||
private void initFilters(ConfigFile config) {
|
||||
|
|
|
@ -14,13 +14,15 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.combined;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.access.ACheckData;
|
||||
import fr.neatmonster.nocheatplus.checks.access.IRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.utilities.PenaltyTime;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency;
|
||||
|
||||
public class CombinedData extends ACheckData implements IRemoveSubCheckData {
|
||||
public class CombinedData extends ACheckData implements IDataOnRemoveSubCheckData {
|
||||
|
||||
// VLs
|
||||
public double bedLeaveVL = 0;
|
||||
|
@ -54,27 +56,32 @@ public class CombinedData extends ACheckData implements IRemoveSubCheckData {
|
|||
public long lastMoveTime;
|
||||
|
||||
@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;
|
||||
public boolean dataOnRemoveSubCheckData(Collection<CheckType> checkTypes) {
|
||||
for (final CheckType checkType : checkTypes)
|
||||
{
|
||||
switch(checkType) {
|
||||
// TODO: case COMBINED:
|
||||
case COMBINED_IMPROBABLE:
|
||||
improbableVL = 0;
|
||||
improbableCount.clear(System.currentTimeMillis()); // TODO: Document there, which to use.
|
||||
break;
|
||||
case COMBINED_YAWRATE:
|
||||
yawFreq.clear(System.currentTimeMillis()); // TODO: Document there, which to use.
|
||||
break;
|
||||
case COMBINED_BEDLEAVE:
|
||||
bedLeaveVL = 0;
|
||||
wasInBed = false; // wasInBed is probably better kept?
|
||||
break;
|
||||
case COMBINED_MUNCHHAUSEN:
|
||||
munchHausenVL = 0;
|
||||
break;
|
||||
case COMBINED:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,10 +28,16 @@ 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.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.players.DataManager;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Class to combine some things, make available for other checks, or just because they don't fit into another section.<br>
|
||||
|
@ -50,8 +56,34 @@ public class CombinedListener extends CheckListener {
|
|||
private final Counters counters = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class);
|
||||
private final int idFakeInvulnerable = counters.registerKey("fakeinvulnerable");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public CombinedListener(){
|
||||
super(CheckType.COMBINED);
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
api.register(api.newRegistrationContext()
|
||||
// CombinedConfig
|
||||
.registerConfigWorld(CombinedConfig.class)
|
||||
.factory(new IFactoryOne<WorldFactoryArgument, CombinedConfig>() {
|
||||
@Override
|
||||
public CombinedConfig getNewInstance(WorldFactoryArgument arg) {
|
||||
return new CombinedConfig(arg.worldData);
|
||||
}
|
||||
})
|
||||
.registerConfigTypesPlayer()
|
||||
.context() //
|
||||
// CombinedData
|
||||
.registerDataPlayer(CombinedData.class)
|
||||
.factory(new IFactoryOne<PlayerFactoryArgument, CombinedData>() {
|
||||
@Override
|
||||
public CombinedData getNewInstance(
|
||||
PlayerFactoryArgument arg) {
|
||||
return new CombinedData();
|
||||
}
|
||||
})
|
||||
.addToGroups(CheckType.MOVING, false, IData.class, ICheckData.class)
|
||||
.removeSubCheckData(CheckType.COMBINED, true)
|
||||
.context() //
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,18 +14,24 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.fight;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.access.ACheckData;
|
||||
import fr.neatmonster.nocheatplus.checks.access.IRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnWorldChange;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.utilities.PenaltyTime;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency;
|
||||
|
||||
/**
|
||||
* Player specific data for the fight checks.
|
||||
*/
|
||||
public class FightData extends ACheckData implements IRemoveSubCheckData {
|
||||
public class FightData extends ACheckData implements IDataOnRemoveSubCheckData, IDataOnWorldChange {
|
||||
|
||||
// Violation levels.
|
||||
public double angleVL;
|
||||
|
@ -115,61 +121,70 @@ public class FightData extends ACheckData implements IRemoveSubCheckData {
|
|||
}
|
||||
|
||||
@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 boolean dataOnRemoveSubCheckData(
|
||||
final Collection<CheckType> checkTypes) {
|
||||
for (final CheckType checkType : checkTypes) {
|
||||
switch(checkType) {
|
||||
// TODO: case FIGHT: ...
|
||||
case FIGHT_DIRECTION:
|
||||
directionVL = 0;
|
||||
break;
|
||||
case FIGHT_REACH:
|
||||
reachVL = 0;
|
||||
reachMod = 1.0;
|
||||
break;
|
||||
case FIGHT_ANGLE:
|
||||
angleVL = 0;
|
||||
angleHits.clear();
|
||||
break;
|
||||
case FIGHT_SPEED:
|
||||
speedVL = 0;
|
||||
speedBuckets.clear(System.currentTimeMillis());
|
||||
speedShortTermCount = 0;
|
||||
speedShortTermTick = 0;
|
||||
break;
|
||||
case FIGHT_FASTHEAL:
|
||||
fastHealVL = 0;
|
||||
fastHealRefTime = 0;
|
||||
fastHealBuffer = 0;
|
||||
regainHealthTime = 0;
|
||||
break;
|
||||
case FIGHT_GODMODE:
|
||||
godModeVL = 0;
|
||||
godModeBuffer = 0;
|
||||
godModeAcc = 0;
|
||||
godModeLastTime = 0;
|
||||
godModeLastAge = 0;
|
||||
lastNoDamageTicks = 0; // Not sure here, possibly a shared thing.
|
||||
// godModeHealth / ...
|
||||
break;
|
||||
case FIGHT_CRITICAL:
|
||||
criticalVL = 0;
|
||||
break;
|
||||
case FIGHT_NOSWING:
|
||||
noSwingVL = 0;
|
||||
// Not reset time, for leniency rather.
|
||||
break;
|
||||
case FIGHT_SELFHIT:
|
||||
selfHitVL.clear(System.currentTimeMillis());
|
||||
break;
|
||||
case FIGHT:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onWorldChange() {
|
||||
@Override
|
||||
public boolean dataOnWorldChange(Player player, IPlayerData pData,
|
||||
World previousWorld, World newWorld) {
|
||||
angleHits.clear();
|
||||
lastAttackedX = Double.MAX_VALUE;
|
||||
lastAttackTick = 0;
|
||||
lastWorld = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import org.bukkit.event.entity.EntityDeathEvent;
|
|||
import org.bukkit.event.entity.EntityRegainHealthEvent;
|
||||
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
|
||||
import org.bukkit.event.player.PlayerAnimationEvent;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
|
@ -55,17 +54,23 @@ import fr.neatmonster.nocheatplus.compat.Bridge1_9;
|
|||
import fr.neatmonster.nocheatplus.compat.BridgeEnchant;
|
||||
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
|
||||
import fr.neatmonster.nocheatplus.compat.IBridgeCrossPlugin;
|
||||
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
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.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.TrigUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Central location to listen to events that are relevant for the fight checks.<br>
|
||||
|
@ -119,8 +124,33 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
|||
// Assume it to stay the same all time.
|
||||
private final IGenericInstanceHandle<IBridgeCrossPlugin> crossPlugin = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstanceHandle(IBridgeCrossPlugin.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public FightListener() {
|
||||
super(CheckType.FIGHT);
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
api.register(api.newRegistrationContext()
|
||||
// FightConfig
|
||||
.registerConfigWorld(FightConfig.class)
|
||||
.factory(new IFactoryOne<WorldFactoryArgument, FightConfig>() {
|
||||
@Override
|
||||
public FightConfig getNewInstance(WorldFactoryArgument arg) {
|
||||
return new FightConfig(arg.worldData);
|
||||
}
|
||||
})
|
||||
.registerConfigTypesPlayer()
|
||||
.context() //
|
||||
// FightData
|
||||
.registerDataPlayer(FightData.class)
|
||||
.factory(new IFactoryOne<PlayerFactoryArgument, FightData>() {
|
||||
@Override
|
||||
public FightData getNewInstance(PlayerFactoryArgument arg) {
|
||||
return new FightData(arg.playerData.getGenericInstance(FightConfig.class));
|
||||
}
|
||||
})
|
||||
.addToGroups(CheckType.FIGHT, false, IData.class, ICheckData.class)
|
||||
.removeSubCheckData(CheckType.FIGHT, true)
|
||||
.context() //
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -281,8 +311,8 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
|||
|
||||
// TODO: Add as real check.
|
||||
// TODO: Add something on packet level already.
|
||||
if (pData.isCheckActive(CheckType.FIGHT_WRONGTURN, damagedPlayer)
|
||||
&& wrongTurn.check(damagedPlayer, loc, data, cc)) {
|
||||
if (pData.isCheckActive(CheckType.FIGHT_WRONGTURN, player)
|
||||
&& wrongTurn.check(player, loc, data, cc)) {
|
||||
cancelled = true;
|
||||
}
|
||||
|
||||
|
@ -830,12 +860,6 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
|||
data.angleHits.clear();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerChangedWorld(final PlayerChangedWorldEvent event) {
|
||||
DataManager.getGenericInstance(event.getPlayer(),
|
||||
FightData.class).onWorldChange();
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = false, priority = EventPriority.MONITOR)
|
||||
public void onItemHeld(final PlayerItemHeldEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
|
|
|
@ -22,10 +22,10 @@ import org.bukkit.util.Vector;
|
|||
import fr.neatmonster.nocheatplus.actions.ActionList;
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
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.net.FlyingQueueHandle;
|
||||
import fr.neatmonster.nocheatplus.checks.net.FlyingQueueLookBlockChecker;
|
||||
import fr.neatmonster.nocheatplus.components.config.ICheckConfig;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.utilities.collision.CollideRayVsAABB;
|
||||
import fr.neatmonster.nocheatplus.utilities.collision.ICollideRayVsAABB;
|
||||
|
|
|
@ -24,7 +24,7 @@ import fr.neatmonster.nocheatplus.checks.access.ACheckConfig;
|
|||
import fr.neatmonster.nocheatplus.config.ConfPaths;
|
||||
import fr.neatmonster.nocheatplus.config.ConfigFile;
|
||||
import fr.neatmonster.nocheatplus.permissions.Permissions;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldData;
|
||||
import fr.neatmonster.nocheatplus.worlds.IWorldData;
|
||||
|
||||
/**
|
||||
* Configurations specific for the "inventory" checks. Every world gets one of
|
||||
|
@ -70,7 +70,7 @@ public class InventoryConfig extends ACheckConfig {
|
|||
* @param data
|
||||
* the data
|
||||
*/
|
||||
public InventoryConfig(final WorldData worldData) {
|
||||
public InventoryConfig(final IWorldData worldData) {
|
||||
super(worldData);
|
||||
final ConfigFile data = worldData.getRawConfiguration();
|
||||
dropLimit = data.getInt(ConfPaths.INVENTORY_DROP_LIMIT);
|
||||
|
|
|
@ -52,13 +52,19 @@ import fr.neatmonster.nocheatplus.checks.combined.Improbable;
|
|||
import fr.neatmonster.nocheatplus.checks.moving.util.MovingUtil;
|
||||
import fr.neatmonster.nocheatplus.compat.Bridge1_9;
|
||||
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
|
||||
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.entity.IEntityAccessVehicle;
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.JoinLeaveListener;
|
||||
import fr.neatmonster.nocheatplus.players.DataManager;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
import fr.neatmonster.nocheatplus.utilities.InventoryUtil;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Central location to listen to events that are relevant for the inventory checks.
|
||||
|
@ -94,8 +100,34 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
|
|||
private final IGenericInstanceHandle<IEntityAccessVehicle> handleVehicles =
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getGenericInstanceHandle(IEntityAccessVehicle.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public InventoryListener() {
|
||||
super(CheckType.INVENTORY);
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
api.register(api.newRegistrationContext()
|
||||
// InventoryConfig
|
||||
.registerConfigWorld(InventoryConfig.class)
|
||||
.factory(new IFactoryOne<WorldFactoryArgument, InventoryConfig>() {
|
||||
@Override
|
||||
public InventoryConfig getNewInstance(
|
||||
WorldFactoryArgument arg) {
|
||||
return new InventoryConfig(arg.worldData);
|
||||
}
|
||||
})
|
||||
.registerConfigTypesPlayer()
|
||||
.context() //
|
||||
// InventoryData
|
||||
.registerDataPlayer(InventoryData.class)
|
||||
.factory(new IFactoryOne<PlayerFactoryArgument, InventoryData>() {
|
||||
@Override
|
||||
public InventoryData getNewInstance(
|
||||
PlayerFactoryArgument arg) {
|
||||
return new InventoryData();
|
||||
}
|
||||
})
|
||||
.addToGroups(CheckType.INVENTORY, true, IData.class, ICheckData.class)
|
||||
.context() //
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,13 +18,13 @@ import java.util.Collection;
|
|||
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.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;
|
||||
|
@ -41,9 +41,13 @@ 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.IDataOnReload;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnWorldUnload;
|
||||
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.components.registry.IGetGenericInstance;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
|
@ -58,33 +62,7 @@ import fr.neatmonster.nocheatplus.workaround.IWorkaroundRegistry.WorkaroundSet;
|
|||
/**
|
||||
* Player specific data for the moving checks.
|
||||
*/
|
||||
public class MovingData extends ACheckData implements IRemoveSubCheckData {
|
||||
|
||||
/*
|
||||
* TODO: Handle world unload and other by registration (PlayerDataManager) -
|
||||
* might just implement the interfaces and auto-handle at registration.
|
||||
*/
|
||||
|
||||
// /**
|
||||
// * 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);
|
||||
// }
|
||||
// }
|
||||
public class MovingData extends ACheckData implements IDataOnRemoveSubCheckData, IDataOnReload, IDataOnWorldUnload {
|
||||
|
||||
// Check specific.
|
||||
|
||||
|
@ -324,59 +302,6 @@ public class MovingData extends ACheckData implements IRemoveSubCheckData {
|
|||
|
||||
}
|
||||
|
||||
@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.
|
||||
*/
|
||||
|
@ -522,26 +447,6 @@ public class MovingData extends ACheckData implements IRemoveSubCheckData {
|
|||
vehicleMoves.invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up data related to worlds with the given name (not case-sensitive).
|
||||
* @param worldName
|
||||
*/
|
||||
public void onWorldUnload(final String worldName) {
|
||||
// TODO: Unlink world references.
|
||||
if (teleported != null && worldName.equalsIgnoreCase(teleported.getWorld().getName())) {
|
||||
resetTeleported();
|
||||
}
|
||||
if (setBack != null && worldName.equalsIgnoreCase(setBack.getWorld().getName())) {
|
||||
clearFlyData();
|
||||
}
|
||||
if (morePacketsSetback != null && worldName.equalsIgnoreCase(morePacketsSetback.getWorld().getName())) {
|
||||
clearPlayerMorePacketsData();
|
||||
clearNoFallData(); // just in case.
|
||||
}
|
||||
// (Assume vehicle data needn't really reset here.)
|
||||
vehicleSetBacks.resetByWorldName(worldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all past player moves data and set last position if not null.
|
||||
*
|
||||
|
@ -1243,13 +1148,6 @@ public class MovingData extends ACheckData implements IRemoveSubCheckData {
|
|||
iead.getWidth(player) / 2.0, Math.max(player.getEyeHeight(), iead.getHeight(player)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust to new parameters.
|
||||
*/
|
||||
protected void adjustOnReload(final MovingConfig cc, final int tick) {
|
||||
trace.adjustSettings(cc.traceMaxAge, cc.traceMaxSize, tick);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if velocity has affected the in-air jumping phase. Keeps set until
|
||||
* reset on-ground or otherwise. Use clearActiveVerVel to force end velocity
|
||||
|
@ -1382,4 +1280,91 @@ public class MovingData extends ACheckData implements IRemoveSubCheckData {
|
|||
verVel.removeLeadingQueuedVerticalVelocityByFlag(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dataOnRemoveSubCheckData(Collection<CheckType> checkTypes) {
|
||||
// TODO: Detect if it is ok to remove data.
|
||||
// TODO: LocationTrace stays (leniency for other players!).
|
||||
// TODO: Likely more fields left to change.
|
||||
for (final CheckType checkType : checkTypes) {
|
||||
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(); // TODO: ...
|
||||
resetSetBack(); // TODO: Not sure this is really best for compatibility.
|
||||
// TODO: other?
|
||||
break;
|
||||
case MOVING_CREATIVEFLY:
|
||||
creativeFlyVL = 0;
|
||||
clearFlyData(); // TODO: ...
|
||||
resetSetBack(); // TODO: Not sure this is really best for compatibility.
|
||||
// TODO: other?
|
||||
break;
|
||||
case MOVING_NOFALL:
|
||||
noFallVL = 0;
|
||||
clearNoFallData();
|
||||
break;
|
||||
case MOVING_MOREPACKETS:
|
||||
morePacketsVL = 0;
|
||||
clearPlayerMorePacketsData();
|
||||
morePacketsSetback = null;
|
||||
morePacketsSetBackResetTime = 0;
|
||||
break;
|
||||
case MOVING_PASSABLE:
|
||||
passableVL = 0;
|
||||
break;
|
||||
case MOVING_VEHICLE:
|
||||
vehicleEnvelopeVL = 0;
|
||||
vehicleMorePacketsVL = 0;
|
||||
clearVehicleData();
|
||||
break;
|
||||
case MOVING_VEHICLE_ENVELOPE:
|
||||
vehicleEnvelopeVL = 0;
|
||||
vehicleMoves.invalidate();
|
||||
vehicleSetBacks.invalidateAll(); // Also invalidates morepackets set back.
|
||||
break;
|
||||
case MOVING_VEHICLE_MOREPACKETS:
|
||||
vehicleMorePacketsVL = 0;
|
||||
clearVehicleMorePacketsData();
|
||||
break;
|
||||
case MOVING:
|
||||
clearMostMovingCheckData(); // Just in case.
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dataOnWorldUnload(final World world,
|
||||
final IGetGenericInstance dataAccess) {
|
||||
// TODO: Unlink world references.
|
||||
final String worldName = world.getName();
|
||||
if (teleported != null && worldName.equalsIgnoreCase(teleported.getWorld().getName())) {
|
||||
resetTeleported();
|
||||
}
|
||||
if (setBack != null && worldName.equalsIgnoreCase(setBack.getWorld().getName())) {
|
||||
clearFlyData();
|
||||
}
|
||||
if (morePacketsSetback != null && worldName.equalsIgnoreCase(morePacketsSetback.getWorld().getName())) {
|
||||
clearPlayerMorePacketsData();
|
||||
clearNoFallData(); // just in case.
|
||||
}
|
||||
// (Assume vehicle data needn't really reset here.)
|
||||
vehicleSetBacks.resetByWorldName(worldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dataOnReload(final IGetGenericInstance dataAccess) {
|
||||
final MovingConfig cc = dataAccess.getGenericInstance(MovingConfig.class);
|
||||
trace.adjustSettings(cc.traceMaxAge, cc.traceMaxSize, TickTask.getTick());
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ import org.bukkit.event.player.PlayerToggleFlightEvent;
|
|||
import org.bukkit.event.player.PlayerToggleSneakEvent;
|
||||
import org.bukkit.event.player.PlayerToggleSprintEvent;
|
||||
import org.bukkit.event.player.PlayerVelocityEvent;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
@ -90,10 +89,13 @@ import fr.neatmonster.nocheatplus.compat.MCAccess;
|
|||
import fr.neatmonster.nocheatplus.compat.blocks.changetracker.BlockChangeTracker;
|
||||
import fr.neatmonster.nocheatplus.compat.blocks.changetracker.BlockChangeTracker.BlockChangeEntry;
|
||||
import fr.neatmonster.nocheatplus.compat.blocks.changetracker.BlockChangeTracker.Direction;
|
||||
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.location.SimplePositionWithLook;
|
||||
import fr.neatmonster.nocheatplus.components.modifier.IAttributeAccess;
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.IHaveCheckType;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.INeedConfig;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.IRemoveData;
|
||||
|
@ -106,6 +108,7 @@ import fr.neatmonster.nocheatplus.logging.Streams;
|
|||
import fr.neatmonster.nocheatplus.logging.debug.DebugUtil;
|
||||
import fr.neatmonster.nocheatplus.players.DataManager;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
|
||||
import fr.neatmonster.nocheatplus.utilities.PotionUtil;
|
||||
|
@ -115,9 +118,9 @@ import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
|
|||
import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.PlayerLocation;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.TrigUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.MapUtil;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Central location to listen to events that are relevant for the moving checks.
|
||||
|
@ -204,10 +207,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
|
|||
private final int idMoveEvent = counters.registerKey("event.player.move");
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public MovingListener() {
|
||||
super(CheckType.MOVING);
|
||||
// Register vehicleChecks.
|
||||
NCPAPIProvider.getNoCheatPlusAPI().addComponent(vehicleChecks);
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
api.addComponent(vehicleChecks);
|
||||
blockChangeTracker = NCPAPIProvider.getNoCheatPlusAPI().getBlockChangeTracker();
|
||||
if (Bridge1_9.hasEntityToggleGlideEvent()) {
|
||||
queuedComponents.add(new Listener() {
|
||||
|
@ -219,6 +224,35 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Register config and data.
|
||||
// TODO: Should register before creating Check instances ?
|
||||
api.register(api.newRegistrationContext()
|
||||
// MovingConfig
|
||||
.registerConfigWorld(MovingConfig.class)
|
||||
.factory(new IFactoryOne<WorldFactoryArgument, MovingConfig>() {
|
||||
@Override
|
||||
public MovingConfig getNewInstance(
|
||||
final WorldFactoryArgument arg) {
|
||||
return new MovingConfig(arg.worldData);
|
||||
}
|
||||
})
|
||||
.registerConfigTypesPlayer(CheckType.MOVING, true)
|
||||
.context() //
|
||||
// MovingData
|
||||
.registerDataPlayer(MovingData.class)
|
||||
.factory(new IFactoryOne<PlayerFactoryArgument, MovingData>() {
|
||||
@Override
|
||||
public MovingData getNewInstance(
|
||||
final PlayerFactoryArgument arg) {
|
||||
return new MovingData(arg.worldData.getGenericInstance(
|
||||
MovingConfig.class), arg.playerData);
|
||||
}
|
||||
})
|
||||
.addToGroups(CheckType.MOVING, false, IData.class, ICheckData.class)
|
||||
.removeSubCheckData(CheckType.MOVING, true)
|
||||
.context() //
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2463,12 +2497,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
|
|||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onWorldunload(final WorldUnloadEvent event) {
|
||||
// TODO: Consider removing the world-related data anyway (even if the event is cancelled).
|
||||
MovingData.onWorldUnload(event.getWorld());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerToggleSneak(final PlayerToggleSneakEvent event) {
|
||||
survivalFly.setReallySneaking(event.getPlayer(), event.isSneaking());
|
||||
|
@ -2696,6 +2724,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
|
|||
@Override
|
||||
public CheckType getCheckType() {
|
||||
// TODO: this is for the hover check only...
|
||||
// TODO: ugly.
|
||||
return CheckType.MOVING_SURVIVALFLY;
|
||||
}
|
||||
|
||||
|
@ -2717,7 +2746,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
|
|||
public void onReload() {
|
||||
aux.clear();
|
||||
hoverTicksStep = Math.max(1, ConfigManager.getConfigFile().getInt(ConfPaths.MOVING_SURVIVALFLY_HOVER_STEP));
|
||||
MovingData.onReload();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,8 +16,16 @@ package fr.neatmonster.nocheatplus.checks.net;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.count.ActionFrequency;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Static method utility for networking related stuff.
|
||||
|
@ -163,4 +171,31 @@ public class NetStatic {
|
|||
return Math.max(0.0, violation);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void registerTypes() {
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
api.register(api.newRegistrationContext()
|
||||
// NetConfig
|
||||
.registerConfigWorld(NetConfig.class)
|
||||
.factory(new IFactoryOne<WorldFactoryArgument, NetConfig>() {
|
||||
@Override
|
||||
public NetConfig getNewInstance(WorldFactoryArgument arg) {
|
||||
return new NetConfig(arg.worldData);
|
||||
}
|
||||
})
|
||||
.registerConfigTypesPlayer()
|
||||
.context() //
|
||||
// NetData
|
||||
.registerDataPlayer(NetData.class)
|
||||
.factory(new IFactoryOne<PlayerFactoryArgument, NetData>() {
|
||||
@Override
|
||||
public NetData getNewInstance(PlayerFactoryArgument arg) {
|
||||
return new NetData(arg.playerData.getGenericInstance(NetConfig.class));
|
||||
}
|
||||
})
|
||||
.addToGroups(CheckType.NET, true, IData.class, ICheckData.class)
|
||||
.context() //
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import org.bukkit.command.CommandSender;
|
|||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.command.BaseCommand;
|
||||
import fr.neatmonster.nocheatplus.command.NoCheatPlusCommand.NCPReloadEvent;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.INotifyReload;
|
||||
|
@ -71,22 +70,14 @@ public class ReloadCommand extends BaseCommand {
|
|||
// Do the actual reload.
|
||||
ConfigManager.cleanup();
|
||||
// (Magic/TODO)
|
||||
ConfigManager.init(access,
|
||||
(WorldDataManager) NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager());
|
||||
final WorldDataManager worldDataManager = (WorldDataManager) NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager();
|
||||
ConfigManager.init(access, worldDataManager);
|
||||
if (logManager instanceof INotifyReload) { // TODO: This is a band-aid.
|
||||
((INotifyReload) logManager).onReload();
|
||||
}
|
||||
|
||||
// Remove all cached configs.
|
||||
DataManager.clearConfigs(); // There you have to add XConfig.clear() form now on.
|
||||
|
||||
// Remove some checks data.
|
||||
// TODO: Better concept (INotifyReload).
|
||||
for (final CheckType checkType : new CheckType[]{
|
||||
CheckType.BLOCKBREAK, CheckType.FIGHT,
|
||||
}){
|
||||
DataManager.clearData(checkType);
|
||||
}
|
||||
// Remove all cached configs from data.
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getPlayerDataManager().removeCachedConfigs();
|
||||
|
||||
// Reset debug flags to default (temp, heavy).
|
||||
DataManager.restoreDefaultDebugFlags();
|
||||
|
|
|
@ -66,28 +66,28 @@ public class RemovePlayerCommand extends BaseCommand {
|
|||
if (player != null) playerName = player.getName();
|
||||
|
||||
ViolationHistory hist = ViolationHistory.getHistory(playerName, false);
|
||||
boolean histRemoved = false;
|
||||
boolean somethingFound = false;
|
||||
if (hist != null){
|
||||
histRemoved = hist.remove(checkType);
|
||||
somethingFound = hist.remove(checkType);
|
||||
if (checkType == CheckType.ALL){
|
||||
histRemoved = true;
|
||||
somethingFound = true;
|
||||
ViolationHistory.removeHistory(playerName);
|
||||
}
|
||||
}
|
||||
|
||||
if (DataManager.removeExecutionHistory(checkType, playerName)) histRemoved = true;
|
||||
if (DataManager.removeExecutionHistory(checkType, playerName)) {
|
||||
somethingFound = true;
|
||||
}
|
||||
|
||||
final boolean dataRemoved = DataManager.removeData(playerName, checkType);
|
||||
if (DataManager.removeData(playerName, checkType)) {
|
||||
somethingFound = true;
|
||||
}
|
||||
|
||||
if (dataRemoved || histRemoved){
|
||||
String which;
|
||||
if (dataRemoved && histRemoved) which = "data and history";
|
||||
else if (dataRemoved) which = "data";
|
||||
else which = "history";
|
||||
sender.sendMessage(TAG + "Removed " + which + " (" + checkType + "): " + playerName);
|
||||
if (somethingFound){
|
||||
sender.sendMessage(TAG + "Issued history and data removal (" + checkType + "): " + playerName);
|
||||
}
|
||||
else
|
||||
sender.sendMessage(TAG + "Nothing found (" + checkType + ", exact spelling): " + playerName);
|
||||
sender.sendMessage(TAG + "Nothing found (" + checkType + "): " + playerName + " (spelled correctly?)");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import fr.neatmonster.nocheatplus.compat.blocks.changetracker.BlockChangeTracker
|
|||
import fr.neatmonster.nocheatplus.components.registry.ComponentRegistry;
|
||||
import fr.neatmonster.nocheatplus.components.registry.ComponentRegistryProvider;
|
||||
import fr.neatmonster.nocheatplus.components.registry.GenericInstanceRegistry;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.RegistrationContext;
|
||||
import fr.neatmonster.nocheatplus.event.mini.EventRegistryBukkit;
|
||||
import fr.neatmonster.nocheatplus.logging.LogManager;
|
||||
import fr.neatmonster.nocheatplus.permissions.PermissionRegistry;
|
||||
|
@ -216,4 +217,20 @@ public interface NoCheatPlusAPI extends ComponentRegistry<Object>, ComponentRegi
|
|||
*/
|
||||
public IPlayerDataManager getPlayerDataManager();
|
||||
|
||||
/**
|
||||
* Get a new registration context instance for registration with
|
||||
* {@link NoCheatPlusAPI#register(RegistrationContext)}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public RegistrationContext newRegistrationContext();
|
||||
|
||||
/**
|
||||
* Do use {@link NoCheatPlusAPI#newRegistrationContext()} for future
|
||||
* compatibility.
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public void register(RegistrationContext context);
|
||||
|
||||
}
|
||||
|
|
|
@ -12,14 +12,14 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.access;
|
||||
package fr.neatmonster.nocheatplus.components.config;
|
||||
|
||||
/**
|
||||
* TODO: Keep / Remove.
|
||||
*
|
||||
* @author asofold
|
||||
*/
|
||||
public interface ICheckConfig {
|
||||
public interface ICheckConfig extends IConfig {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.config;
|
||||
|
||||
/**
|
||||
* Empty interface for grouping configurations.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IConfig {
|
||||
|
||||
}
|
|
@ -32,6 +32,8 @@ package fr.neatmonster.nocheatplus.components.data;
|
|||
*/
|
||||
public interface ICanHandleTimeRunningBackwards {
|
||||
|
||||
// TODO: IDataOn ? Applicable data access (IGetGenericInstance) as argument?
|
||||
|
||||
/**
|
||||
* Adjust to system time having run backwards (just "a second ago").
|
||||
*/
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.access;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
package fr.neatmonster.nocheatplus.components.data;
|
||||
|
||||
/**
|
||||
* This is for future purposes. Might remove...<br>
|
||||
|
@ -27,6 +25,6 @@ import fr.neatmonster.nocheatplus.components.data.IData;
|
|||
* @author asofold
|
||||
* @TODO Keep/Remove
|
||||
*/
|
||||
public interface ICheckData extends IData{
|
||||
public interface ICheckData extends IData {
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.data;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
|
||||
/**
|
||||
* Player join: : Data storage specific listener for explicit registration with
|
||||
* the appropriate registry.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IDataOnJoin {
|
||||
|
||||
/**
|
||||
* Called with a player join event.
|
||||
*
|
||||
* @param player
|
||||
* @param pData
|
||||
* @return Return true to remove the data instance from the cache in
|
||||
* question, false otherwise.
|
||||
*/
|
||||
public boolean dataOnJoin(Player player, IPlayerData pData);
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.data;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
|
||||
/**
|
||||
* Player leave (quit / kick): Data storage specific listener for explicit
|
||||
* registration with the appropriate registry.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IDataOnLeave {
|
||||
|
||||
/**
|
||||
* Called with player quit or kick.
|
||||
* <hr>
|
||||
* (TODO / subject to fix:) Might get called twice (kick + quit).
|
||||
*
|
||||
* @param player
|
||||
* @param pData
|
||||
* @return Return true to remove the data instance from the cache in
|
||||
* question, false otherwise.
|
||||
*/
|
||||
public boolean dataOnLeave(Player player, IPlayerData pData);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.data;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.registry.IGetGenericInstance;
|
||||
|
||||
/**
|
||||
* Configuration reload: Data storage specific listener for explicit
|
||||
* registration with the appropriate registry.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IDataOnReload {
|
||||
|
||||
/**
|
||||
* Called after the configuration has been reloaded.
|
||||
*
|
||||
* @param dataAccess
|
||||
* Applicable data access point for data / configs.
|
||||
* @return Return true to remove the data instance from the cache in
|
||||
* question, false otherwise.
|
||||
*/
|
||||
public boolean dataOnReload(IGetGenericInstance dataAccess);
|
||||
|
||||
}
|
|
@ -12,29 +12,29 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.access;
|
||||
package fr.neatmonster.nocheatplus.components.data;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
|
||||
/**
|
||||
* Extension for CheckData, enabling disable spell checking removal of sub check
|
||||
* data.
|
||||
* Check type specific data removal: Data storage specific listener for explicit
|
||||
* registration with the appropriate registry.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IRemoveSubCheckData {
|
||||
public interface IDataOnRemoveSubCheckData {
|
||||
|
||||
/**
|
||||
* Remove the sub check data of the given CheckType.
|
||||
* Pinpoint per check type data removal (with the option to keep the
|
||||
* containing data instance).
|
||||
*
|
||||
* @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.
|
||||
* @param checkTypes
|
||||
* @return Return true to remove the data instance from the cache in
|
||||
* question, false otherwise.
|
||||
*/
|
||||
public boolean removeSubCheckData(CheckType checkType);
|
||||
public boolean dataOnRemoveSubCheckData(final Collection<CheckType> checkTypes);
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.data;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
|
||||
/**
|
||||
* Player changed world: Data storage specific listener for explicit
|
||||
* registration with the appropriate registry.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IDataOnWorldChange {
|
||||
|
||||
/**
|
||||
* Called with player having changed the world.
|
||||
*
|
||||
* @param player
|
||||
* @param pData
|
||||
* @param previousWorld
|
||||
* @param newWorld
|
||||
* @return Return true to remove the data instance from the cache in
|
||||
* question, false otherwise.
|
||||
*/
|
||||
public boolean dataOnWorldChange(Player player, IPlayerData pData,
|
||||
World previousWorld, World newWorld);
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.data;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.registry.IGetGenericInstance;
|
||||
|
||||
/**
|
||||
* World unload: Data storage specific listener for explicit registration with
|
||||
* the appropriate registry.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IDataOnWorldUnload {
|
||||
|
||||
/**
|
||||
* Called with a world unload event.
|
||||
*
|
||||
* @param world
|
||||
* @return Return true to remove the data instance from the cache in
|
||||
* question, false otherwise.
|
||||
*/
|
||||
public boolean dataOnWorldUnload(World world,
|
||||
final IGetGenericInstance dataAccess);
|
||||
|
||||
}
|
|
@ -52,19 +52,27 @@ public abstract class BaseCheckNode<N extends BaseCheckNode<N>> extends CheckTyp
|
|||
|
||||
// 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<N> access) {
|
||||
/**
|
||||
* Override state.
|
||||
*
|
||||
* @param active
|
||||
* @param overrideType
|
||||
* @param overrideChildren
|
||||
* @param access
|
||||
*/
|
||||
protected void override(final AlmostBoolean active,
|
||||
final OverrideType overrideType, final boolean overrideChildren,
|
||||
final IConfigFlagAccess<N> access) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final boolean applicable = access.getConfigState((N) this).setValue(active, overrideType);
|
||||
if (applicable) {
|
||||
// The flag is updated here.
|
||||
configFlagUpdate(rawConfiguration, false, access);
|
||||
update(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,
|
||||
child.override(active, overrideType,
|
||||
true, access);
|
||||
}
|
||||
}
|
||||
|
@ -72,14 +80,20 @@ public abstract class BaseCheckNode<N extends BaseCheckNode<N>> extends CheckTyp
|
|||
// 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);
|
||||
child.update(false, access);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void configFlagUpdate(final ConfigFile rawConfiguration,
|
||||
final boolean forceUpdateChildren, final IConfigFlagAccess<N> access) {
|
||||
/**
|
||||
* Update in place according to tree state.
|
||||
*
|
||||
* @param forceUpdateChildren
|
||||
* @param access
|
||||
*/
|
||||
protected void update(final boolean forceUpdateChildren,
|
||||
final IConfigFlagAccess<N> access) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final N thisNode = (N) this; // TODO
|
||||
final boolean previousActive = access.getState(thisNode);
|
||||
|
@ -89,19 +103,7 @@ public abstract class BaseCheckNode<N extends BaseCheckNode<N>> extends CheckTyp
|
|||
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.
|
||||
// Fetch from parent.
|
||||
if (newActive == AlmostBoolean.MAYBE) {
|
||||
N parent = getParent();
|
||||
if (parent == null) {
|
||||
|
@ -123,11 +125,63 @@ public abstract class BaseCheckNode<N extends BaseCheckNode<N>> extends CheckTyp
|
|||
// Only update, if the state depends on the parent.
|
||||
if (forceUpdateChildren
|
||||
|| access.getConfigState(node).getValue() == AlmostBoolean.MAYBE) {
|
||||
node.configFlagUpdate(rawConfiguration, forceUpdateChildren, access);
|
||||
node.update(forceUpdateChildren, access);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update towards the given rawConfiguration instance.
|
||||
*
|
||||
* @param rawConfiguration
|
||||
* @param forceUpdateChildren
|
||||
* @param access
|
||||
*/
|
||||
protected void update(final ConfigFile rawConfiguration,
|
||||
final boolean forceUpdateChildren, final IConfigFlagAccess<N> access) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final N thisNode = (N) this; // TODO
|
||||
final AlmostBooleanWithOverride configActivation = access.getConfigState(thisNode);
|
||||
|
||||
// First attempt to override by config.
|
||||
if (rawConfiguration != null) {
|
||||
if (configActivation.allowsOverrideBy(
|
||||
OverrideType.SPECIFIC)) {
|
||||
// TODO: SPECIFIC for inherited !?
|
||||
final String configPath = access.getConfigPath(thisNode);
|
||||
final AlmostBoolean setValue;
|
||||
if (configPath == null) {
|
||||
setValue = AlmostBoolean.MAYBE;
|
||||
}
|
||||
else {
|
||||
// TODO: Contract? Either config is null, or path must exist.
|
||||
setValue = rawConfiguration.getAlmostBoolean(configPath, AlmostBoolean.MAYBE);
|
||||
}
|
||||
configActivation.setValue(setValue, configOverrideType);
|
||||
}
|
||||
}
|
||||
// TODO: else -> set to MAYBE ?
|
||||
|
||||
final boolean oldState = access.getState(thisNode);
|
||||
update(false, access); // Update in-place.
|
||||
final boolean changed = oldState ^ access.getState(thisNode);
|
||||
|
||||
if (forceUpdateChildren) {
|
||||
// Update children with configuration (forced).
|
||||
for (final N node : this.getChildren()) {
|
||||
node.update(rawConfiguration, forceUpdateChildren, access);
|
||||
}
|
||||
}
|
||||
else if (changed) {
|
||||
// Update children just for the changed parent.
|
||||
for (final N node : this.getChildren()) {
|
||||
// Only update, if the state depends on the parent.
|
||||
if (access.getConfigState(node).getValue() == AlmostBoolean.MAYBE) {
|
||||
node.update(false, access);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -78,16 +78,26 @@ public abstract class CheckNodeWithDebug<N extends CheckNodeWithDebug<N>> extend
|
|||
|
||||
// TODO: @Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void overrideDebug(final ConfigFile rawConfiguration,
|
||||
final AlmostBoolean active, final OverrideType overrideType,
|
||||
protected void overrideDebug(
|
||||
final AlmostBoolean active,
|
||||
final OverrideType overrideType,
|
||||
final boolean overrideChildren) {
|
||||
configFlagOverride(rawConfiguration, active, overrideType, overrideChildren, accessDebug);
|
||||
override(active, overrideType, overrideChildren, accessDebug);
|
||||
}
|
||||
|
||||
// TODO: @Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void updateDebug(final ConfigFile rawConfiguration, final boolean forceUpdateChildren) {
|
||||
configFlagUpdate(rawConfiguration, forceUpdateChildren, accessDebug);
|
||||
protected void updateDebug(
|
||||
final ConfigFile rawConfiguration,
|
||||
final boolean forceUpdateChildren) {
|
||||
update(rawConfiguration, forceUpdateChildren, accessDebug);
|
||||
}
|
||||
|
||||
// TODO: @Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void updateDebug(
|
||||
final boolean forceUpdateChildren) {
|
||||
update(forceUpdateChildren, accessDebug);
|
||||
}
|
||||
|
||||
// TODO: resetDebug(...)
|
||||
|
|
|
@ -160,7 +160,7 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry,
|
|||
* Only call if uniqueHandle is null and under lock.
|
||||
*/
|
||||
private void updateUniqueHandle() {
|
||||
if (uniqueHandle.isDisabled()) {
|
||||
if (uniqueHandle != null && uniqueHandle.isDisabled()) {
|
||||
unregisterListener(uniqueHandle);
|
||||
}
|
||||
if (uniqueHandle == null) {
|
||||
|
|
|
@ -12,12 +12,11 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.registry;
|
||||
package fr.neatmonster.nocheatplus.components.registry.factory;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -31,7 +30,7 @@ import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW;
|
|||
* @param <A>
|
||||
* Argument type for IFactoryOne instances.
|
||||
*/
|
||||
public class FactoryOneRegistry<A> {
|
||||
public class FactoryOneRegistry<A> implements IFactoryOneRegistry<A> {
|
||||
|
||||
private final Lock lock;
|
||||
private final IPrimaryThreadContextTester primaryThreadContextTester;
|
||||
|
@ -45,13 +44,8 @@ public class FactoryOneRegistry<A> {
|
|||
factories = new HashMapLOW<Class<?>, IFactoryOne<A,?>>(lock, 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that types are automatically sorted into registered groups.
|
||||
*
|
||||
* @param registerFor
|
||||
* @param factory
|
||||
*/
|
||||
public <I, T extends I> void registerFactory(final Class<T> registerFor,
|
||||
@Override
|
||||
public <T> void registerFactory(final Class<T> registerFor,
|
||||
final IFactoryOne<A, T> factory) {
|
||||
if (!primaryThreadContextTester.isPrimaryThread()) {
|
||||
outsideThreadContext("register factory");
|
||||
|
@ -65,16 +59,7 @@ public class FactoryOneRegistry<A> {
|
|||
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-
|
||||
*/
|
||||
@Override
|
||||
public <T> T getNewInstance(final Class<T> registeredFor, final A arg) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final IFactoryOne<A, T> factory = (IFactoryOne<A, T>) factories.get(registeredFor);
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.registry.factory;
|
||||
|
||||
public interface IFactoryOneRegistry<A> {
|
||||
|
||||
/**
|
||||
* Register a factory.
|
||||
*
|
||||
* @param registerFor
|
||||
* @param factory
|
||||
*/
|
||||
public <T> void registerFactory(final Class<T> registerFor,
|
||||
final IFactoryOne<A, T> factory);
|
||||
|
||||
/**
|
||||
* Fetch a new instance from a registered factory.
|
||||
*
|
||||
* @param registeredFor
|
||||
* @param arg
|
||||
* @return
|
||||
* @throws RuntimeException
|
||||
* (might get changed to a registry type of exception), in case
|
||||
* a factory throws something-
|
||||
*/
|
||||
public <T> T getNewInstance(final Class<T> registeredFor, final A arg);
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.registry.factory;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.registry.meta.IRichTypeSetRegistry;
|
||||
|
||||
/**
|
||||
* Combine an IFactoryOneRegistry with TypeSetRegistries (general and per check
|
||||
* type). TypeSetRegistries are kept "synchronized", in terms of registered
|
||||
* groups (not items).
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IRichFactoryRegistry<A> extends IRichTypeSetRegistry, IFactoryOneRegistry<A> {
|
||||
|
||||
/**
|
||||
* Register a factory, see:
|
||||
* {@link IFactoryOneRegistry#registerFactory(Class, IFactoryOne)}
|
||||
* <hr/>
|
||||
* The type the factory is registered for might automatically be added to
|
||||
* all groups which have been set to auto grouping:
|
||||
* {@link #createAutoGroup(Class)}
|
||||
* <hr/>
|
||||
*/
|
||||
@Override
|
||||
public <T> void registerFactory(final Class<T> registerFor,
|
||||
final IFactoryOne<A, T> factory);
|
||||
|
||||
|
||||
/**
|
||||
* Create the group, and automatically add factory return types to this group
|
||||
* @param groupType
|
||||
*/
|
||||
public <G> void createAutoGroup(Class<G> groupType);
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.registry.factory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.meta.RichTypeSetRegistry;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckTypeUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
|
||||
|
||||
/**
|
||||
* Thread safe "read" factory registry with additional convenience
|
||||
* functionality. (TODO: Registration might not be thread-safe.)
|
||||
* <hr>
|
||||
* Thread safety further depends on the registered factories for fetching new
|
||||
* instances.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
* @param <A>
|
||||
* Factory argument type.
|
||||
*/
|
||||
public class RichFactoryRegistry<A> extends RichTypeSetRegistry implements IRichFactoryRegistry<A> {
|
||||
|
||||
public static class CheckRemovalSpec {
|
||||
|
||||
public final Collection<Class<?>> completeRemoval = new LinkedHashSet<Class<?>>();
|
||||
public final Collection<Class<? extends IDataOnRemoveSubCheckData>> subCheckRemoval = new LinkedHashSet<Class<? extends IDataOnRemoveSubCheckData>>();
|
||||
public final Collection<CheckType> checkTypes;;
|
||||
|
||||
public CheckRemovalSpec(final CheckType checkType,
|
||||
final boolean withDescendantCheckTypes,
|
||||
final IRichFactoryRegistry<?> factoryRegistry
|
||||
) {
|
||||
this(withDescendantCheckTypes
|
||||
? CheckTypeUtil.getWithDescendants(checkType)
|
||||
: Arrays.asList(checkType), factoryRegistry);
|
||||
}
|
||||
|
||||
public CheckRemovalSpec(final Collection<CheckType> checkTypes,
|
||||
final IRichFactoryRegistry<?> factoryRegistry) {
|
||||
this.checkTypes = checkTypes;
|
||||
for (final CheckType refType : checkTypes) {
|
||||
for (final Class<? extends IData> type : factoryRegistry.getGroupedTypes(
|
||||
IData.class, refType)) {
|
||||
completeRemoval.add(type);
|
||||
}
|
||||
for (final Class<? extends IDataOnRemoveSubCheckData> type : factoryRegistry.getGroupedTypes(
|
||||
IDataOnRemoveSubCheckData.class, refType)) {
|
||||
subCheckRemoval.add(type);
|
||||
}
|
||||
}
|
||||
if (checkTypes.contains(CheckType.ALL)) {
|
||||
for (final Class<? extends IData> type : factoryRegistry.getGroupedTypes(
|
||||
IData.class)) {
|
||||
completeRemoval.add(type);
|
||||
}
|
||||
for (final Class<? extends IDataOnRemoveSubCheckData> type : factoryRegistry.getGroupedTypes(
|
||||
IDataOnRemoveSubCheckData.class)) {
|
||||
subCheckRemoval.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Lock lock;
|
||||
private final FactoryOneRegistry<A> factoryRegistry;
|
||||
@SuppressWarnings("unchecked")
|
||||
private Set<Class<?>> autoGroups = Collections.EMPTY_SET;
|
||||
|
||||
|
||||
public RichFactoryRegistry(final Lock lock) {
|
||||
super(lock);
|
||||
this.lock = lock;
|
||||
factoryRegistry = new FactoryOneRegistry<A>(
|
||||
lock, CheckUtils.primaryServerThreadContextTester);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getNewInstance(final Class<T> registeredFor, final A arg) {
|
||||
return factoryRegistry.getNewInstance(registeredFor, arg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> void registerFactory(final Class<T> registerFor,
|
||||
final IFactoryOne<A, T> factory) {
|
||||
lock.lock();
|
||||
factoryRegistry.registerFactory(registerFor, factory);
|
||||
for (final Class<?> groupType: autoGroups) {
|
||||
if (groupType.isAssignableFrom(registerFor)) {
|
||||
addToGroups(registerFor, (Class<? super T>) groupType);
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <G> void createAutoGroup(final Class<G> groupType) {
|
||||
lock.lock();
|
||||
createGroup(groupType);
|
||||
final Set<Class<?>> autoGroups = new LinkedHashSet<Class<?>>(this.autoGroups);
|
||||
autoGroups.add(groupType);
|
||||
this.autoGroups = autoGroups;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.registry.meta;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
|
||||
/**
|
||||
* Combine a general with per check type TypeSetRegistries. TypeSetRegistries
|
||||
* are kept "synchronized", in terms of registered groups (not items).
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IRichTypeSetRegistry {
|
||||
// TODO: package name?
|
||||
|
||||
/**
|
||||
* Get all data types extending 'registeredFor', that have been explicitly
|
||||
* registered for that group.
|
||||
*
|
||||
* @param registeredFor
|
||||
* @return
|
||||
*/
|
||||
public <T> Collection<Class<? extends T>> getGroupedTypes(
|
||||
Class<T> groupType);
|
||||
|
||||
/**
|
||||
* Get all data types extending 'registeredFor', that have been explicitly
|
||||
* registered for that group and for that check type. No inheritance logic
|
||||
* is applied, nor will CheckType.ALL return all data types (use
|
||||
* {@link #getGroupedTypes(Class)} instead).
|
||||
*
|
||||
* @param registeredFor
|
||||
* @return
|
||||
*/
|
||||
public <T> Collection<Class<? extends T>> getGroupedTypes(
|
||||
Class<T> groupType, CheckType checkType);
|
||||
|
||||
// TODO: getFactoryTypes -> registered factory return types ?
|
||||
|
||||
/**
|
||||
* Register types for a group type.
|
||||
* <hr>
|
||||
* Groups are always present for the general registry, as well as for all
|
||||
* check type specific registries. Item type registration remains specific.
|
||||
*
|
||||
* @param itemType
|
||||
* @param groupTypes
|
||||
*/
|
||||
public <I> void addToGroups(Class<I> itemType,
|
||||
Class<? super I>... groupTypes);
|
||||
|
||||
/**
|
||||
* Register the itemType for all applicable group types that already have
|
||||
* been registered.
|
||||
* <hr>
|
||||
* Groups are always present for the general registry, as well as for all
|
||||
* check type specific registries. Item type registration remains specific.
|
||||
*
|
||||
* @param itemType
|
||||
*/
|
||||
public void addToExistingGroups(final Class<?> itemType);
|
||||
|
||||
/**
|
||||
* Register an item type for group types for for a check type (and general). Types get added
|
||||
* both to the general grouped types and those specific to the given check
|
||||
* type.
|
||||
* <hr>
|
||||
* Groups are always present for the general registry, as well as for all
|
||||
* check type specific registries. Item type registration remains specific.
|
||||
*
|
||||
* @param checkType
|
||||
* @param itemType
|
||||
* @param groupTypes
|
||||
*/
|
||||
public <I> void addToGroups(CheckType checkType,
|
||||
Class<I> itemType, Class<? super I>... groupTypes);
|
||||
|
||||
/**
|
||||
* Register the itemType for all applicable group types that already have
|
||||
* been registered, both for the general registry and check type specific
|
||||
* (no inheritance logic).
|
||||
* <hr>
|
||||
* Groups are always present for the general registry, as well as for all
|
||||
* check type specific registries. Item type registration remains specific.
|
||||
*
|
||||
*
|
||||
* @param checkType
|
||||
* @param itemType
|
||||
*/
|
||||
public <I> void addToExistingGroups(CheckType checkType,
|
||||
Class<I> itemType);
|
||||
|
||||
/**
|
||||
* Register an item type for group types for for all given check types (and
|
||||
* general). Data types get added both to the general grouped types and
|
||||
* those specific to the given check types. Suggested use is with
|
||||
* {@link fr.neatmonster.nocheatplus.utilities.CheckTypeUtil}.
|
||||
* <hr>
|
||||
* Groups are always present for the general registry, as well as for all
|
||||
* check type specific registries. Item type registration remains specific.
|
||||
*
|
||||
* @param checkTypes
|
||||
* @param itemType
|
||||
* @param groupTypes
|
||||
*/
|
||||
public <I> void addToGroups(Collection<CheckType> checkTypes,
|
||||
Class<I> itemType, Class<? super I>... groupTypes);
|
||||
|
||||
/**
|
||||
* Register the itemType for all applicable group types that already have
|
||||
* been registered, both for the general registry and check type specific
|
||||
* (no inheritance logic).Suggested use is with
|
||||
* {@link fr.neatmonster.nocheatplus.utilities.CheckTypeUtil}.
|
||||
* <hr>
|
||||
* Groups are always present for the general registry, as well as for all
|
||||
* check type specific registries. Item type registration remains specific.
|
||||
*
|
||||
*
|
||||
* @param checkType
|
||||
* @param itemType
|
||||
*/
|
||||
public <I> void addToExistingGroups(Collection<CheckType> checkTypes,
|
||||
Class<I> itemType);
|
||||
|
||||
/**
|
||||
* Register the group type both for the general registry and for all check
|
||||
* types.
|
||||
* <hr>
|
||||
* Groups are always present for the general registry, as well as for all
|
||||
* check type specific registries. Item type registration remains specific.
|
||||
*
|
||||
* @param groupType
|
||||
*/
|
||||
public <G> void createGroup(Class<G> groupType);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.registry.meta;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW;
|
||||
|
||||
public class RichTypeSetRegistry implements IRichTypeSetRegistry {
|
||||
|
||||
private final Lock lock;
|
||||
|
||||
/**
|
||||
* Grouped types to have a faster way of iterating data types stored in the
|
||||
* PlayerData cache.
|
||||
*/
|
||||
private final TypeSetRegistry groupedTypes;
|
||||
/**
|
||||
* Additional attachment of grouped types to check types - needs to be
|
||||
* registered explicitly.
|
||||
*/
|
||||
private final HashMapLOW<CheckType, TypeSetRegistry> groupedTypesByCheckType;
|
||||
|
||||
|
||||
public RichTypeSetRegistry(final Lock lock) {
|
||||
this.lock = lock;
|
||||
groupedTypes = new TypeSetRegistry(lock);
|
||||
groupedTypesByCheckType = new HashMapLOW<CheckType,
|
||||
TypeSetRegistry>(lock, 35);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Collection<Class<? extends T>> getGroupedTypes(final Class<T> groupType) {
|
||||
return groupedTypes.getGroupedTypes(groupType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Collection<Class<? extends T>> getGroupedTypes(final Class<T> groupType,
|
||||
final CheckType checkType) {
|
||||
final TypeSetRegistry reg = groupedTypesByCheckType.get(checkType);
|
||||
return (reg == null
|
||||
? (Collection<Class<? extends T>>) Collections.EMPTY_SET
|
||||
: reg.getGroupedTypes(groupType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToGroups(final Class<I> itemType,
|
||||
final Class<? super I>... groupTypes) {
|
||||
lock.lock();
|
||||
for (final Class<? super I> groupType : groupTypes) {
|
||||
createGroup(groupType);
|
||||
}
|
||||
groupedTypes.addToGroups(itemType, groupTypes);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToGroups(CheckType checkType, Class<I> itemType,
|
||||
Class<? super I>... groupTypes) {
|
||||
lock.lock();
|
||||
for (final Class<? super I> groupType : groupTypes) {
|
||||
createGroup(groupType);
|
||||
}
|
||||
TypeSetRegistry reg = groupedTypesByCheckType.get(checkType);
|
||||
if (reg == null) {
|
||||
reg = new TypeSetRegistry(lock);
|
||||
updateRegistry(reg);
|
||||
groupedTypesByCheckType.put(checkType, reg);
|
||||
}
|
||||
reg.addToGroups(itemType, groupTypes);
|
||||
groupedTypes.addToGroups(itemType, groupTypes);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToExistingGroups(Class<?> itemType) {
|
||||
groupedTypes.addToExistingGroups(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToExistingGroups(final CheckType checkType,
|
||||
final Class<I> itemType) {
|
||||
lock.lock();
|
||||
TypeSetRegistry reg = groupedTypesByCheckType.get(checkType);
|
||||
if (reg == null) {
|
||||
reg = new TypeSetRegistry(lock);
|
||||
updateRegistry(reg);
|
||||
groupedTypesByCheckType.put(checkType, reg);
|
||||
}
|
||||
reg.addToExistingGroups(itemType);
|
||||
groupedTypes.addToExistingGroups(itemType);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given registry to contain all group types of the general
|
||||
* registry.
|
||||
*
|
||||
* @param reg
|
||||
*/
|
||||
private void updateRegistry(final TypeSetRegistry reg) {
|
||||
reg.updateGroupTypes(groupedTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <G> void createGroup(Class<G> groupType) {
|
||||
groupedTypes.createGroup(groupType);
|
||||
for (Entry<CheckType, TypeSetRegistry> entry : groupedTypesByCheckType.iterable()) {
|
||||
entry.getValue().createGroup(groupType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToGroups(final Collection<CheckType> checkTypes,
|
||||
final Class<I> itemType, final Class<? super I>... groupTypes) {
|
||||
lock.lock();
|
||||
for (final CheckType checkType : checkTypes) {
|
||||
addToGroups(checkType, itemType, groupTypes);
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToExistingGroups(final Collection<CheckType> checkTypes,
|
||||
final Class<I> itemType) {
|
||||
lock.lock();
|
||||
for (final CheckType checkType : checkTypes) {
|
||||
addToExistingGroups(checkType, itemType);
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.components.registry;
|
||||
package fr.neatmonster.nocheatplus.components.registry.meta;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -69,6 +69,10 @@ public class TypeSetRegistry {
|
|||
return group;
|
||||
}
|
||||
|
||||
void createGroup(TypeSetRegistry extReg) {
|
||||
extReg.createGroup(this.groupType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////////////////////77
|
||||
|
@ -110,6 +114,19 @@ public class TypeSetRegistry {
|
|||
lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create if not existent.
|
||||
*
|
||||
* @param itemTypes
|
||||
*/
|
||||
public <G> void createGroup(final Class<G> groupType) {
|
||||
lock.lock();
|
||||
if (!groupedTypes.containsKey(groupType)) {
|
||||
newGroupNode(groupType);
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
private <G> GroupNode<G> newGroupNode(Class<G> groupType) {
|
||||
final GroupNode<G> node = new GroupNode<G>(groupType);
|
||||
groupedTypes.put(groupType, node);
|
||||
|
@ -147,4 +164,19 @@ public class TypeSetRegistry {
|
|||
return group == null ? Collections.EMPTY_LIST : group.getItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure all groups exist (items are not copied).
|
||||
*
|
||||
* @param refReg
|
||||
*/
|
||||
public void updateGroupTypes(TypeSetRegistry refReg) {
|
||||
lock.lock(); // Ensure no interruption - iterator is not using lock, thus no dead locks.
|
||||
for (final Entry<Class<?>, GroupNode<?>> entry : refReg.groupedTypes.iterable()) {
|
||||
if (!this.groupedTypes.containsKey(entry.getKey())) {
|
||||
entry.getValue().createGroup(this);
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
|
@ -681,5 +681,14 @@ public class RegistrationOrder {
|
|||
&& (afterTag == null ? other.getAfterTag() == null : afterTag.equals(other.getAfterTag()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RegistrationOrder(p=" + basePriority
|
||||
+ (tag == null ? "" : " t='" + tag + "'")
|
||||
+ (beforeTag == null ? "" : " bt='" + beforeTag + "'")
|
||||
+ (afterTag == null ? "" : "at='" + afterTag + "'")
|
||||
+ ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package fr.neatmonster.nocheatplus.components.registry.setup;
|
||||
|
||||
public interface IDoRegister {
|
||||
|
||||
public void doRegister();
|
||||
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
package fr.neatmonster.nocheatplus.components.registry.setup;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.config.IConfig;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.config.RegisterConfigWorld;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.data.RegisterDataPlayer;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.data.RegisterDataWorld;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.instance.RegisterInstancePlayer;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.instance.RegisterInstanceWorld;
|
||||
|
||||
/**
|
||||
* Convenience: set up a check or similar with NCP registries.
|
||||
* <hr/>
|
||||
* For now, this is only a registry helper for internal registration. Later on,
|
||||
* this will aggregate components, dependencies and activation conditions,
|
||||
* enabling automatic registration and unregistering. Multiple contexts
|
||||
* registering the same types could lead to inconsistencies, if one gets
|
||||
* unregistered - the planned dependency mechanism is meant to mend this (if not
|
||||
* already registered, register the dependency first, then the component using
|
||||
* it).
|
||||
* <hr/>
|
||||
* <ul>
|
||||
* <li>Register factories and type relations for instances, config, data.</li>
|
||||
* <li>(When to register, dependencies, IActivation.)</li>
|
||||
* <li>(Register further components, such as listeners.)</li>
|
||||
* <li>(When to unregister.)</li>
|
||||
* <li>(More precise definition what/how to unregister.)</li>
|
||||
* </ul>
|
||||
* <hr/>
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public class RegistrationContext implements IDoRegister {
|
||||
|
||||
/*
|
||||
* / TODO: ILockable <-> tie to instantiation by global registry, tie sub
|
||||
* objects to this.
|
||||
*/
|
||||
|
||||
// TODO: Base some things rather on ICheckConfig, ICheckData ?
|
||||
|
||||
/**
|
||||
* General type of registration, in terms of how often / when it's tried to
|
||||
* get registered.
|
||||
* <hr/>
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public static enum RegistrationType {
|
||||
/** Try to register directly, one time only. */
|
||||
ONCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removal type, in terms of a rough description for when to unregister the
|
||||
* contained components.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public static enum RemovalType {
|
||||
/**
|
||||
* Never remove registration. Still might get removed/dented with the
|
||||
* plugin getting disabled.
|
||||
*/
|
||||
NEVER;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// Instance
|
||||
//////////////////////////////
|
||||
|
||||
// TODO: Put a global registry in control of instantiation, add id(s) / tags.
|
||||
|
||||
private final List<IDoRegister> registerItems = new LinkedList<IDoRegister>();
|
||||
|
||||
//////////////////////////////
|
||||
// Getter
|
||||
//////////////////////////////
|
||||
|
||||
public RegistrationType registrationType() {
|
||||
return RegistrationType.ONCE;
|
||||
}
|
||||
|
||||
public RemovalType removalType() {
|
||||
return RemovalType.NEVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new (attached) per world instance registration object.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public <T extends IConfig> RegisterInstanceWorld<T> registerInstanceWorld(Class<T> type) {
|
||||
RegisterInstanceWorld<T> item = new RegisterInstanceWorld<T>(this, type);
|
||||
registerItems.add(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new (attached) per world config registration object. The config
|
||||
* types are registered with the IPlayerDataManager too (no further grouping
|
||||
* , no factory).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public <T extends IConfig> RegisterConfigWorld<T> registerConfigWorld(Class<T> configType) {
|
||||
RegisterConfigWorld<T> item = new RegisterConfigWorld<T>(this, configType);
|
||||
registerItems.add(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new (attached) per world data registration object. The data
|
||||
* types are registered with the IPlayerDataManager too (no further grouping
|
||||
* , no factory).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public <T extends IData> RegisterDataWorld<T> registerDataWorld(Class<T> dataType) {
|
||||
RegisterDataWorld<T> item = new RegisterDataWorld<T>(this, dataType);
|
||||
registerItems.add(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new (attached) per instance data registration object.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public <T extends IData> RegisterInstancePlayer<T> registerInstancePlayer(Class<T> type) {
|
||||
RegisterInstancePlayer<T> item = new RegisterInstancePlayer<T>(this, type);
|
||||
registerItems.add(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new (attached) per player data registration object.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public <T extends IData> RegisterDataPlayer<T> registerDataPlayer(Class<T> dataType) {
|
||||
RegisterDataPlayer<T> item = new RegisterDataPlayer<T>(this, dataType);
|
||||
registerItems.add(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// Setter
|
||||
//////////////////////////////
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// Other functionality.
|
||||
//////////////////////////////
|
||||
|
||||
@Override
|
||||
public void doRegister() {
|
||||
// TODO: ILockable, ...
|
||||
// TODO: Exception handling.
|
||||
for (IDoRegister item : registerItems) {
|
||||
item.doRegister();
|
||||
}
|
||||
// TODO: (Capability to roll back?)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package fr.neatmonster.nocheatplus.components.registry.setup.config;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.components.config.IConfig;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.RegistrationContext;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.instance.RegisterInstanceWorld;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* World config types are automatically registered as config types with the
|
||||
* IPlayerDataManager - no further grouping is done.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class RegisterConfigWorld<T extends IConfig> extends RegisterInstanceWorld<T> {
|
||||
|
||||
public RegisterConfigWorld(RegistrationContext registrationContext,
|
||||
Class<T> type) {
|
||||
super(registrationContext, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterConfigWorld<T> factory(
|
||||
IFactoryOne<WorldFactoryArgument, T> factory) {
|
||||
super.factory(factory);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterConfigWorld<T> registerConfigTypesPlayer() {
|
||||
registerConfigTypesPlayer = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterConfigWorld<T> addToGroups(
|
||||
final CheckType checkType, final boolean withDescendantCheckTypes,
|
||||
final Class<? super T>... groupTypes) {
|
||||
super.addToGroups(checkType, withDescendantCheckTypes, groupTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public RegisterConfigWorld<T> registerConfigTypesPlayer(
|
||||
CheckType checkType, boolean withDescendantCheckTypes) {
|
||||
super.registerConfigTypesPlayer(checkType, withDescendantCheckTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRegister() {
|
||||
super.doRegister();
|
||||
if (!registerConfigTypesPlayer) {
|
||||
registerConfigTypesPlayer(NCPAPIProvider.getNoCheatPlusAPI().getPlayerDataManager());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package fr.neatmonster.nocheatplus.components.registry.setup.data;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.RegistrationContext;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.instance.RegisterInstancePlayer;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
|
||||
public class RegisterDataPlayer<T extends IData> extends RegisterInstancePlayer<T> {
|
||||
|
||||
public RegisterDataPlayer(RegistrationContext registrationContext,
|
||||
Class<T> type) {
|
||||
super(registrationContext, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterDataPlayer<T> factory(
|
||||
IFactoryOne<PlayerFactoryArgument, T> factory) {
|
||||
super.factory(factory);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterDataPlayer<T> addToGroups(
|
||||
final CheckType checkType, final boolean withDescendantCheckTypes,
|
||||
final Class<? super T>... groupTypes) {
|
||||
super.addToGroups(checkType, withDescendantCheckTypes, groupTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterDataPlayer<T> registerDataTypesPlayer(
|
||||
CheckType checkType, boolean withDescendantCheckTypes) {
|
||||
super.registerDataTypesPlayer(checkType, withDescendantCheckTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterDataPlayer<T> removeSubCheckData(
|
||||
CheckType checkType, boolean withDescendantCheckTypes) {
|
||||
super.removeSubCheckData(checkType, withDescendantCheckTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package fr.neatmonster.nocheatplus.components.registry.setup.data;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.RegistrationContext;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.instance.RegisterInstanceWorld;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
/**
|
||||
* Per world data types are automatically registered as (data) types with the
|
||||
* IPlayerDataManager - no further grouping is done.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class RegisterDataWorld<T extends IData> extends RegisterInstanceWorld<T> {
|
||||
|
||||
public RegisterDataWorld(RegistrationContext registrationContext,
|
||||
Class<T> type) {
|
||||
super(registrationContext, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterDataWorld<T> factory(
|
||||
IFactoryOne<WorldFactoryArgument, T> factory) {
|
||||
super.factory(factory);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterDataWorld<T> addToGroups(
|
||||
final CheckType checkType, final boolean withDescendantCheckTypes,
|
||||
final Class<? super T>... groupTypes) {
|
||||
super.addToGroups(checkType, withDescendantCheckTypes, groupTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterDataWorld<T> registerDataTypesPlayer(
|
||||
CheckType checkType, boolean withDescendantCheckTypes) {
|
||||
super.registerDataTypesPlayer(checkType, withDescendantCheckTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterDataWorld<T> removeSubCheckData(
|
||||
CheckType checkType, boolean withDescendantCheckTypes) {
|
||||
super.removeSubCheckData(checkType, withDescendantCheckTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRegister() {
|
||||
super.doRegister();
|
||||
if (!registerDataTypesPlayer) {
|
||||
registerDataTypesPlayer(NCPAPIProvider.getNoCheatPlusAPI().getPlayerDataManager());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,329 @@
|
|||
package fr.neatmonster.nocheatplus.components.registry.setup.instance;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.components.config.ICheckConfig;
|
||||
import fr.neatmonster.nocheatplus.components.config.IConfig;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IRichFactoryRegistry;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.IDoRegister;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.RegistrationContext;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerDataManager;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckTypeUtil;
|
||||
|
||||
/**
|
||||
* Base class.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
* @param <T>
|
||||
* Instance type.
|
||||
* @param <A>
|
||||
* Argument type for IFactoryOne.
|
||||
*/
|
||||
public abstract class RegisterInstance<T, A> implements IDoRegister {
|
||||
|
||||
/**
|
||||
* Allow registering with multiple registries.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
protected static interface IDoRegisterWithRegistry {
|
||||
void doRegister(IRichFactoryRegistry<?> factoryRegistry);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Instance
|
||||
////////////////////
|
||||
|
||||
protected final RegistrationContext registrationContext;
|
||||
protected final IRichFactoryRegistry<A> factoryRegistry;
|
||||
protected final Class<T> type;
|
||||
protected IFactoryOne<A, T> factory = null;
|
||||
protected boolean registerConfigTypesPlayer = false;
|
||||
protected boolean registerDataTypesPlayer = false;
|
||||
/**
|
||||
* Types that may be registered as types for players as well, for the case
|
||||
* this is a per world type (with or without factory).
|
||||
*/
|
||||
protected final List<IDoRegisterWithRegistry> genericDataItems = new LinkedList<IDoRegisterWithRegistry>();
|
||||
/**
|
||||
* Types that may be registered as types for players as well, for the case
|
||||
* this is a per world type (with or without factory).
|
||||
*/
|
||||
protected final List<IDoRegisterWithRegistry> genericConfigItems = new LinkedList<IDoRegisterWithRegistry>();
|
||||
|
||||
/** Standard items. */
|
||||
protected final List<IDoRegister> items = new LinkedList<IDoRegister>();
|
||||
|
||||
public RegisterInstance(RegistrationContext registrationContext, Class<T> type,
|
||||
IRichFactoryRegistry<A> factoryRegistry) {
|
||||
this.registrationContext = registrationContext;
|
||||
this.factoryRegistry = factoryRegistry;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// Abstract
|
||||
//////////////////////////////
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// Setter (chaining).
|
||||
//////////////////////////////
|
||||
|
||||
/**
|
||||
*
|
||||
* @param factory
|
||||
* @return This instance for chaining.
|
||||
*/
|
||||
public RegisterInstance<T,A> factory(IFactoryOne<A, T> factory) {
|
||||
this.factory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This does not check for data/config types, to apply with
|
||||
* registreXYTypesAB.
|
||||
*
|
||||
* @param checkType
|
||||
* @param withDescendantCheckTypes
|
||||
* @param groupTypes
|
||||
* @return
|
||||
*/
|
||||
public RegisterInstance<T,A> addToGroups(final CheckType checkType,
|
||||
final boolean withDescendantCheckTypes,
|
||||
final Class<? super T>... groupTypes) {
|
||||
items.add(new IDoRegister() {
|
||||
@Override
|
||||
public void doRegister() {
|
||||
if (withDescendantCheckTypes) {
|
||||
factoryRegistry.addToGroups(
|
||||
CheckTypeUtil.getWithDescendants(checkType),
|
||||
type, groupTypes);
|
||||
}
|
||||
else {
|
||||
factoryRegistry.addToGroups(checkType, type, groupTypes);
|
||||
}
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register standard config types with the player registry as well (aiming
|
||||
* at per world configuration types).
|
||||
* <hr>
|
||||
* <ul>
|
||||
* <li>IConfig</li>
|
||||
* <li>ICheckConfig</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public RegisterInstance<T,A> registerConfigTypesPlayer() {
|
||||
registerConfigTypesPlayer = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register standard config types with the player registry as well (aiming
|
||||
* at per world configuration types).
|
||||
* <hr>
|
||||
* <ul>
|
||||
* <li>IConfig</li>
|
||||
* <li>ICheckConfig</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param checkType
|
||||
* @param withDescendantCheckTypes
|
||||
* @return
|
||||
*/
|
||||
public RegisterInstance<T,A> registerConfigTypesPlayer(
|
||||
final CheckType checkType,
|
||||
final boolean withDescendantCheckTypes) {
|
||||
registerConfigTypesPlayer();
|
||||
final Collection<CheckType> checkTypes = withDescendantCheckTypes ? CheckTypeUtil.getWithDescendants(checkType)
|
||||
: Arrays.asList(checkType);
|
||||
if (IConfig.class.isAssignableFrom(type)) {
|
||||
genericConfigItems.add(new IDoRegisterWithRegistry() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void doRegister(IRichFactoryRegistry<?> factoryRegistry) {
|
||||
factoryRegistry.addToGroups(checkTypes,
|
||||
(Class<? extends IConfig>) type,
|
||||
IConfig.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (ICheckConfig.class.isAssignableFrom(type)) {
|
||||
genericConfigItems.add(new IDoRegisterWithRegistry() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void doRegister(IRichFactoryRegistry<?> factoryRegistry) {
|
||||
factoryRegistry.addToGroups(checkTypes,
|
||||
(Class<? extends ICheckConfig>) type,
|
||||
ICheckConfig.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register standard data types with the player registry as well (aiming at
|
||||
* per world data).
|
||||
* <hr>
|
||||
* <ul>
|
||||
* <li>IData</li>
|
||||
* <li>ICheckData</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public RegisterInstance<T,A> registerDataTypesPlayer() {
|
||||
registerDataTypesPlayer = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register standard data types with the player registry as well (aiming at
|
||||
* per world data).
|
||||
* <hr>
|
||||
* <ul>
|
||||
* <li>IData</li>
|
||||
* <li>ICheckData</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param checkType
|
||||
* @param withDescendantCheckTypes
|
||||
* @return
|
||||
*/
|
||||
public RegisterInstance<T,A> registerDataTypesPlayer(
|
||||
final CheckType checkType,
|
||||
final boolean withDescendantCheckTypes) {
|
||||
registerDataTypesPlayer();
|
||||
final Collection<CheckType> checkTypes = withDescendantCheckTypes ? CheckTypeUtil.getWithDescendants(checkType)
|
||||
: Arrays.asList(checkType);
|
||||
if (IData.class.isAssignableFrom(type)) {
|
||||
genericConfigItems.add(new IDoRegisterWithRegistry() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void doRegister(IRichFactoryRegistry<?> factoryRegistry) {
|
||||
factoryRegistry.addToGroups(checkTypes,
|
||||
(Class<? extends IData>) type,
|
||||
IData.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (ICheckData.class.isAssignableFrom(type)) {
|
||||
genericConfigItems.add(new IDoRegisterWithRegistry() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void doRegister(IRichFactoryRegistry<?> factoryRegistry) {
|
||||
factoryRegistry.addToGroups(checkTypes,
|
||||
(Class<? extends ICheckData>) type,
|
||||
ICheckData.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register for sub check removal.
|
||||
*
|
||||
* @param checkType
|
||||
* @param withDescendantCheckTypes
|
||||
* @return
|
||||
*/
|
||||
public RegisterInstance<T,A> removeSubCheckData(
|
||||
final CheckType checkType,
|
||||
final boolean withDescendantCheckTypes) {
|
||||
if (!IDataOnRemoveSubCheckData.class.isAssignableFrom(type)) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
final Collection<CheckType> checkTypes = withDescendantCheckTypes ? CheckTypeUtil.getWithDescendants(checkType)
|
||||
: Arrays.asList(checkType);
|
||||
items.add(new IDoRegister() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void doRegister() {
|
||||
factoryRegistry.addToGroups(checkTypes,
|
||||
(Class<? extends IDataOnRemoveSubCheckData>) type,
|
||||
IDataOnRemoveSubCheckData.class);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// Other functionality.
|
||||
//////////////////////////////
|
||||
|
||||
public RegistrationContext registrationContext() {
|
||||
return registrationContext;
|
||||
}
|
||||
|
||||
public RegistrationContext context() {
|
||||
return registrationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRegister() {
|
||||
if (factory != null) {
|
||||
factoryRegistry.registerFactory(type, factory);
|
||||
}
|
||||
for (final IDoRegister item : items) {
|
||||
item.doRegister();
|
||||
}
|
||||
for (final IDoRegisterWithRegistry item : genericDataItems) {
|
||||
item.doRegister(factoryRegistry);
|
||||
}
|
||||
final IPlayerDataManager pdMan = NCPAPIProvider.getNoCheatPlusAPI().getPlayerDataManager();
|
||||
if (registerConfigTypesPlayer) {
|
||||
registerConfigTypesPlayer(pdMan);
|
||||
}
|
||||
if (registerDataTypesPlayer) {
|
||||
registerDataTypesPlayer(pdMan);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void registerConfigTypesPlayer(final IPlayerDataManager pdMan) {
|
||||
if (IConfig.class.isAssignableFrom(type)) {
|
||||
pdMan.addToGroups((Class<? extends IConfig>) type, IConfig.class);
|
||||
}
|
||||
if (ICheckConfig.class.isAssignableFrom(type)) {
|
||||
pdMan.addToGroups((Class<? extends ICheckConfig>) type, ICheckConfig.class);
|
||||
}
|
||||
for (final IDoRegisterWithRegistry item : genericConfigItems) {
|
||||
item.doRegister(pdMan);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void registerDataTypesPlayer(final IPlayerDataManager pdMan) {
|
||||
if (IData.class.isAssignableFrom(type)) {
|
||||
pdMan.addToGroups((Class<? extends IData>) type, IData.class);
|
||||
}
|
||||
if (ICheckData.class.isAssignableFrom(type)) {
|
||||
pdMan.addToGroups((Class<? extends ICheckData>) type, ICheckData.class);
|
||||
}
|
||||
for (final IDoRegisterWithRegistry item : genericDataItems) {
|
||||
item.doRegister(pdMan);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package fr.neatmonster.nocheatplus.components.registry.setup.instance;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.RegistrationContext;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerFactoryArgument;
|
||||
|
||||
public class RegisterInstancePlayer<T> extends RegisterInstance<T, PlayerFactoryArgument> {
|
||||
|
||||
public RegisterInstancePlayer(RegistrationContext registrationContext,
|
||||
Class<T> type) {
|
||||
super(registrationContext, type,
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getPlayerDataManager());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package fr.neatmonster.nocheatplus.components.registry.setup.instance;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.RegistrationContext;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldFactoryArgument;
|
||||
|
||||
public class RegisterInstanceWorld<T> extends RegisterInstance<T, WorldFactoryArgument> {
|
||||
|
||||
public RegisterInstanceWorld(RegistrationContext registrationContext,
|
||||
Class<T> type) {
|
||||
super(registrationContext, type,
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager());
|
||||
}
|
||||
|
||||
}
|
|
@ -14,21 +14,21 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.event.mini;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.PluginDisableEvent;
|
||||
import org.bukkit.plugin.EventExecutor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.ComponentWithName;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.PluginDisableEvent;
|
||||
import org.bukkit.plugin.EventExecutor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.ComponentWithName;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder;
|
||||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
||||
|
||||
|
@ -68,8 +68,8 @@ public class EventRegistryBukkit extends MultiListenerRegistry<Event, EventPrior
|
|||
*/
|
||||
protected static class CancellableNodeBukkit<E> extends MiniListenerNode<E, EventPriority> {
|
||||
|
||||
public CancellableNodeBukkit(EventPriority basePriority) {
|
||||
super(basePriority);
|
||||
public CancellableNodeBukkit(Class<E> baseType, EventPriority basePriority) {
|
||||
super(baseType, basePriority);
|
||||
}
|
||||
|
||||
// TODO: Future java: E extends Cancellable ?
|
||||
|
@ -95,9 +95,9 @@ public class EventRegistryBukkit extends MultiListenerRegistry<Event, EventPrior
|
|||
if (Cancellable.class.isAssignableFrom(eventClass)) {
|
||||
// TODO: Check if order is right (eventClass extends Cancellable).
|
||||
// TODO: Future java (see above) ?
|
||||
return new CancellableNodeBukkit<E>(basePriority);
|
||||
return new CancellableNodeBukkit<E>(eventClass, basePriority);
|
||||
} else {
|
||||
return new MiniListenerNode<E, EventPriority>(basePriority);
|
||||
return new MiniListenerNode<E, EventPriority>(eventClass, basePriority);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,16 +14,19 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.event.mini;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.IGetRegistrationOrder;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.AbstractRegistrationOrderSort;
|
||||
import fr.neatmonster.nocheatplus.logging.StaticLog;
|
||||
import fr.neatmonster.nocheatplus.logging.Streams;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.ComponentWithName;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.IGetRegistrationOrder;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.AbstractRegistrationOrderSort;
|
||||
import fr.neatmonster.nocheatplus.logging.StaticLog;
|
||||
import fr.neatmonster.nocheatplus.logging.Streams;
|
||||
import fr.neatmonster.nocheatplus.utilities.StringUtil;
|
||||
|
||||
/**
|
||||
|
@ -78,13 +81,15 @@ public class MiniListenerNode<E, P> {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ListenerEntry<E>[] sortedListeners = new ListenerEntry[0];
|
||||
|
||||
|
||||
protected final Class<E> baseType;
|
||||
/**
|
||||
* Stored for the case of exceptions.
|
||||
*/
|
||||
protected final P basePriority;
|
||||
|
||||
public MiniListenerNode(P basePriority) {
|
||||
public MiniListenerNode(Class<E> baseType, P basePriority) {
|
||||
this.baseType = baseType;
|
||||
this.basePriority = basePriority;
|
||||
}
|
||||
|
||||
|
@ -159,12 +164,37 @@ public class MiniListenerNode<E, P> {
|
|||
}
|
||||
}
|
||||
|
||||
private void logListenerException(final ListenerEntry<E> entry, final int index, final int length, final E event, final Throwable t) {
|
||||
// Log long part once, to keep spam slightly down.
|
||||
StaticLog.logOnce(Streams.STATUS, Level.SEVERE,
|
||||
"Listener exception: event=" + event.getClass().getName() + " priority=" + this.basePriority + " index=" + index + " n=" + length
|
||||
// TODO: Add id information to compare to registry log (later).
|
||||
, StringUtil.throwableToString(t));
|
||||
private void logListenerException(final ListenerEntry<E> entry,
|
||||
final int index, final int length,
|
||||
final E event, final Throwable t) {
|
||||
// Log long part once, to keep spam slightly down.
|
||||
// TODO: Add more info (ORDER with tags, class/wrapped class).
|
||||
final StringBuilder builder = new StringBuilder(1024);
|
||||
builder.append(" Details:");
|
||||
builder.append(" listenerType=" + entry.listener.getClass().getName());
|
||||
builder.append(" listenerOrder=" + entry.order);
|
||||
builder.append(" listenerIndex=" + index + "/" + length);
|
||||
if (entry.listener instanceof ComponentWithName) {
|
||||
builder.append(" listenerName=");
|
||||
builder.append(((ComponentWithName) entry.listener).getComponentName());
|
||||
}
|
||||
builder.append("\n exception:\n");
|
||||
builder.append(StringUtil.throwableToString(t));
|
||||
final Set<Throwable> done = new HashSet<Throwable>();
|
||||
done.add(t);
|
||||
Throwable cause = t.getCause();
|
||||
while (cause != null && !done.contains(cause)) {
|
||||
done.add(cause);
|
||||
builder.append("\n caused by:\n");
|
||||
builder.append(StringUtil.throwableToString(cause));
|
||||
cause = t.getCause();
|
||||
}
|
||||
// TODO: Add id information to compare to registry log (later).
|
||||
StaticLog.logOnce(Streams.STATUS, Level.SEVERE,
|
||||
"Listener exception: baseType=" + baseType.getName()
|
||||
+ " basePriority=" + this.basePriority
|
||||
+ " eventType=" + event.getClass().getName(),
|
||||
builder.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ public abstract class MiniListenerRegistry<EB, P> {
|
|||
protected NodeFactory<EB, P> nodeFactory = new NodeFactory<EB, P>() {
|
||||
@Override
|
||||
public <E extends EB> MiniListenerNode<E, P> newNode(Class<E> eventClass, P basePriority) {
|
||||
return new MiniListenerNode<E, P>(basePriority);
|
||||
return new MiniListenerNode<E, P>(eventClass, basePriority);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,17 +14,21 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.event.mini;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterEventsWithOrder;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterMethodWithOrder;
|
||||
import fr.neatmonster.nocheatplus.logging.Streams;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.ComponentWithName;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterEventsWithOrder;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterMethodWithOrder;
|
||||
import fr.neatmonster.nocheatplus.logging.StaticLog;
|
||||
import fr.neatmonster.nocheatplus.logging.Streams;
|
||||
import fr.neatmonster.nocheatplus.utilities.StringUtil;
|
||||
|
||||
/**
|
||||
* Support for registering multiple event-handler methods at once.<br>
|
||||
|
@ -52,7 +56,74 @@ import fr.neatmonster.nocheatplus.logging.Streams;
|
|||
* @param <P>
|
||||
* Priority class, e.g. EventPriority for Bukkit.
|
||||
*/
|
||||
public abstract class MultiListenerRegistry<EB, P> extends MiniListenerRegistry<EB, P> {
|
||||
public abstract class MultiListenerRegistry<EB, P> extends MiniListenerRegistry<EB, P> {
|
||||
|
||||
protected class AutoListener<E> implements MiniListenerWithOrder<E>, ComponentWithName {
|
||||
|
||||
private final Class<E> eventClass;
|
||||
private final Object listener;
|
||||
private final Method method;
|
||||
private final RegistrationOrder order;
|
||||
private final P basePriority;
|
||||
|
||||
private AutoListener(final Class<E> eventClass,
|
||||
final Object listener, final Method method,
|
||||
final RegistrationOrder order, final P basePriority) {
|
||||
this.eventClass = eventClass;
|
||||
this.listener = listener;
|
||||
this.method = method;
|
||||
this.order = order;
|
||||
this.basePriority = basePriority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(final E event) {
|
||||
try {
|
||||
method.invoke(listener, event);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
onException(event, e);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
onException(event, e);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
onException(event, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void onException(final E event, final Throwable t) {
|
||||
final StringBuilder builder = new StringBuilder(1024);
|
||||
builder.append("Exception:\n");
|
||||
builder.append(StringUtil.throwableToString(t));
|
||||
Throwable cause = t.getCause();
|
||||
while (cause != null) {
|
||||
builder.append("caused by:\n");
|
||||
builder.append(StringUtil.throwableToString(t.getCause()));
|
||||
cause = cause.getCause();
|
||||
}
|
||||
StaticLog.logOnce(Level.SEVERE,
|
||||
"Exception with " + getComponentName() + ", processing " + event.getClass().getName() + ": " + t.getClass().getSimpleName(),
|
||||
builder.toString());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RegistrationOrder getRegistrationOrder() {
|
||||
/*
|
||||
* Return the given instance of RegistrationOrder, assuming
|
||||
* it'll be copied upon registration. Typically the registry
|
||||
* can't and shouldn't distinguish if this comes from an
|
||||
* external source anyway.
|
||||
*/
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentName() {
|
||||
return "AutoListener(" + listener.getClass().getName() +"." + method.getName() + "/" + eventClass.getName() + "/" + basePriority + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -75,7 +146,7 @@ public abstract class MultiListenerRegistry<EB, P> extends MiniListenerRegistry<
|
|||
if (order == null) {
|
||||
order = defaultOrder;
|
||||
}
|
||||
MiniListener<E> miniListener = getMiniListener(listener, method, order);
|
||||
MiniListener<E> miniListener = getMiniListener(listener, method, order, basePriority);
|
||||
if (listener == null) {
|
||||
// TODO: Throw rather.
|
||||
return null;
|
||||
|
@ -91,36 +162,11 @@ public abstract class MultiListenerRegistry<EB, P> extends MiniListenerRegistry<
|
|||
* @param method
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <E extends EB> MiniListener<E> getMiniListener(final Object listener,
|
||||
final Method method, final RegistrationOrder order) {
|
||||
@SuppressWarnings({ "unchecked", "unused" })
|
||||
Class<E> eventClass = (Class<E>) method.getParameterTypes()[0];
|
||||
MiniListener<E> miniListener = new MiniListenerWithOrder<E>() {
|
||||
@Override
|
||||
public void onEvent(E event) {
|
||||
try {
|
||||
method.invoke(listener, event);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistrationOrder getRegistrationOrder() {
|
||||
/*
|
||||
* Return the given instance of RegistrationOrder, assuming
|
||||
* it'll be copied upon registration. Typically the registry
|
||||
* can't and shouldn't distinguish if this comes from an
|
||||
* external source anyway.
|
||||
*/
|
||||
return order;
|
||||
}
|
||||
};
|
||||
return miniListener;
|
||||
final Method method, final RegistrationOrder order, final P basePriority) {
|
||||
return new AutoListener<E>((Class<E>) method.getParameterTypes()[0],
|
||||
listener, method, order, basePriority);
|
||||
}
|
||||
|
||||
protected boolean check_and_prepare_method(final Method method) {
|
||||
|
|
|
@ -14,13 +14,12 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.players;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
|
||||
|
||||
|
@ -40,26 +39,7 @@ public class DataManager {
|
|||
*/
|
||||
// TODO: Should/can some data structures share the same lock?
|
||||
|
||||
private static PlayerDataManager instance = null;
|
||||
|
||||
/**
|
||||
* Clear all cached CheckConfig instances.<br>
|
||||
* This does not cleanup ConfigManager, i.e. stored yml-versions.
|
||||
*/
|
||||
public static void clearConfigs() {
|
||||
// TODO: general DataManager thing, otherwise it's now a WorldDataManager thing.
|
||||
final Set<CheckConfigFactory> factories = new LinkedHashSet<CheckConfigFactory>();
|
||||
for (final CheckType checkType : CheckType.values()) {
|
||||
final CheckConfigFactory factory = checkType.getConfigFactory();
|
||||
if (factory != null) {
|
||||
factories.add(factory);
|
||||
}
|
||||
}
|
||||
for (final CheckConfigFactory factory : factories) {
|
||||
factory.removeAllConfigs();
|
||||
}
|
||||
}
|
||||
|
||||
static PlayerDataManager instance = null;
|
||||
|
||||
/**
|
||||
* Get the exact player name, stored internally.
|
||||
|
@ -108,11 +88,12 @@ public class DataManager {
|
|||
|
||||
/**
|
||||
* Remove data and history of all players for the given check type and sub
|
||||
* checks.
|
||||
* checks. Also removes check related data from the world manager.
|
||||
*
|
||||
* @param checkType
|
||||
*/
|
||||
public static void clearData(final CheckType checkType) {
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().clearData(checkType);
|
||||
instance.clearData(checkType);
|
||||
}
|
||||
|
||||
|
@ -147,7 +128,7 @@ public class DataManager {
|
|||
* Exact player name.
|
||||
* @param checkType
|
||||
* Check type to remove data for, null is regarded as ALL.
|
||||
* @return If any data was present.
|
||||
* @return If any data was present (not strict).
|
||||
*/
|
||||
public static boolean removeData(final String playerName, CheckType checkType) {
|
||||
return instance.removeData(playerName, checkType);
|
||||
|
@ -273,4 +254,9 @@ public class DataManager {
|
|||
return instance.getPlayerData(player).getGenericInstance(registeredFor);
|
||||
}
|
||||
|
||||
static <T> T getFromFactory(final Class<T> registeredFor,
|
||||
final PlayerFactoryArgument arg) {
|
||||
return instance.getNewInstance(registeredFor, arg);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.players;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -22,6 +23,7 @@ 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.IDataOnRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.checktype.IBaseDataAccess;
|
||||
import fr.neatmonster.nocheatplus.components.registry.IGetGenericInstance;
|
||||
import fr.neatmonster.nocheatplus.hooks.ExemptionContext;
|
||||
|
@ -269,6 +271,23 @@ public interface IPlayerData extends IData, IBaseDataAccess, IGetGenericInstance
|
|||
*/
|
||||
public <T> void removeGenericInstance(Class<T> registeredFor);
|
||||
|
||||
/**
|
||||
* Remove all generic instances from cache, which are contained in the given
|
||||
* collection.
|
||||
*
|
||||
* @param types
|
||||
*/
|
||||
public void removeAllGenericInstances(Collection<Class<?>> types);
|
||||
|
||||
/**
|
||||
* Call dataOnRemoveSubCheckData(...).
|
||||
*
|
||||
* @param subCheckRemoval
|
||||
*/
|
||||
public void removeSubCheckData(
|
||||
Collection<Class<? extends IDataOnRemoveSubCheckData>> subCheckRemoval,
|
||||
Collection<CheckType> checkTypes);
|
||||
|
||||
/**
|
||||
* Check if notifications are turned off, this does not bypass permission
|
||||
* checks.
|
||||
|
|
|
@ -20,18 +20,44 @@ import org.bukkit.entity.Player;
|
|||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.components.registry.ComponentRegistry;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IRichFactoryRegistry;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.IRemoveData;
|
||||
|
||||
/**
|
||||
* Player data specific operations.
|
||||
* <hr>
|
||||
* <hr/>
|
||||
* ComponentRegistry:
|
||||
* <li>Supported: IRemoveData</li>
|
||||
* <hr/>
|
||||
* <b>Preset groups and automatic registration.</b><br/>
|
||||
* All of the types mentioned in the lists below are preset for grouping. <br/>
|
||||
* However only those item types for which a factory gets registered here will
|
||||
* be automatically put into existing groups. External types like configuration
|
||||
* instances fetched from IWorldData need to be registered explicitly. <br/>
|
||||
* <br/>
|
||||
* Automatic data type grouping with call support (return value controls removal
|
||||
* of the entire data object):
|
||||
* <ul>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IDataOnReload}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IDataOnWorldUnload}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IDataOnJoin}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IDataOnLeave}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IDataOnWorldChange}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData}</li></li>
|
||||
* </ul>
|
||||
* <br/>
|
||||
* Automatic data type grouping for direct removal (API/reload/commands):
|
||||
* <ul>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IData}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.config.IConfig}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.ICheckData}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.config.ICheckConfig}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IPlayerDataManager extends ComponentRegistry<IRemoveData> {
|
||||
public interface IPlayerDataManager extends ComponentRegistry<IRemoveData>, IRichFactoryRegistry<PlayerFactoryArgument> {
|
||||
|
||||
// TODO: Complete (...)
|
||||
|
||||
|
@ -139,6 +165,12 @@ public interface IPlayerDataManager extends ComponentRegistry<IRemoveData> {
|
|||
*
|
||||
* @param checkType
|
||||
*/
|
||||
public void clearData(final CheckType checkType);
|
||||
public void clearData(CheckType checkType);
|
||||
|
||||
/**
|
||||
* Convenience method to remove cached types that implement IConfig for all
|
||||
* players. Types need to be registered (player data factory or explicitly).
|
||||
*/
|
||||
public void removeCachedConfigs();
|
||||
|
||||
}
|
||||
|
|
|
@ -230,7 +230,12 @@ public class PlayerCheckTypeTree extends CheckTypeTree<PlayerCheckTypeTreeNode>{
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
void updateDebug(ConfigFile rawConfiguration) {
|
||||
configFlagUpdate(rawConfiguration, true, accessDebug);
|
||||
update(rawConfiguration, true, accessDebug);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void updateDebug() {
|
||||
update(true, accessDebug);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,10 +263,10 @@ public class PlayerCheckTypeTree extends CheckTypeTree<PlayerCheckTypeTreeNode>{
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void overrideDebug(final ConfigFile rawConfiguration,
|
||||
void overrideDebug(
|
||||
final CheckType checkType, final AlmostBoolean active,
|
||||
final OverrideType overrideType, final boolean overrideChildren) {
|
||||
configFlagOverride(rawConfiguration, active, overrideType, overrideChildren, accessDebug);
|
||||
override(active, overrideType, overrideChildren, accessDebug);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.Arrays;
|
|||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
@ -34,6 +35,13 @@ 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.components.data.IDataOnJoin;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnLeave;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnReload;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnWorldChange;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnWorldUnload;
|
||||
import fr.neatmonster.nocheatplus.hooks.ExemptionContext;
|
||||
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
|
||||
import fr.neatmonster.nocheatplus.permissions.PermissionInfo;
|
||||
|
@ -45,6 +53,7 @@ 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.utilities.ds.map.InstanceMapLOW;
|
||||
import fr.neatmonster.nocheatplus.worlds.IWorldData;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldDataManager;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldIdentifier;
|
||||
|
@ -85,7 +94,7 @@ import fr.neatmonster.nocheatplus.worlds.WorldIdentifier;
|
|||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
||||
public class PlayerData implements IPlayerData {
|
||||
|
||||
// TODO: IPlayerData for the more official API.
|
||||
|
||||
|
@ -153,6 +162,8 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
|
||||
/** Permission cache. */
|
||||
private final HashMapLOW<Integer, PermissionNode> permissions = new HashMapLOW<Integer, PermissionNode>(lock, 35);
|
||||
// TODO: a per entry typed variant (key - value relation)?
|
||||
private final InstanceMapLOW dataCache = new InstanceMapLOW(lock, 24);
|
||||
|
||||
private boolean requestUpdateInventory = false;
|
||||
private boolean requestPlayerSetBack = false;
|
||||
|
@ -370,8 +381,8 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTimeRanBackwards() {
|
||||
public void handleTimeRanBackwards(final Collection<Class<? extends IData>> dataTypes) {
|
||||
// Permissions.
|
||||
final Iterator<Entry<Integer, PermissionNode>> it = permissions.iterator();
|
||||
final long timeNow = System.currentTimeMillis();
|
||||
while (it.hasNext()) {
|
||||
|
@ -380,14 +391,20 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
case INTERVAL:
|
||||
node.invalidate();
|
||||
break;
|
||||
case ONCE:
|
||||
node.setState(node.getLastState(), timeNow);
|
||||
break;
|
||||
default:
|
||||
// Ignore.
|
||||
if (node.getLastFetch() > timeNow) {
|
||||
node.setState(node.getLastState(), timeNow);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: Register explicitly or not? (+ auto register?)...
|
||||
for (final Class<? extends IData> type : dataTypes) {
|
||||
final IData obj = dataCache.get(type);
|
||||
if (obj != null && obj instanceof ICanHandleTimeRunningBackwards) {
|
||||
((ICanHandleTimeRunningBackwards) obj).handleTimeRanBackwards();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void requestPermissionUpdatePrimaryThread(final RegisteredPermission registeredPermission) {
|
||||
|
@ -421,7 +438,16 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
registerFrequentPlayerTaskAsynchronous();
|
||||
}
|
||||
|
||||
void onPlayerLeave(final long timeNow) {
|
||||
void onPlayerLeave(final Player player, final long timeNow,
|
||||
Collection<Class<? extends IDataOnLeave>> types) {
|
||||
// (Might collect to be removed types first.)
|
||||
for (final Class<? extends IDataOnLeave> type : types) {
|
||||
final IDataOnLeave instance = dataCache.get(type);
|
||||
if (instance != null && instance.dataOnLeave(player, this)) {
|
||||
dataCache.remove(type);
|
||||
}
|
||||
}
|
||||
// (Somewhat reversed order of invalidation.)
|
||||
invalidateOffline();
|
||||
}
|
||||
|
||||
|
@ -430,12 +456,20 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
*
|
||||
* @param world
|
||||
* @param timeNow
|
||||
* @param types
|
||||
*/
|
||||
void onPlayerJoin(final World world, final long timeNow,
|
||||
final WorldDataManager worldDataManager) {
|
||||
void onPlayerJoin(final Player player, final World world,
|
||||
final long timeNow, final WorldDataManager worldDataManager,
|
||||
final Collection<Class<? extends IDataOnJoin>> types) {
|
||||
// Only update world if the data hasn't just been created.
|
||||
updateCurrentWorld(world, worldDataManager);
|
||||
invalidateOffline();
|
||||
for (final Class<? extends IDataOnJoin> type : types) {
|
||||
final IDataOnJoin instance = dataCache.get(type);
|
||||
if (instance != null && instance.dataOnJoin(player, this)) {
|
||||
dataCache.remove(type);
|
||||
}
|
||||
}
|
||||
requestLazyPermissionUpdate(permissionRegistry.getPreferKeepUpdatedOffline());
|
||||
lastJoinTime = timeNow;
|
||||
}
|
||||
|
@ -481,9 +515,12 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
*
|
||||
* @param oldWorld
|
||||
* @param newWorld
|
||||
* @param types
|
||||
*/
|
||||
void onPlayerChangedWorld(final World oldWorld, final World newWorld,
|
||||
final WorldDataManager worldDataManager) {
|
||||
void onPlayerChangedWorld(final Player player,
|
||||
final World oldWorld, final World newWorld,
|
||||
final WorldDataManager worldDataManager,
|
||||
final Collection<Class<? extends IDataOnWorldChange>> types) {
|
||||
updateCurrentWorld(newWorld, worldDataManager);
|
||||
// TODO: Double-invalidation (previous policy and target world policy)
|
||||
final Iterator<Entry<Integer, PermissionNode>> it = permissions.iterator();
|
||||
|
@ -496,18 +533,10 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
}
|
||||
}
|
||||
requestLazyPermissionUpdate(permissionRegistry.getPreferKeepUpdatedWorld());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called with adjusting to the configuration (enable / config reload).
|
||||
* @param changedPermissions
|
||||
*/
|
||||
public void adjustSettings(final Set<RegisteredPermission> changedPermissions) {
|
||||
final Iterator<RegisteredPermission> it = changedPermissions.iterator();
|
||||
while (it.hasNext()) {
|
||||
final PermissionNode node = permissions.get(it.next().getId());
|
||||
if (node != null) {
|
||||
node.invalidate();
|
||||
for (final Class<? extends IDataOnWorldChange> type : types) {
|
||||
final IDataOnWorldChange instance = dataCache.get(type);
|
||||
if (instance != null && instance.dataOnWorldChange(player, this, oldWorld, newWorld)) {
|
||||
dataCache.remove(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -588,6 +617,7 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
permissions.clear(); // Might keep login-related permissions. Implement a 'retain-xy' or 'essential' flag?
|
||||
updatePermissions.clearPrimaryThread();
|
||||
updatePermissionsLazy.clearPrimaryThread();
|
||||
dataCache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -733,7 +763,6 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -818,19 +847,112 @@ public class PlayerData implements IPlayerData, ICanHandleTimeRunningBackwards {
|
|||
&& (frequentPlayerTaskShouldBeScheduled || isFrequentPlayerTaskScheduled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a data/config instance (1.local cache, 2. player related factory, 3.
|
||||
* world registry).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T getGenericInstance(Class<T> registeredFor) {
|
||||
// TODO: 1. Check for cache (local).
|
||||
// TODO: 2. Check for registered factory (local)
|
||||
public <T> T getGenericInstance(final Class<T> registeredFor) {
|
||||
// 1. Check for cache (local).
|
||||
final Object res = dataCache.get(registeredFor);
|
||||
if (res == null) {
|
||||
/*
|
||||
* TODO: Consider storing null and check containsKey(registeredFor)
|
||||
* here. On the other hand it's not intended to query non existent
|
||||
* data (just yet).
|
||||
*/
|
||||
return cacheMissGenericInstance(registeredFor);
|
||||
}
|
||||
else {
|
||||
return (T) res;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T cacheMissGenericInstance(final Class<T> registeredFor) {
|
||||
// 2. Check for registered factory (local)
|
||||
// TODO: Might store PlayerDataManager here.
|
||||
T res = DataManager.getFromFactory(registeredFor,
|
||||
new PlayerFactoryArgument(this, getCurrentWorldDataSafe()));
|
||||
if (res != null) {
|
||||
return putDataCache(registeredFor, res);
|
||||
}
|
||||
// 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);
|
||||
res = getCurrentWorldDataSafe().getGenericInstance(registeredFor);
|
||||
return res == null ? null : putDataCache(registeredFor, res);
|
||||
}
|
||||
|
||||
private <T> T putDataCache(final Class<T> registeredFor, final T instance) {
|
||||
final T previousInstance = (T) dataCache.putIfAbsent(registeredFor, instance); // Under lock.
|
||||
return previousInstance == null ? instance : previousInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove from cache.
|
||||
*/
|
||||
@Override
|
||||
public <T> void removeGenericInstance(final Class<T> type) {
|
||||
dataCache.remove(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void removeGenericInstance(Class<T> registeredFor) {
|
||||
// TODO: implement
|
||||
public void removeAllGenericInstances(final Collection<Class<?>> types) {
|
||||
if (dataCache.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
dataCache.remove(types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSubCheckData(
|
||||
final Collection<Class<? extends IDataOnRemoveSubCheckData>> types,
|
||||
final Collection<CheckType> checkTypes
|
||||
) {
|
||||
final Collection<Class<?>> removeTypes = new LinkedList<Class<?>>();
|
||||
for (final Class<? extends IDataOnRemoveSubCheckData> type : types) {
|
||||
final IDataOnRemoveSubCheckData impl = (IDataOnRemoveSubCheckData) dataCache.get(type);
|
||||
if (impl != null) {
|
||||
if (impl.dataOnRemoveSubCheckData(checkTypes)) {
|
||||
removeTypes.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!removeTypes.isEmpty()) {
|
||||
dataCache.remove(removeTypes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called with adjusting to the configuration (enable / config reload).
|
||||
* @param changedPermissions
|
||||
*/
|
||||
public void adjustSettings(final Set<RegisteredPermission> changedPermissions) {
|
||||
final Iterator<RegisteredPermission> it = changedPermissions.iterator();
|
||||
while (it.hasNext()) {
|
||||
final PermissionNode node = permissions.get(it.next().getId());
|
||||
if (node != null) {
|
||||
node.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onWorldUnload(final World world,
|
||||
final Collection<Class<? extends IDataOnWorldUnload>> types) {
|
||||
for (final Class<? extends IDataOnWorldUnload> type : types) {
|
||||
final IDataOnWorldUnload instance = dataCache.get(type);
|
||||
if (instance != null && instance.dataOnWorldUnload(world, this)) {
|
||||
dataCache.remove(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onReload(final Collection<Class<? extends IDataOnReload>> types) {
|
||||
for (final Class<? extends IDataOnReload> type : types) {
|
||||
final IDataOnReload instance = dataCache.get(type);
|
||||
if (instance != null && instance.dataOnReload(this)) {
|
||||
dataCache.remove(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
package fr.neatmonster.nocheatplus.players;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
|
@ -37,21 +37,31 @@ 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 org.bukkit.event.world.WorldUnloadEvent;
|
||||
|
||||
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.config.ICheckConfig;
|
||||
import fr.neatmonster.nocheatplus.components.config.IConfig;
|
||||
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.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnJoin;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnLeave;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnReload;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnWorldChange;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnWorldUnload;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.RichFactoryRegistry;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.RichFactoryRegistry.CheckRemovalSpec;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.ComponentWithName;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.ConsistencyChecker;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.IDisableListener;
|
||||
|
@ -90,6 +100,7 @@ import fr.neatmonster.nocheatplus.worlds.WorldDataManager;
|
|||
*
|
||||
*/
|
||||
// TODO: RegisterWithOrder still relevant ?
|
||||
// TODO: Tag utility (common stuff).
|
||||
@RegisterWithOrder(tag = "system.nocheatplus.datamanager", beforeTag = "(^feature.*)", basePriority = "-80")
|
||||
public class PlayerDataManager implements IPlayerDataManager, ComponentWithName, INeedConfig, ConsistencyChecker, IDisableListener {
|
||||
|
||||
|
@ -163,14 +174,7 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
// TODO: Consider same lock for some registry parts (deadlocking possibilities with exposed API).
|
||||
private final FactoryOneRegistry<PlayerFactoryArgument> factoryRegistry = new FactoryOneRegistry<PlayerFactoryArgument>(
|
||||
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 RichFactoryRegistry<PlayerFactoryArgument> factoryRegistry = new RichFactoryRegistry<PlayerFactoryArgument>(lock);
|
||||
private final TickListener tickListener = new TickListener() {
|
||||
|
||||
private int delayRareTasks = 0;
|
||||
|
@ -198,16 +202,19 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
* nocheatplus.system.data.player...). (RegistryTags for other?).
|
||||
*/
|
||||
new MiniListener<PlayerQuitEvent>() {
|
||||
@Override
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
@RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = ".*")
|
||||
@Override
|
||||
public void onEvent(final PlayerQuitEvent event) {
|
||||
playerLeaves(event.getPlayer());
|
||||
}
|
||||
},
|
||||
new MiniListener<PlayerKickEvent>() {
|
||||
// TODO: ignoreCancelled !?
|
||||
// TODO: afterTag !?
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
@RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = ".*")
|
||||
@RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = "feature.*")
|
||||
@Override
|
||||
public void onEvent(final PlayerKickEvent event) {
|
||||
playerLeaves(event.getPlayer());
|
||||
}
|
||||
|
@ -215,23 +222,34 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
new MiniListener<PlayerJoinEvent>() {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", beforeTag = ".*")
|
||||
@Override
|
||||
public void onEvent(final PlayerJoinEvent event) {
|
||||
playerJoins(event);
|
||||
}
|
||||
},
|
||||
new MiniListener<PlayerChangedWorldEvent>() {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", afterTag = ".*")
|
||||
@RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", beforeTag = ".*")
|
||||
@Override
|
||||
public void onEvent(final PlayerChangedWorldEvent event) {
|
||||
playerChangedWorld(event);
|
||||
}
|
||||
},
|
||||
new MiniListener<WorldUnloadEvent>() {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@RegisterMethodWithOrder(tag = "system.nocheatplus.datamanager", beforeTag = ".*")
|
||||
@Override
|
||||
public void onEvent(final WorldUnloadEvent event) {
|
||||
onWorldUnload(event);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the static instance reference.
|
||||
* @param worldDataManager
|
||||
*
|
||||
* @param worldDataManager
|
||||
* @param permissionRegistry
|
||||
*/
|
||||
public PlayerDataManager(final WorldDataManager worldDataManager, final PermissionRegistry permissionRegistry) {
|
||||
DataManager.instance = this; // TODO: Let NoCheatPlus do this, DataManager returns an ILockable.
|
||||
|
@ -248,8 +266,20 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
// Likely an older version without efficient mapping.
|
||||
playerMap = new PlayerMap(true);
|
||||
}
|
||||
this.permissionRegistry = permissionRegistry;
|
||||
this.permissionRegistry = permissionRegistry; // TODO: World specific.
|
||||
this.worldDataManager = worldDataManager;
|
||||
// (Call support.)
|
||||
factoryRegistry.createAutoGroup(IDataOnReload.class);
|
||||
factoryRegistry.createAutoGroup(IDataOnWorldUnload.class);
|
||||
factoryRegistry.createAutoGroup(IDataOnJoin.class);
|
||||
factoryRegistry.createAutoGroup(IDataOnLeave.class);
|
||||
factoryRegistry.createAutoGroup(IDataOnWorldChange.class);
|
||||
factoryRegistry.createAutoGroup(IDataOnRemoveSubCheckData.class);
|
||||
// Data/config removal.
|
||||
factoryRegistry.createAutoGroup(IData.class);
|
||||
factoryRegistry.createAutoGroup(IConfig.class);
|
||||
factoryRegistry.createAutoGroup(ICheckData.class);
|
||||
factoryRegistry.createAutoGroup(ICheckConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -262,18 +292,18 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
return;
|
||||
}
|
||||
final long now = System.currentTimeMillis();
|
||||
final Set<CheckDataFactory> factories = new LinkedHashSet<CheckDataFactory>();
|
||||
final Set<Entry<UUID, Long>> entries = lastLogout.entrySet();
|
||||
final Iterator<Entry<UUID, Long>> iterator = entries.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Entry<UUID, Long> entry = iterator.next();
|
||||
// TODO: Multi stage expiration.
|
||||
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);
|
||||
legacyPlayerDataExpirationRemovalByName(playerId, deleteData);
|
||||
bulkPlayerDataRemoval.add(playerId); // For bulk removal.
|
||||
iterator.remove();
|
||||
}
|
||||
|
@ -284,7 +314,7 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
}
|
||||
|
||||
private final void legacyPlayerDataExpirationRemovalByName(final UUID playerId,
|
||||
final Set<CheckDataFactory> factories, final boolean deleteData) {
|
||||
final boolean deleteData) {
|
||||
final String playerName = DataManager.getPlayerName(playerId);
|
||||
if (playerName == null) {
|
||||
// TODO: WARN
|
||||
|
@ -292,15 +322,9 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
}
|
||||
// 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);
|
||||
final PlayerData pData = playerData.get(playerId);
|
||||
if (pData != null) {
|
||||
pData.removeData(false); // TODO: staged ...
|
||||
}
|
||||
clearComponentData(CheckType.ALL, playerName);
|
||||
}
|
||||
|
@ -382,107 +406,70 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove the player data for a given player and a given check type.
|
||||
* CheckType.ALL and null will be interpreted as removing all data.<br>
|
||||
* Remove data instances from the cache for a given player and a given check
|
||||
* type. CheckType.ALL and null will be interpreted as removing all data.
|
||||
* <hr/>
|
||||
* Does not touch the execution history.
|
||||
* <hr/>
|
||||
*
|
||||
* @param playerName
|
||||
* Exact player name.
|
||||
* @param checkType
|
||||
* Check type to remove data for, null is regarded as ALL.
|
||||
* @return If any data was present.
|
||||
* @return If any data was present (not strict).
|
||||
*/
|
||||
public boolean removeData(final String playerName, CheckType checkType) {
|
||||
|
||||
final PlayerData pd = getPlayerData(playerName);
|
||||
PlayerData pData = getPlayerData(playerName);
|
||||
// TODO: Once working, use the most correct name from PlayerData.
|
||||
final UUID playerId = pd == null ? getUUID(playerName) : pd.getPlayerId();
|
||||
final UUID playerId = pData == null ? getUUID(playerName) : pData.getPlayerId();
|
||||
if (pData == null && playerId != null) {
|
||||
pData = playerData.get(playerId);
|
||||
}
|
||||
boolean somethingFound = pData != null || playerId != null;
|
||||
|
||||
// TODO: Method signature with UUID / (I)PlayerData ?
|
||||
|
||||
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;
|
||||
}
|
||||
/*
|
||||
* TODO: "System data" might not be wise to erase for online players.
|
||||
* ICheckData vs IData (...), except if registered for per check
|
||||
* type removal.
|
||||
*/
|
||||
somethingFound |= clearComponentData(checkType, playerName);
|
||||
|
||||
// Collect factories.
|
||||
final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
|
||||
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.";
|
||||
if (pData != null) {
|
||||
final CheckRemovalSpec removalSpec = new CheckRemovalSpec(checkType, true, this);
|
||||
final boolean hasComplete = !removalSpec.completeRemoval.isEmpty();
|
||||
final boolean hasSub = !removalSpec.subCheckRemoval.isEmpty();
|
||||
if (hasComplete || hasSub) {
|
||||
if (hasComplete) {
|
||||
pData.removeAllGenericInstances(removalSpec.completeRemoval);
|
||||
}
|
||||
res = true;
|
||||
}
|
||||
else {
|
||||
// Just remove.
|
||||
if (factory.removeData(playerName) == null) {
|
||||
// Is this even possible?
|
||||
if (debug) {
|
||||
debugText += "Could not remove data, despite present!";
|
||||
}
|
||||
if (hasSub) {
|
||||
pData.removeSubCheckData(removalSpec.subCheckRemoval, removalSpec.checkTypes);
|
||||
}
|
||||
else {
|
||||
if (debug) {
|
||||
debugText += "Removed the entire data object.";
|
||||
}
|
||||
res = true;
|
||||
// TODO: Remove the PlayerData instance, if necessary?
|
||||
}
|
||||
// TODO: Maintain a shouldBeOnline flag for fast skipping?
|
||||
if (checkType == CheckType.ALL) {
|
||||
// TODO: Fetch/use UUID early, and check validity of name.
|
||||
if (playerId != null) {
|
||||
bulkPlayerDataRemoval.add(playerId);
|
||||
}
|
||||
}
|
||||
if (debug) {
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, debugText);
|
||||
if (pData.isDebugActive(checkType)) {
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(
|
||||
Streams.TRACE_FILE,
|
||||
CheckUtils.getLogMessagePrefix(playerName, checkType)
|
||||
+ "Removed data.");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return somethingFound;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -534,7 +521,6 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
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();
|
||||
|
@ -545,6 +531,13 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
}
|
||||
}
|
||||
|
||||
public void onWorldUnload(final WorldUnloadEvent event) {
|
||||
final Collection<Class<? extends IDataOnWorldUnload>> types = factoryRegistry.getGroupedTypes(IDataOnWorldUnload.class);
|
||||
for (final Entry<UUID, PlayerData> entry : playerData.iterable()) {
|
||||
entry.getValue().onWorldUnload(event.getWorld(), types);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add mappings for player names variations.
|
||||
* @param player
|
||||
|
@ -575,7 +568,8 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
* TODO: Now we update the world already with getPlayerData, in case
|
||||
* it's just been created...
|
||||
*/
|
||||
pData.onPlayerJoin(player.getWorld(), timeNow, worldDataManager);
|
||||
final Collection<Class<? extends IDataOnJoin>> types = factoryRegistry.getGroupedTypes(IDataOnJoin.class);
|
||||
pData.onPlayerJoin(player, player.getWorld(), timeNow, worldDataManager, types);
|
||||
pData.getGenericInstance(CombinedData.class).lastJoinTime = timeNow;
|
||||
}
|
||||
|
||||
|
@ -589,17 +583,22 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
lastLogout.put(playerId, timeNow);
|
||||
final PlayerData pData = playerData.get(playerId);
|
||||
if (pData != null) {
|
||||
pData.onPlayerLeave(timeNow);
|
||||
final Collection<Class<? extends IDataOnLeave>> types = factoryRegistry.getGroupedTypes(IDataOnLeave.class);
|
||||
pData.onPlayerLeave(player, timeNow, types);
|
||||
pData.getGenericInstance(CombinedData.class).lastLogoutTime = timeNow;
|
||||
}
|
||||
else {
|
||||
// TODO: put lastLogoutTime to OfflinePlayerData ?
|
||||
}
|
||||
// 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);
|
||||
final Collection<Class<? extends IDataOnWorldChange>> types = factoryRegistry.getGroupedTypes(IDataOnWorldChange.class);
|
||||
pData.onPlayerChangedWorld(player, event.getFrom(), player.getWorld(),
|
||||
worldDataManager, types);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -633,6 +632,10 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
public void onReload() {
|
||||
// present.
|
||||
adjustSettings();
|
||||
final Collection<Class<? extends IDataOnReload>> types = factoryRegistry.getGroupedTypes(IDataOnReload.class);
|
||||
for (final Entry<UUID, PlayerData> entry : playerData.iterable()) {
|
||||
entry.getValue().onReload(types);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -748,25 +751,13 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
* which implement this.
|
||||
*/
|
||||
public void handleSystemTimeRanBackwards() {
|
||||
// TODO: WorldDataManager should have an extra method and be called before this.
|
||||
// Collect data factories and clear execution history.
|
||||
final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
|
||||
for (final CheckType type : CheckTypeUtil.getWithDescendants(CheckType.ALL)) {
|
||||
final Map<String, ExecutionHistory> 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) {
|
||||
|
@ -778,8 +769,10 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
}
|
||||
ViolationHistory.clear(CheckType.ALL);
|
||||
// PlayerData
|
||||
// TODO: Register explicitly (adding IDataOnTimeRanBackwards)?
|
||||
Collection<Class<? extends IData>> dataTypes = factoryRegistry.getGroupedTypes(IData.class);
|
||||
for (final Entry<UUID, PlayerData> entry : playerData.iterable()){
|
||||
entry.getValue().handleTimeRanBackwards();
|
||||
entry.getValue().handleTimeRanBackwards(dataTypes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -905,22 +898,22 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
|
||||
@Override
|
||||
public void clearData(final CheckType checkType) {
|
||||
// TODO: WorldDataManager: clear player related data there (registered in PlayerDataManager!?).
|
||||
final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
|
||||
for (final CheckType type : CheckTypeUtil.getWithDescendants(checkType)) {
|
||||
final Map<String, ExecutionHistory> map = executionHistories.get(type);
|
||||
if (map != null) {
|
||||
map.clear();
|
||||
}
|
||||
final CheckDataFactory factory = type.getDataFactory();
|
||||
if (factory != null) {
|
||||
factories.add(factory);
|
||||
final CheckRemovalSpec removalSpec = new CheckRemovalSpec(checkType, true, this);
|
||||
final boolean hasComplete = !removalSpec.completeRemoval.isEmpty();
|
||||
final boolean hasSub = !removalSpec.subCheckRemoval.isEmpty();
|
||||
if (hasComplete || hasSub) {
|
||||
for (final Entry<UUID, PlayerData> entry : playerData.iterable()) {
|
||||
final IPlayerData pData = entry.getValue();
|
||||
if (hasComplete) {
|
||||
pData.removeAllGenericInstances(removalSpec.completeRemoval);
|
||||
}
|
||||
if (hasSub) {
|
||||
pData.removeSubCheckData(removalSpec.subCheckRemoval, removalSpec.checkTypes);
|
||||
}
|
||||
// TODO: Remove the PlayerData instance, if suitable?
|
||||
}
|
||||
}
|
||||
for (final CheckDataFactory factory : factories) {
|
||||
// TODO: Support precise removal ?
|
||||
factory.removeAllData();
|
||||
}
|
||||
// TODO: IRemoveData - why register here at all ?
|
||||
for (final IRemoveData rmd : iRemoveData) {
|
||||
if (checkType == CheckType.ALL) {
|
||||
// Not sure this is really good, though.
|
||||
|
@ -933,7 +926,14 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
}
|
||||
}
|
||||
}
|
||||
for (final CheckType type : removalSpec.checkTypes) {
|
||||
final Map<String, ExecutionHistory> map = executionHistories.get(type);
|
||||
if (map != null) {
|
||||
map.clear();
|
||||
}
|
||||
}
|
||||
ViolationHistory.clear(checkType);
|
||||
// TODO: PlayerData removal should have other mechanisms (stages).
|
||||
if (checkType == CheckType.ALL) {
|
||||
bulkPlayerDataRemoval.addAll(playerData.getKeys());
|
||||
doBulkPlayerDataRemoval(); // Only removes offline player data.
|
||||
|
@ -989,4 +989,83 @@ public class PlayerDataManager implements IPlayerDataManager, ComponentWithName
|
|||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void registerFactory(final Class<T> registerFor,
|
||||
final IFactoryOne<PlayerFactoryArgument, T> factory) {
|
||||
factoryRegistry.registerFactory(registerFor, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Collection<Class<? extends T>> getGroupedTypes(final Class<T> groupType) {
|
||||
return factoryRegistry.getGroupedTypes(groupType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Collection<Class<? extends T>> getGroupedTypes(final Class<T> groupType,
|
||||
final CheckType checkType) {
|
||||
return factoryRegistry.getGroupedTypes(groupType, checkType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToGroups(final Class<I> itemType,
|
||||
final Class<? super I>... groupTypes) {
|
||||
factoryRegistry.addToGroups(itemType, groupTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToGroups(CheckType checkType, Class<I> itemType,
|
||||
Class<? super I>... groupTypes) {
|
||||
factoryRegistry.addToGroups(checkType, itemType, groupTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToExistingGroups(Class<?> itemType) {
|
||||
factoryRegistry.addToExistingGroups(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToExistingGroups(final CheckType checkType,
|
||||
final Class<I> itemType) {
|
||||
factoryRegistry.addToExistingGroups(checkType, itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <G> void createGroup(final Class<G> groupType) {
|
||||
factoryRegistry.createGroup(groupType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <G> void createAutoGroup(final Class<G> groupType) {
|
||||
factoryRegistry.createAutoGroup(groupType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToGroups(final Collection<CheckType> checkTypes,
|
||||
final Class<I> itemType, final Class<? super I>... groupTypes) {
|
||||
factoryRegistry.addToGroups(checkTypes, itemType, groupTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToExistingGroups(final Collection<CheckType> checkTypes,
|
||||
final Class<I> itemType) {
|
||||
factoryRegistry.addToExistingGroups(checkTypes, itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getNewInstance(final Class<T> registeredFor,
|
||||
final PlayerFactoryArgument arg) {
|
||||
return factoryRegistry.getNewInstance(registeredFor, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCachedConfigs() {
|
||||
final Collection<Class<?>> types = new LinkedHashSet<Class<?>>(
|
||||
factoryRegistry.getGroupedTypes(IConfig.class));
|
||||
if (!types.isEmpty()) {
|
||||
for (final Entry<UUID, PlayerData> entry : playerData.iterable()) {
|
||||
entry.getValue().removeAllGenericInstances(types);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -157,9 +157,22 @@ public class CheckUtils {
|
|||
* @return the log message prefix
|
||||
*/
|
||||
public static String getLogMessagePrefix(final Player player, final CheckType checkType) {
|
||||
return getLogMessagePrefix(player == null ? null : player.getName(), checkType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the standard log message prefix with a trailing space.
|
||||
*
|
||||
* @param playerName
|
||||
* May be null.
|
||||
* @param checkType
|
||||
* the check type
|
||||
* @return the log message prefix
|
||||
*/
|
||||
public static String getLogMessagePrefix(final String playerName, final CheckType checkType) {
|
||||
String base = "[" + checkType + "] ";
|
||||
if (player != null) {
|
||||
base += "[" + player.getName() + "] ";
|
||||
if (playerName != null) {
|
||||
base += "[" + playerName + "] ";
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.worlds;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData;
|
||||
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.
|
||||
|
@ -25,7 +27,7 @@ import fr.neatmonster.nocheatplus.components.registry.IGetGenericInstanceHandle;
|
|||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IWorldData extends IConfigDataAccess, IGetGenericInstance, IGetGenericInstanceHandle {
|
||||
public interface IWorldData extends IConfigDataAccess, IGetGenericInstance {
|
||||
|
||||
|
||||
/**
|
||||
|
@ -59,7 +61,30 @@ public interface IWorldData extends IConfigDataAccess, IGetGenericInstance, IGet
|
|||
*/
|
||||
public boolean shouldAdjustToLag(CheckType checkType);
|
||||
|
||||
// TODO: Generic data (includes config) storage.
|
||||
/**
|
||||
* Remove data from the cache (not from underlying factories, nor from per
|
||||
* world storage.
|
||||
*
|
||||
* @param registeredFor
|
||||
*/
|
||||
public <T> void removeGenericInstance(Class<T> registeredFor);
|
||||
|
||||
/**
|
||||
* Remove all generic instances from cache, which are contained in the given
|
||||
* collection.
|
||||
*
|
||||
* @param types
|
||||
*/
|
||||
public void removeAllGenericInstances(Collection<Class<?>> types);
|
||||
|
||||
/**
|
||||
* Call dataOnRemoveSubCheckData(...).
|
||||
*
|
||||
* @param subCheckRemoval
|
||||
*/
|
||||
public void removeSubCheckData(
|
||||
Collection<Class<? extends IDataOnRemoveSubCheckData>> subCheckRemoval,
|
||||
Collection<CheckType> checkTypes);
|
||||
|
||||
// TODO: isDebugActive(CheckType checkType);
|
||||
|
||||
|
|
|
@ -23,8 +23,36 @@ 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.registry.factory.IRichFactoryRegistry;
|
||||
|
||||
public interface IWorldDataManager {
|
||||
/**
|
||||
*
|
||||
* <hr/>
|
||||
* <b>Preset groups and automatic registration.</b><br/>
|
||||
* All of the types mentioned in the lists below are preset for grouping. <br/>
|
||||
* However only those item types for which a factory gets registered here will
|
||||
* be automatically put into existing groups. External types like configuration
|
||||
* instances fetched from IWorldData need to be registered explicitly. <br/>
|
||||
* <br/>
|
||||
* Automatic data type grouping with call support (return value controls removal
|
||||
* of the entire data object):
|
||||
* <ul>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IDataOnReload}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IDataOnWorldUnload}</li>
|
||||
* </ul>
|
||||
* <br/>
|
||||
* Automatic data type grouping for direct removal (API/reload/commands):
|
||||
* <ul>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.IData}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.config.IConfig}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.data.ICheckData}</li>
|
||||
* <li>{@link fr.neatmonster.nocheatplus.components.config.ICheckConfig}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public interface IWorldDataManager extends IRichFactoryRegistry<WorldFactoryArgument> {
|
||||
|
||||
/**
|
||||
* Get the default world data, which applies for all worlds for which no
|
||||
|
@ -140,4 +168,18 @@ public interface IWorldDataManager {
|
|||
*/
|
||||
public IWorldData getWorldDataSafe(Player player);
|
||||
|
||||
/**
|
||||
* Remove data for all worlds for the given check type and sub checks.
|
||||
*
|
||||
* @param checkType
|
||||
*/
|
||||
public void clearData(CheckType checkType);
|
||||
|
||||
/**
|
||||
* Convenience method to remove cached types that implement IConfig for all
|
||||
* worlds. Types need to be registered (world data factory or explicitly).
|
||||
*/
|
||||
public void removeCachedConfigs();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ package fr.neatmonster.nocheatplus.worlds;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
|
@ -23,13 +26,15 @@ 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.IDataOnReload;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnRemoveSubCheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnWorldUnload;
|
||||
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.components.registry.factory.IFactoryOneRegistry;
|
||||
import fr.neatmonster.nocheatplus.config.ConfigFile;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.InstanceMapLOW;
|
||||
|
||||
/**
|
||||
* Data stored per world.
|
||||
|
@ -137,6 +142,9 @@ public class WorldData implements IWorldData {
|
|||
if (configDebug.setValue(parentNode.configDebug.getValue(), configOverrideType)) {
|
||||
debug = parentNode.debug;
|
||||
}
|
||||
if (configLag.setValue(parentNode.configLag.getValue(), configOverrideType)) {
|
||||
lag = parentNode.lag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,24 +153,40 @@ public class WorldData implements IWorldData {
|
|||
* @param rawConfiguration
|
||||
*/
|
||||
void update(final ConfigFile rawConfiguration) {
|
||||
// TODO: A multi update method walking all nodes only once.
|
||||
// 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);
|
||||
/**
|
||||
* Update to activation states.
|
||||
*/
|
||||
void update() {
|
||||
// TODO: A multi update method walking all nodes only once?
|
||||
updateActivation(true);
|
||||
updateDebug(true);
|
||||
updateLag(true);
|
||||
// TODO: contained configurations.
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void overrideCheckActivation(final ConfigFile rawConfiguration,
|
||||
private void updateLag(final ConfigFile rawConfiguration,
|
||||
final boolean forceUpdateChildren) {
|
||||
update(rawConfiguration, forceUpdateChildren, accessLag);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void updateLag(final boolean forceUpdateChildren) {
|
||||
update(forceUpdateChildren, accessLag);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void overrideCheckActivation(
|
||||
final AlmostBoolean active, final OverrideType overrideType,
|
||||
final boolean overrideChildren) {
|
||||
configFlagOverride(rawConfiguration, active,
|
||||
override(active,
|
||||
overrideType, overrideChildren, accessActive);
|
||||
}
|
||||
|
||||
|
@ -178,8 +202,17 @@ public class WorldData implements IWorldData {
|
|||
@SuppressWarnings("unchecked")
|
||||
void updateActivation(final ConfigFile rawConfiguration,
|
||||
final boolean forceUpdateChildren) {
|
||||
update(rawConfiguration, forceUpdateChildren, accessActive);
|
||||
}
|
||||
|
||||
configFlagUpdate(rawConfiguration, forceUpdateChildren, accessActive);
|
||||
/**
|
||||
* Just update the activation.
|
||||
* @param forceUpdateChildren
|
||||
*/
|
||||
@SuppressWarnings({"unchecked" })
|
||||
void updateActivation(
|
||||
final boolean forceUpdateChildren) {
|
||||
update(forceUpdateChildren, accessActive);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -223,12 +256,11 @@ public class WorldData implements IWorldData {
|
|||
// Instance.
|
||||
///////////////////
|
||||
|
||||
// /** World wide lock ;). */
|
||||
// private final Lock lock = new ReentrantLock();
|
||||
/** World wide lock ;). */
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
WorldData parent = null;
|
||||
private final Collection<WorldData> children = new LinkedHashSet<WorldData>();
|
||||
private final GenericInstanceRegistry dataRegistry = new DefaultGenericInstanceRegistry();
|
||||
|
||||
private ConfigFile rawConfiguration = null;
|
||||
|
||||
|
@ -237,18 +269,25 @@ public class WorldData implements IWorldData {
|
|||
private final String worldNameLowerCase;
|
||||
private WorldIdentifier worldIdentifier = null;
|
||||
|
||||
WorldData(String worldName) {
|
||||
this(worldName, null);
|
||||
private IFactoryOneRegistry<WorldFactoryArgument> factoryRegistry;
|
||||
private final InstanceMapLOW dataCache = new InstanceMapLOW(lock, 25);
|
||||
|
||||
WorldData(final String worldName,
|
||||
final IFactoryOneRegistry<WorldFactoryArgument> factoryRegistry) {
|
||||
this(worldName, null, factoryRegistry);
|
||||
}
|
||||
|
||||
WorldData(String worldName, WorldData parent) {
|
||||
WorldData(final String worldName, final WorldData parent,
|
||||
final IFactoryOneRegistry<WorldFactoryArgument> factoryRegistry) {
|
||||
// TODO: ILockable ?
|
||||
this.parent = parent;
|
||||
this.worldNameLowerCase = worldName.toLowerCase(); // Locale.ENGLISH ?
|
||||
this.worldNameLowerCase = worldName == null ? null : worldName.toLowerCase(); // Locale.ENGLISH ?
|
||||
this.factoryRegistry = factoryRegistry;
|
||||
if (parent == null) {
|
||||
checkTypeTree.setConfigOverrideType(OverrideType.SPECIFIC);
|
||||
}
|
||||
else {
|
||||
checkTypeTree.setConfigOverrideType(OverrideType.DEFAULT);
|
||||
adjustToParent(parent);
|
||||
}
|
||||
}
|
||||
|
@ -267,8 +306,8 @@ public class WorldData implements IWorldData {
|
|||
checkTypeTree.getNode(checkType).adjustToParent(
|
||||
parent.checkTypeTree.getNode(checkType));
|
||||
}
|
||||
// Force update.
|
||||
checkTypeTree.getNode(CheckType.ALL).update(rawConfiguration);
|
||||
// Force update (custom overrides might be persistent, just not on object creation).
|
||||
checkTypeTree.getNode(CheckType.ALL).update();
|
||||
// TODO: What if children exist?
|
||||
}
|
||||
|
||||
|
@ -304,25 +343,40 @@ public class WorldData implements IWorldData {
|
|||
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.parent = null;
|
||||
this.checkTypeTree.getNode(CheckType.ALL).setConfigOverrideType(OverrideType.SPECIFIC);
|
||||
}
|
||||
this.update();
|
||||
// TODO: Propagate to children?
|
||||
}
|
||||
|
||||
void update() {
|
||||
// TODO: Locking ?
|
||||
// TODO: Distinguish updateByConfig and update().
|
||||
checkTypeTree.getNode(CheckType.ALL).update(rawConfiguration);
|
||||
// TODO: Propagate to children?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void overrideCheckActivation(final CheckType checkType,
|
||||
final AlmostBoolean active, final OverrideType overrideType,
|
||||
final boolean overrideChildren) {
|
||||
// TODO: Concept for locking.
|
||||
checkTypeTree.getNode(checkType).overrideCheckActivation(
|
||||
active, overrideType, overrideChildren);
|
||||
// TODO: Propagate to children?
|
||||
}
|
||||
|
||||
// TODO: overrideDebug?
|
||||
|
||||
@Override
|
||||
public ConfigFile getRawConfiguration() {
|
||||
return rawConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -335,14 +389,6 @@ public class WorldData implements IWorldData {
|
|||
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);
|
||||
|
@ -350,14 +396,16 @@ public class WorldData implements IWorldData {
|
|||
|
||||
@Override
|
||||
public <T> T getGenericInstance(final Class<T> registeredFor) {
|
||||
// TODO: Factories.
|
||||
return dataRegistry.getGenericInstance(registeredFor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> IGenericInstanceHandle<T> getGenericInstanceHandle(final Class<T> registeredFor) {
|
||||
// TODO: Factories.
|
||||
return dataRegistry.getGenericInstanceHandle(registeredFor);
|
||||
T instance = dataCache.get(registeredFor);
|
||||
if (instance == null) {
|
||||
instance = factoryRegistry.getNewInstance(registeredFor,
|
||||
new WorldFactoryArgument(this));
|
||||
if (instance != null) {
|
||||
final T newInstance = dataCache.putIfAbsent(registeredFor, instance);
|
||||
return newInstance == null ? instance : newInstance;
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -391,4 +439,58 @@ public class WorldData implements IWorldData {
|
|||
return getCheckNode(checkType).shouldAdjustToLag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove from cache.
|
||||
*/
|
||||
@Override
|
||||
public <T> void removeGenericInstance(final Class<T> type) {
|
||||
dataCache.remove(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllGenericInstances(final Collection<Class<?>> types) {
|
||||
if (dataCache.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
dataCache.remove(types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSubCheckData(
|
||||
final Collection<Class<? extends IDataOnRemoveSubCheckData>> types,
|
||||
final Collection<CheckType> checkTypes
|
||||
) {
|
||||
final Collection<Class<?>> removeTypes = new LinkedList<Class<?>>();
|
||||
for (final Class<? extends IDataOnRemoveSubCheckData> type : types) {
|
||||
final IDataOnRemoveSubCheckData impl = dataCache.get(type);
|
||||
if (impl != null) {
|
||||
if (impl.dataOnRemoveSubCheckData(checkTypes)) {
|
||||
removeTypes.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!removeTypes.isEmpty()) {
|
||||
dataCache.remove(removeTypes);
|
||||
}
|
||||
}
|
||||
|
||||
public void onWorldUnload(final World world, final Collection<Class<? extends IDataOnWorldUnload>> types) {
|
||||
for (final Class<? extends IDataOnWorldUnload> type : types) {
|
||||
final IDataOnWorldUnload instance = dataCache.get(type);
|
||||
if (instance != null && instance.dataOnWorldUnload(world, this)) {
|
||||
dataCache.remove(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onReload(final Collection<Class<? extends IDataOnReload>> types) {
|
||||
// (Might collect types in a set.)
|
||||
for (final Class<? extends IDataOnReload> type : types) {
|
||||
final IDataOnReload instance = dataCache.get(type);
|
||||
if (instance != null && instance.dataOnReload(this)) {
|
||||
dataCache.remove(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.worlds;
|
||||
|
||||
import java.util.Collection;
|
||||
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;
|
||||
|
@ -29,14 +31,32 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
|
||||
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
||||
import fr.neatmonster.nocheatplus.components.config.ICheckConfig;
|
||||
import fr.neatmonster.nocheatplus.components.config.IConfig;
|
||||
import fr.neatmonster.nocheatplus.components.config.value.OverrideType;
|
||||
import fr.neatmonster.nocheatplus.components.data.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IData;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnReload;
|
||||
import fr.neatmonster.nocheatplus.components.data.IDataOnWorldUnload;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.IFactoryOne;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.RichFactoryRegistry;
|
||||
import fr.neatmonster.nocheatplus.components.registry.factory.RichFactoryRegistry.CheckRemovalSpec;
|
||||
import fr.neatmonster.nocheatplus.components.registry.feature.INotifyReload;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.RegistrationOrder.RegisterMethodWithOrder;
|
||||
import fr.neatmonster.nocheatplus.config.ConfigFile;
|
||||
import fr.neatmonster.nocheatplus.config.DefaultConfig;
|
||||
import fr.neatmonster.nocheatplus.event.mini.MiniListener;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.HashMapLOW;
|
||||
|
||||
public class WorldDataManager implements IWorldDataManager {
|
||||
public class WorldDataManager implements IWorldDataManager, INotifyReload {
|
||||
|
||||
static class IWorldDataEntry implements Entry<String, IWorldData> {
|
||||
|
||||
|
@ -93,15 +113,41 @@ public class WorldDataManager implements IWorldDataManager {
|
|||
/** Global access lock for this registry. Also used for ConfigFile editing. */
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
/** Exact case name to WorldData map. */
|
||||
/** Lower case name to WorldData map. */
|
||||
// TODO: ID-name pairs / mappings?
|
||||
private final HashMapLOW<String, WorldData> worldDataMap = new HashMapLOW<String, WorldData>(lock, 10);
|
||||
private Map<String, ConfigFile> rawConfigurations = new HashMap<String, ConfigFile>(); // COW
|
||||
private final RichFactoryRegistry<WorldFactoryArgument> factoryRegistry = new RichFactoryRegistry<WorldFactoryArgument>(lock);
|
||||
|
||||
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<WorldUnloadEvent>() {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@RegisterMethodWithOrder(tag = "system.nocheatplus.worlddatamanager", beforeTag = "(system\\.nocheatplus\\.playerdatamanager|feature.*)")
|
||||
@Override
|
||||
public void onEvent(final WorldUnloadEvent event) {
|
||||
onWorldUnload(event);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
public WorldDataManager() {
|
||||
// TODO: ILockable
|
||||
// TODO: Create a default node with some basic settings.
|
||||
createDefaultWorldData();
|
||||
// (Call support.)
|
||||
factoryRegistry.createAutoGroup(IDataOnReload.class);
|
||||
factoryRegistry.createAutoGroup(IDataOnWorldUnload.class);
|
||||
// Data/config removal.
|
||||
factoryRegistry.createAutoGroup(IData.class);
|
||||
factoryRegistry.createAutoGroup(IConfig.class);
|
||||
factoryRegistry.createAutoGroup(ICheckData.class);
|
||||
factoryRegistry.createAutoGroup(ICheckConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -146,7 +192,18 @@ public class WorldDataManager implements IWorldDataManager {
|
|||
}
|
||||
|
||||
private void createDefaultWorldData() {
|
||||
createWorldData(null);
|
||||
lock.lock();
|
||||
if (worldDataMap.containsKey(null)) {
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
ConfigFile config = rawConfigurations.get(null);
|
||||
if (config == null) {
|
||||
config = new DefaultConfig();
|
||||
}
|
||||
worldDataMap.put(null, new WorldData(null, this));
|
||||
updateWorldData(null, config);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -188,11 +245,12 @@ public class WorldDataManager implements IWorldDataManager {
|
|||
lock.lock();
|
||||
final Map<String, ConfigFile> rawConfigurations = new LinkedHashMap<String, ConfigFile>(rawWorldConfigs.size());
|
||||
for (final Entry<String, ConfigFile> entry : rawWorldConfigs.entrySet()) {
|
||||
rawConfigurations.put(entry.getKey().toLowerCase(), entry.getValue());
|
||||
final String worldName = entry.getKey();
|
||||
rawConfigurations.put(worldName == null ? null : worldName.toLowerCase(), entry.getValue());
|
||||
}
|
||||
this.rawConfigurations = rawConfigurations;
|
||||
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
|
||||
|
@ -209,14 +267,14 @@ public class WorldDataManager implements IWorldDataManager {
|
|||
// 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<String, WorldData> entry : worldDataMap.iterable()) {
|
||||
if (!rawConfigurations.containsKey(entry.getKey())) {
|
||||
final String worldName = entry.getKey();
|
||||
if (worldName != null
|
||||
&& !rawConfigurations.containsKey(worldName)) {
|
||||
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();
|
||||
}
|
||||
lock.lock();
|
||||
defaultWorldData.addChild(ref); // Redundant calls are ok.
|
||||
ref.adjustToParent(defaultWorldData); // Inherit specific overrides and more.
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -269,17 +327,24 @@ public class WorldDataManager implements IWorldDataManager {
|
|||
* @param rawConfiguration
|
||||
* @return
|
||||
*/
|
||||
private WorldData updateWorldData(final String worldName, final ConfigFile rawConfiguration) {
|
||||
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();
|
||||
final String lcName = worldName == null ? null : worldName.toLowerCase();
|
||||
WorldData data = worldDataMap.get(lcName);
|
||||
boolean skipUpdate = false;
|
||||
if (data == null) {
|
||||
data = new WorldData(worldName, defaultWorldData);
|
||||
worldDataMap.put(worldName.toLowerCase(), data);
|
||||
defaultWorldData.addChild(data);
|
||||
data = new WorldData(worldName, defaultWorldData, factoryRegistry);
|
||||
worldDataMap.put(data.getWorldNameLowerCase(), data);
|
||||
if (rawConfiguration == defaultWorldData.getRawConfiguration()) {
|
||||
defaultWorldData.addChild(data);
|
||||
skipUpdate = true;
|
||||
}
|
||||
}
|
||||
if (!skipUpdate) {
|
||||
data.update(rawConfiguration); // Parent/child state is updated here.
|
||||
}
|
||||
data.update(rawConfiguration); // Parent/child state is updated here.
|
||||
lock.unlock();
|
||||
return data;
|
||||
}
|
||||
|
@ -287,17 +352,16 @@ public class WorldDataManager implements IWorldDataManager {
|
|||
@Override
|
||||
public void overrideCheckActivation(final CheckType checkType, final AlmostBoolean active,
|
||||
final OverrideType overrideType, final boolean overrideChildren) {
|
||||
|
||||
// TODO: Implement changed signature
|
||||
//
|
||||
lock.lock();
|
||||
final IWorldData defaultWorldData = getDefaultWorldData();
|
||||
defaultWorldData.overrideCheckActivation(checkType, active, overrideType, overrideChildren);
|
||||
// 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.
|
||||
// TODO: If possible, skip derived from default, since default data is done first.
|
||||
for (final Entry<String, WorldData> entry : worldDataMap.iterable()) {
|
||||
final WorldData worldData = entry.getValue();
|
||||
// TODO: default visibility method including overrideChildWorldDatas (here: false).
|
||||
worldData.overrideCheckActivation(checkType, active, overrideType, overrideChildren);
|
||||
final IWorldData worldData = entry.getValue();
|
||||
if (worldData != defaultWorldData) {
|
||||
worldData.overrideCheckActivation(checkType, active, overrideType, overrideChildren);
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
@ -328,4 +392,129 @@ public class WorldDataManager implements IWorldDataManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void registerFactory(Class<T> registerFor,
|
||||
IFactoryOne<WorldFactoryArgument, T> factory) {
|
||||
factoryRegistry.registerFactory(registerFor, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <G> void createAutoGroup(Class<G> groupType) {
|
||||
factoryRegistry.createAutoGroup(groupType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Collection<Class<? extends T>> getGroupedTypes(
|
||||
Class<T> groupType) {
|
||||
return factoryRegistry.getGroupedTypes(groupType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Collection<Class<? extends T>> getGroupedTypes(
|
||||
Class<T> groupType, CheckType checkType) {
|
||||
return factoryRegistry.getGroupedTypes(groupType, checkType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToGroups(Class<I> itemType,
|
||||
Class<? super I>... groupTypes) {
|
||||
factoryRegistry.addToGroups(itemType, groupTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToExistingGroups(Class<?> itemType) {
|
||||
factoryRegistry.addToExistingGroups(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToGroups(CheckType checkType, Class<I> itemType,
|
||||
Class<? super I>... groupTypes) {
|
||||
factoryRegistry.addToGroups(checkType, itemType, groupTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToExistingGroups(CheckType checkType,
|
||||
Class<I> itemType) {
|
||||
factoryRegistry.addToExistingGroups(checkType, itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToGroups(Collection<CheckType> checkTypes,
|
||||
Class<I> itemType, Class<? super I>... groupTypes) {
|
||||
factoryRegistry.addToGroups(checkTypes, itemType, groupTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I> void addToExistingGroups(Collection<CheckType> checkTypes,
|
||||
Class<I> itemType) {
|
||||
factoryRegistry.addToExistingGroups(checkTypes, itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <G> void createGroup(Class<G> groupType) {
|
||||
factoryRegistry.createGroup(groupType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getNewInstance(Class<T> registeredFor,
|
||||
WorldFactoryArgument arg) {
|
||||
return factoryRegistry.getNewInstance(registeredFor, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializing with online players.
|
||||
*/
|
||||
public void onEnable() {
|
||||
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
|
||||
for (final MiniListener<?> listener : miniListeners) {
|
||||
api.addComponent(listener, false);
|
||||
}
|
||||
api.addComponent(this);
|
||||
}
|
||||
|
||||
private void onWorldUnload(WorldUnloadEvent event) {
|
||||
final Collection<Class<? extends IDataOnWorldUnload>> types = factoryRegistry.getGroupedTypes(IDataOnWorldUnload.class);
|
||||
final World world = event.getWorld();
|
||||
final WorldData worldData = worldDataMap.get(world.getName().toLowerCase());
|
||||
worldData.onWorldUnload(event.getWorld(), types);
|
||||
// TODO: Minimize, clear cache / remove ?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
final Collection<Class<? extends IDataOnReload>> types = factoryRegistry.getGroupedTypes(IDataOnReload.class);
|
||||
for (final Entry<String, WorldData> entry : worldDataMap.iterable()) {
|
||||
entry.getValue().onReload(types);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearData(CheckType checkType) {
|
||||
final CheckRemovalSpec removalSpec = new CheckRemovalSpec(checkType, true, this);
|
||||
final boolean hasComplete = !removalSpec.completeRemoval.isEmpty();
|
||||
final boolean hasSub = !removalSpec.subCheckRemoval.isEmpty();
|
||||
if (hasComplete || hasSub) {
|
||||
for (final Entry<String, WorldData> entry : worldDataMap.iterable()) {
|
||||
final WorldData worldData = entry.getValue();
|
||||
if (hasComplete) {
|
||||
worldData.removeAllGenericInstances(removalSpec.completeRemoval);
|
||||
}
|
||||
if (hasSub) {
|
||||
worldData.removeSubCheckData(removalSpec.subCheckRemoval, removalSpec.checkTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCachedConfigs() {
|
||||
final Collection<Class<?>> types = new LinkedHashSet<Class<?>>(
|
||||
factoryRegistry.getGroupedTypes(IConfig.class));
|
||||
if (!types.isEmpty()) {
|
||||
for (final Entry<String, WorldData> entry : worldDataMap.iterable()) {
|
||||
entry.getValue().removeAllGenericInstances(types);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package fr.neatmonster.nocheatplus.worlds;
|
||||
|
||||
public class WorldFactoryArgument {
|
||||
|
||||
public final IWorldData worldData;
|
||||
|
||||
public WorldFactoryArgument(IWorldData worldData) {
|
||||
this.worldData = worldData;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package fr.neatmonster.nocheatplus.test;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
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.config.value.ValueWithOverride;
|
||||
|
||||
public class TestConfigValueWithOverride {
|
||||
|
||||
private <T> void expectValueIdentity(ValueWithOverride<T> configValue, T value) {
|
||||
if (configValue.getValue() != value) {
|
||||
fail("Expect value '" + value + "', got instead: '" + configValue.getValue() + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlmostBoolean() {
|
||||
|
||||
AlmostBooleanWithOverride val1 = new AlmostBooleanWithOverride();
|
||||
if (!val1.setValue(AlmostBoolean.NO, OverrideType.SPECIFIC)) {
|
||||
fail("Override to SPECIFIC after init is expected to work.");
|
||||
}
|
||||
expectValueIdentity(val1, AlmostBoolean.NO);
|
||||
|
||||
if (!val1.setValue(AlmostBoolean.YES, OverrideType.SPECIFIC)) {
|
||||
fail("Override SPECIFIC -> SPECIFIC is expected to work.");
|
||||
}
|
||||
expectValueIdentity(val1, AlmostBoolean.YES);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -65,6 +65,7 @@ import fr.neatmonster.nocheatplus.checks.moving.MovingListener;
|
|||
import fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace.TraceEntryPool;
|
||||
import fr.neatmonster.nocheatplus.checks.moving.util.AuxMoving;
|
||||
import fr.neatmonster.nocheatplus.checks.net.NetConfig;
|
||||
import fr.neatmonster.nocheatplus.checks.net.NetStatic;
|
||||
import fr.neatmonster.nocheatplus.checks.workaround.WRPT;
|
||||
import fr.neatmonster.nocheatplus.clients.ModUtil;
|
||||
import fr.neatmonster.nocheatplus.command.NoCheatPlusCommand;
|
||||
|
@ -100,6 +101,7 @@ import fr.neatmonster.nocheatplus.components.registry.feature.TickListener;
|
|||
import fr.neatmonster.nocheatplus.components.registry.lockable.BasicLockable;
|
||||
import fr.neatmonster.nocheatplus.components.registry.lockable.ILockable;
|
||||
import fr.neatmonster.nocheatplus.components.registry.order.SetupOrder;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.RegistrationContext;
|
||||
import fr.neatmonster.nocheatplus.config.ConfPaths;
|
||||
import fr.neatmonster.nocheatplus.config.ConfigFile;
|
||||
import fr.neatmonster.nocheatplus.config.ConfigManager;
|
||||
|
@ -122,12 +124,13 @@ 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.IPlayerDataManager;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.IPlayerDataManager;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerDataManager;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerMessageSender;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
import fr.neatmonster.nocheatplus.utilities.ColorUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.Misc;
|
||||
import fr.neatmonster.nocheatplus.utilities.OnDemandTickListener;
|
||||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.StringUtil;
|
||||
|
@ -269,6 +272,17 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
|
|||
|
||||
}
|
||||
|
||||
@SetupOrder(priority = - 100)
|
||||
private class ReloadHook implements INotifyReload{
|
||||
@Override
|
||||
public void onReload() {
|
||||
// Only for reloading, not INeedConfig.
|
||||
processReload();
|
||||
}
|
||||
}
|
||||
|
||||
private INotifyReload reloadHook = new ReloadHook();
|
||||
|
||||
/** 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();
|
||||
|
@ -939,23 +953,15 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
|
|||
initBlockProperties(config);
|
||||
|
||||
// Initialize data manager.
|
||||
worldDataManager.onEnable();
|
||||
pDataMan.onEnable();
|
||||
|
||||
// Register components.
|
||||
@SetupOrder(priority = - 100)
|
||||
class ReloadHook implements INotifyReload{
|
||||
@Override
|
||||
public void onReload() {
|
||||
// Only for reloading, not INeedConfig.
|
||||
processReload();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the "low level" system components first.
|
||||
for (final Object obj : new Object[]{
|
||||
getCoreListener(),
|
||||
// Put ReloadListener first, because Checks could also listen to it.
|
||||
new ReloadHook(),
|
||||
reloadHook,
|
||||
pDataMan,
|
||||
new AuxMoving(),
|
||||
}) {
|
||||
|
@ -981,6 +987,8 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
|
|||
// Register sub-components (allow later added to use registries, if any).
|
||||
processQueuedSubComponentHolders();
|
||||
}
|
||||
// Ensure net types are registered.
|
||||
NetStatic.registerTypes();
|
||||
|
||||
// Register optional default components.
|
||||
final DefaultComponentFactory dcf = new DefaultComponentFactory();
|
||||
|
@ -1018,8 +1026,12 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
|
|||
}, 1207, 1207);
|
||||
|
||||
// Ensure dataMan is first on disableListeners.
|
||||
disableListeners.remove(pDataMan);
|
||||
disableListeners.add(0, pDataMan);
|
||||
// TODO: Why first ?
|
||||
Misc.putFirst(pDataMan, disableListeners);
|
||||
Misc.putFirst(pDataMan, notifyReload);
|
||||
Misc.putFirst(worldDataManager, notifyReload);
|
||||
// Put ReloadListener first, because Checks could also listen to it.
|
||||
Misc.putFirst(reloadHook, notifyReload);
|
||||
|
||||
// Set up consistency checking.
|
||||
scheduleConsistencyCheckers();
|
||||
|
@ -1518,4 +1530,14 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
|
|||
return pDataMan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RegistrationContext context) {
|
||||
context.doRegister(); // TODO: ...
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistrationContext newRegistrationContext() {
|
||||
return new RegistrationContext();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package fr.neatmonster.nocheatplus;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -25,6 +26,9 @@ import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
|
|||
import fr.neatmonster.nocheatplus.components.registry.ComponentRegistry;
|
||||
import fr.neatmonster.nocheatplus.components.registry.DefaultGenericInstanceRegistry;
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle;
|
||||
import fr.neatmonster.nocheatplus.components.registry.setup.RegistrationContext;
|
||||
import fr.neatmonster.nocheatplus.config.ConfigFile;
|
||||
import fr.neatmonster.nocheatplus.config.DefaultConfig;
|
||||
import fr.neatmonster.nocheatplus.event.mini.EventRegistryBukkit;
|
||||
import fr.neatmonster.nocheatplus.logging.LogManager;
|
||||
import fr.neatmonster.nocheatplus.logging.StaticLog;
|
||||
|
@ -51,10 +55,14 @@ public class PluginTests {
|
|||
private final PermissionRegistry permissionRegistry = new PermissionRegistry(10000);
|
||||
|
||||
public UnitTestNoCheatPlusAPI() {
|
||||
StaticLog.setUseLogManager(false); // Ensure either this instance provides it or it's unset.
|
||||
genericInstanceRegistry.registerGenericInstance(MCAccess.class, new MCAccessBukkit());
|
||||
for (RegisteredPermission rp : Permissions.getPermissions()) {
|
||||
permissionRegistry.addRegisteredPermission(rp);
|
||||
}
|
||||
Map<String, ConfigFile> rawConfigs = new HashMap<String, ConfigFile>();
|
||||
rawConfigs.put(null, new DefaultConfig());
|
||||
worldDataManager.applyConfiguration((rawConfigs));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -194,6 +202,16 @@ public class PluginTests {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistrationContext newRegistrationContext() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RegistrationContext context) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void setUnitTestNoCheatPlusAPI(boolean force) {
|
||||
|
|
|
@ -16,6 +16,7 @@ package fr.neatmonster.nocheatplus.test;
|
|||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -29,6 +30,7 @@ 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.logging.StaticLog;
|
||||
import fr.neatmonster.nocheatplus.worlds.WorldDataManager;
|
||||
|
||||
public class TestWorldDataManager {
|
||||
|
@ -55,9 +57,30 @@ public class TestWorldDataManager {
|
|||
cfg.set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set for all.
|
||||
*
|
||||
* @param map
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
void set(Map<String, ConfigFile> map, String key, Object value) {
|
||||
for (String worldName : map.keySet()) {
|
||||
set(map, worldName, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void setup(Map<String, ConfigFile> map, String... worldNames) {
|
||||
for (String worldName : worldNames) {
|
||||
set(map, worldName, "dummy", true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BasicTests() {
|
||||
|
||||
//PluginTests.setUnitTestNoCheatPlusAPI(false);
|
||||
StaticLog.setUseLogManager(false);
|
||||
|
||||
WorldDataManager worldMan = getWorldDataManager();
|
||||
|
||||
|
@ -66,7 +89,9 @@ public class TestWorldDataManager {
|
|||
// (Implicitly create configurations via set).
|
||||
// Default.
|
||||
set(rawWorldConfigs, null, ConfPaths.COMBINED + ConfPaths.SUB_ACTIVE, "yes");
|
||||
set(rawWorldConfigs, null, ConfPaths.COMBINED_MUNCHHAUSEN_CHECK, "default");
|
||||
// All existing.
|
||||
setup(rawWorldConfigs, null, "Exist1", "Exist2");
|
||||
set(rawWorldConfigs, ConfPaths.COMBINED_MUNCHHAUSEN_CHECK, "default");
|
||||
|
||||
// Exist1
|
||||
set(rawWorldConfigs, "Exist1", ConfPaths.COMBINED + ConfPaths.SUB_ACTIVE, "no");
|
||||
|
@ -76,8 +101,18 @@ public class TestWorldDataManager {
|
|||
|
||||
// (Might set some particularly interesting values here.)
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// Apply configuration
|
||||
/////////////////////////
|
||||
worldMan.applyConfiguration(rawWorldConfigs);
|
||||
|
||||
for (String worldName : Arrays.asList("Exist1", "Exist2")) {
|
||||
if (rawWorldConfigs.get(worldName) != worldMan.getWorldData(worldName).getRawConfiguration()) {
|
||||
fail("Raw configuration set wrongly: " + worldName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!worldMan.getWorldData("notExist1").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) {
|
||||
fail("Inherited from default: COMBINED_MUNCHHAUSEN should be active (-> COMBINED is)");
|
||||
}
|
||||
|
@ -94,6 +129,15 @@ public class TestWorldDataManager {
|
|||
fail("Specific: COMBINED_MUNCHHAUSEN should not be active (directly set)");
|
||||
}
|
||||
|
||||
if (!worldMan.getWorldData("notExist2").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) {
|
||||
fail("Inherited from default: COMBINED_MUNCHHAUSEN should be active (-> COMBINED is)");
|
||||
}
|
||||
|
||||
|
||||
////////////////
|
||||
// Override
|
||||
////////////////
|
||||
|
||||
// Override via config "reload":
|
||||
set(rawWorldConfigs, "Exist2", ConfPaths.COMBINED_MUNCHHAUSEN_CHECK, true);
|
||||
worldMan.applyConfiguration(rawWorldConfigs);
|
||||
|
@ -101,32 +145,57 @@ public class TestWorldDataManager {
|
|||
fail("Specific: COMBINED_MUNCHHAUSEN should be active (directly set)");
|
||||
}
|
||||
|
||||
// Specific override (mild / reset with reload).
|
||||
// Specific override (mild).
|
||||
worldMan.overrideCheckActivation(CheckType.COMBINED, AlmostBoolean.NO,
|
||||
OverrideType.SPECIFIC, false);
|
||||
if (worldMan.getWorldData("notExist2").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) {
|
||||
fail("Overridden (inherited from default): COMBINED_MUNCHHAUSEN should not be active (-> COMBINED is not)");
|
||||
}
|
||||
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)");
|
||||
fail("Overridden (inherited from default): COMBINED_MUNCHHAUSEN should not be active (overrideChildren from COMBINED should explicitly set this)");
|
||||
}
|
||||
|
||||
|
||||
///////////////////
|
||||
// Fake reload 1
|
||||
///////////////////
|
||||
/*
|
||||
* NOTE: With this testing scenario, ConfigFile instances within
|
||||
* rawWorldConfigs stay identical, which would not be the case with a
|
||||
* ConfigManager based reload.
|
||||
*/
|
||||
worldMan.applyConfiguration(rawWorldConfigs);
|
||||
|
||||
if (!worldMan.getWorldData("notExist2").isCheckActive(CheckType.COMBINED)) {
|
||||
fail("Inherited from default: COMBINED should be active after reload.");
|
||||
}
|
||||
if (!worldMan.getWorldData("notExist2").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) {
|
||||
fail("Inherited from default: COMBINED_MUNCHHAUSEN should be active (-> COMBINED is)");
|
||||
}
|
||||
|
||||
|
||||
////////////////
|
||||
// Override 2
|
||||
////////////////
|
||||
|
||||
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)");
|
||||
}
|
||||
|
||||
|
||||
///////////////////
|
||||
// Fake reload 2
|
||||
///////////////////
|
||||
worldMan.applyConfiguration(rawWorldConfigs);
|
||||
if (worldMan.getWorldData("notExist3").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) {
|
||||
fail("Overridden (SPECIFIC): COMBINED_MUNCHHAUSEN should not be active after reload (directly set)");
|
||||
|
||||
if (!worldMan.getWorldData("notExist3").isCheckActive(CheckType.COMBINED_MUNCHHAUSEN)) {
|
||||
fail("Overridden (SPECIFIC): COMBINED_MUNCHHAUSEN should be active after reload (COMBINED is)");
|
||||
}
|
||||
|
||||
// TODO: "Reload with special cases"
|
||||
// TODO: overriding
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue