Formatting / cleanup.

This commit is contained in:
asofold 2014-11-01 16:33:48 +01:00
parent 1d78b4eac0
commit d013f289ec
2 changed files with 541 additions and 508 deletions

View File

@ -62,453 +62,486 @@ import fr.neatmonster.nocheatplus.utilities.StringUtil;
*/
@SetupOrder(priority = -80)
public class DataManager implements Listener, INotifyReload, INeedConfig, ComponentRegistry<IRemoveData>, ComponentWithName, ConsistencyChecker, DisableListener{
protected static DataManager instance = null;
// Not static
private int foundInconsistencies = 0;
/** PlayerData storage. */
protected final Map<String, PlayerData> playerData = new LinkedHashMap<String, PlayerData>(100);
/*
*
*/
/**
* Access order for playerName (exact) -> ms time of logout.
* <hr>
* Later this might hold central player data objects instead of the long only.
*/
private final Map<String, Long> lastLogout = new LinkedHashMap<String, Long>(50, 0.75f, true);
/**
* Keeping track of online players.<br>
* Mappings:
* <li>exact player name -> Player instance</li>
* <li>lower case player name -> Player instance</li>
*/
protected final Map<String, Player> onlinePlayers = new LinkedHashMap<String, Player>(100);
/**
* IRemoveData instances.
* // TODO: might use a map for those later (extra or not).
*/
protected final ArrayList<IRemoveData> iRemoveData = new ArrayList<IRemoveData>();
/**
* Execution histories of the checks.
*/
protected final Map<CheckType, Map<String, ExecutionHistory>> executionHistories = new HashMap<CheckType, Map<String,ExecutionHistory>>();
/** Flag if data expiration is active at all. */
protected boolean doExpireData = false;
/**
* Duration in milliseconds for expiration of logged off players data.
* In the config minutes are used as unit.
*/
protected long durExpireData = 0;
/** Data and execution history. */
protected boolean deleteData = true;
/** Violation history and execution history. */
protected boolean deleteHistory = false;
/**
* Sets the static instance reference.
*/
public DataManager(){
instance = this;
}
/**
* Check the logged out players for if any data can be removed.<br>
* Currently only "dumb" full removal is performed. Later it is thinkable to remove "as much as reasonable".
*/
public void checkExpiration(){
if (!doExpireData || durExpireData <= 0) return;
final long now = System.currentTimeMillis();
final Set<CheckDataFactory> factories = new LinkedHashSet<CheckDataFactory>();
final Set<Entry<String, Long>> entries = lastLogout.entrySet();
final Iterator<Entry<String, Long>> iterator = entries.iterator();
while (iterator.hasNext()){
final Entry<String, Long> entry = iterator.next();
final long ts = entry.getValue();
if (now - ts <= durExpireData) break;
final String playerName = entry.getKey();
if (deleteData){
factories.clear();
for (final CheckType type : CheckType.values()){
final CheckDataFactory factory = type.getDataFactory();
if (factory != null) factories.add(factory);
}
for (final CheckDataFactory factory : factories){
factory.removeData(playerName);
}
clearComponentData(CheckType.ALL, playerName);
playerData.remove(playerName.toLowerCase()); // TODO
}
if (deleteData || deleteHistory) removeExecutionHistory(CheckType.ALL, playerName);
if (deleteHistory) ViolationHistory.removeHistory(playerName);
iterator.remove();
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(final PlayerJoinEvent event){
final Player player = event.getPlayer();
lastLogout.remove(player.getName());
CombinedData.getData(player).lastJoinTime = System.currentTimeMillis();
addOnlinePlayer(player);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(final PlayerQuitEvent event){
onLeave(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerKick(final PlayerKickEvent event){
protected static DataManager instance = null;
// Not static
private int foundInconsistencies = 0;
/** PlayerData storage. */
protected final Map<String, PlayerData> playerData = new LinkedHashMap<String, PlayerData>(100);
/*
*
*/
/**
* Access order for playerName (exact) -> ms time of logout.
* <hr>
* Later this might hold central player data objects instead of the long only.
*/
private final Map<String, Long> lastLogout = new LinkedHashMap<String, Long>(50, 0.75f, true);
/**
* Keeping track of online players.<br>
* Mappings:
* <li>exact player name -> Player instance</li>
* <li>lower case player name -> Player instance</li>
*/
protected final Map<String, Player> onlinePlayers = new LinkedHashMap<String, Player>(100);
/**
* IRemoveData instances.
* // TODO: might use a map for those later (extra or not).
*/
protected final ArrayList<IRemoveData> iRemoveData = new ArrayList<IRemoveData>();
/**
* Execution histories of the checks.
*/
protected final Map<CheckType, Map<String, ExecutionHistory>> executionHistories = new HashMap<CheckType, Map<String,ExecutionHistory>>();
/** Flag if data expiration is active at all. */
protected boolean doExpireData = false;
/**
* Duration in milliseconds for expiration of logged off players data.
* In the config minutes are used as unit.
*/
protected long durExpireData = 0;
/** Data and execution history. */
protected boolean deleteData = true;
/** Violation history and execution history. */
protected boolean deleteHistory = false;
/**
* Sets the static instance reference.
*/
public DataManager() {
instance = this;
}
/**
* Check the logged out players for if any data can be removed.<br>
* Currently only "dumb" full removal is performed. Later it is thinkable to remove "as much as reasonable".
*/
public void checkExpiration() {
if (!doExpireData || durExpireData <= 0) {
return;
}
final long now = System.currentTimeMillis();
final Set<CheckDataFactory> factories = new LinkedHashSet<CheckDataFactory>();
final Set<Entry<String, Long>> entries = lastLogout.entrySet();
final Iterator<Entry<String, Long>> iterator = entries.iterator();
while (iterator.hasNext()) {
final Entry<String, Long> entry = iterator.next();
final long ts = entry.getValue();
if (now - ts <= durExpireData) {
break;
}
final String playerName = entry.getKey();
if (deleteData) {
factories.clear();
for (final CheckType type : CheckType.values()) {
final CheckDataFactory factory = type.getDataFactory();
if (factory != null) {
factories.add(factory);
}
}
for (final CheckDataFactory factory : factories) {
factory.removeData(playerName);
}
clearComponentData(CheckType.ALL, playerName);
playerData.remove(playerName.toLowerCase()); // TODO
}
if (deleteData || deleteHistory) {
removeExecutionHistory(CheckType.ALL, playerName);
}
if (deleteHistory) {
ViolationHistory.removeHistory(playerName);
}
iterator.remove();
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(final PlayerJoinEvent event) {
final Player player = event.getPlayer();
lastLogout.remove(player.getName());
CombinedData.getData(player).lastJoinTime = System.currentTimeMillis();
addOnlinePlayer(player);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(final PlayerQuitEvent event) {
onLeave(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerKick(final PlayerKickEvent event) {
onLeave(event.getPlayer());
}
/**
* Quit or kick.
* @param player
*/
private final void onLeave(final Player player) {
final long now = System.currentTimeMillis();
private final void onLeave(final Player player) {
final long now = System.currentTimeMillis();
lastLogout.put(player.getName(), now);
CombinedData.getData(player).lastLogoutTime = now;
removeOnlinePlayer(player);
}
@Override
public void onReload() {
// present.
adjustSettings();
}
/**
* Fetch settings from the current default config.
*/
private void adjustSettings() {
final ConfigFile config = ConfigManager.getConfigFile();
doExpireData = config.getBoolean(ConfPaths.DATA_EXPIRATION_ACTIVE);
durExpireData = config.getLong(ConfPaths.DATA_EXPIRATION_DURATION, 1, 1000000, 60) * 60000L; // in minutes
deleteData = config.getBoolean(ConfPaths.DATA_EXPIRATION_DATA, true); // hidden.
deleteHistory = config.getBoolean(ConfPaths.DATA_EXPIRATION_HISTORY);
}
@Override
public void onReload() {
// present.
adjustSettings();
}
/**
* Used by checks to register the history for external access.<br>
* NOTE: This method is not really meant ot be used from outside NCP.
* @param type
* @param histories
*/
public static void registerExecutionHistory(CheckType type, Map<String, ExecutionHistory> histories) {
instance.executionHistories.put(type, histories);
}
/**
* Access method to the the execution history for check type for a player.
* @param type
* @param playerName Exact case for player name.
* @return null if not present.
*/
public static ExecutionHistory getExecutionHistory(final CheckType type, final String playerName){
final Map<String, ExecutionHistory> map = instance.executionHistories.get(type);
if (map != null) return map.get(playerName);
/**
* Fetch settings from the current default config.
*/
private void adjustSettings() {
final ConfigFile config = ConfigManager.getConfigFile();
doExpireData = config.getBoolean(ConfPaths.DATA_EXPIRATION_ACTIVE);
durExpireData = config.getLong(ConfPaths.DATA_EXPIRATION_DURATION, 1, 1000000, 60) * 60000L; // in minutes
deleteData = config.getBoolean(ConfPaths.DATA_EXPIRATION_DATA, true); // hidden.
deleteHistory = config.getBoolean(ConfPaths.DATA_EXPIRATION_HISTORY);
}
/**
* Used by checks to register the history for external access.<br>
* NOTE: This method is not really meant ot be used from outside NCP.
* @param type
* @param histories
*/
public static void registerExecutionHistory(CheckType type, Map<String, ExecutionHistory> histories) {
instance.executionHistories.put(type, histories);
}
/**
* Access method to the the execution history for check type for a player.
* @param type
* @param playerName Exact case for player name.
* @return null if not present.
*/
public static ExecutionHistory getExecutionHistory(final CheckType type, final String playerName) {
final Map<String, ExecutionHistory> map = instance.executionHistories.get(type);
if (map != null) {
return map.get(playerName);
}
return null;
}
/**
* Remove the execution history for a player for the given check type.
* @param type
* @param playerName
* @return
*/
public static boolean removeExecutionHistory(final CheckType type, final String playerName){
boolean removed = false;
// TODO: design ...
for (final CheckType refType : APIUtils.getWithChildren(type)){
final Map<String, ExecutionHistory> map = instance.executionHistories.get(refType);
if (map != null && map.remove(playerName) != null) removed = true;
}
return removed;
}
/**
* Removes all data and history for a player.
* @deprecated Use clearData instead, this likely to be removed later.
* @param checkType
*/
public static void clear(final CheckType checkType){
clearData(checkType);
}
}
/**
* Remove the execution history for a player for the given check type.
* @param type
* @param playerName
* @return
*/
public static boolean removeExecutionHistory(final CheckType type, final String playerName) {
boolean removed = false;
// TODO: design ...
for (final CheckType refType : APIUtils.getWithChildren(type)) {
final Map<String, ExecutionHistory> map = instance.executionHistories.get(refType);
if (map != null && map.remove(playerName) != null) {
removed = true;
}
}
return removed;
}
/**
* Removes all data and history for a player.
* @deprecated Use clearData instead, this likely to be removed later.
* @param checkType
*/
public static void clear(final CheckType checkType) {
clearData(checkType);
}
/**
* Remove data and history of all players for the given check type and sub checks.
* @param checkType
*/
public static void clearData(final CheckType checkType) {
final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
for (final CheckType type : APIUtils.getWithChildren(checkType)) {
final Map<String, ExecutionHistory> map = instance.executionHistories.get(type);
if (map != null) {
map.clear();
}
final CheckDataFactory factory = type.getDataFactory();
if (factory != null) {
factories.add(factory);
}
}
for (final CheckDataFactory factory : factories) {
factory.removeAllData();
}
for (final IRemoveData rmd : instance.iRemoveData) {
if (checkType == CheckType.ALL) {
// Not sure this is really good, though.
rmd.removeAllData();
}
else if (rmd instanceof IHaveCheckType) {
final CheckType refType = ((IHaveCheckType) rmd).getCheckType();
if (refType == checkType || APIUtils.isParent(checkType, refType)) {
rmd.removeAllData();
}
}
}
ViolationHistory.clear(checkType);
if (checkType == CheckType.ALL) {
instance.playerData.clear(); // TODO
}
}
/**
* Remove data and history of all players for the given check type and sub checks.
* @param checkType
*/
public static void clearData(final CheckType checkType) {
final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
for (final CheckType type : APIUtils.getWithChildren(checkType)){
final Map<String, ExecutionHistory> map = instance.executionHistories.get(type);
if (map != null) map.clear();
final CheckDataFactory factory = type.getDataFactory();
if (factory != null) factories.add(factory);
}
for (final CheckDataFactory factory : factories){
factory.removeAllData();
}
for (final IRemoveData rmd : instance.iRemoveData){
if (checkType == CheckType.ALL){
// Not sure this is really good, though.
rmd.removeAllData();
}
else if (rmd instanceof IHaveCheckType){
final CheckType refType = ((IHaveCheckType) rmd).getCheckType();
if (refType == checkType || APIUtils.isParent(checkType, refType)) rmd.removeAllData();
}
}
ViolationHistory.clear(checkType);
if (checkType == CheckType.ALL){
instance.playerData.clear(); // TODO
}
}
/**
* Remove the player data for a given player and a given check type. CheckType.ALL and null will be interpreted as removing all data.<br>
* @param playerName Exact player name.
* @param checkType Check type to remove data for, null is regarded as ALL.
* @return If any data was present.
*/
public static boolean removeData(final String playerName, CheckType checkType) {
if (checkType == null) checkType = CheckType.ALL;
boolean had = false;
// Check extended registered components.
if (clearComponentData(checkType, playerName)) had = true;
// Collect factories.
final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
for (CheckType otherType : APIUtils.getWithChildren(checkType)){
final CheckDataFactory otherFactory = otherType.getDataFactory();
if (otherFactory != null) factories.add(otherFactory);
}
// Remove data.
for (final CheckDataFactory otherFactory : factories){
if (otherFactory.removeData(playerName) != null) had = true;
}
if (checkType == CheckType.ALL){
instance.playerData.remove(playerName.toLowerCase());
}
return had;
}
/**
* Clear player related data, only for registered components (not execution history, violation history, normal check data).<br>
* That should at least go for chat engine data.
* @param CheckType
* @param PlayerName
* @return If something was removed.
*/
public static boolean clearComponentData(final CheckType checkType, final String PlayerName){
boolean removed = false;
for (final IRemoveData rmd : instance.iRemoveData){
if (checkType == CheckType.ALL){
// Not sure this is really good, though.
if (rmd.removeData(PlayerName) != null) removed = true;
}
else if (rmd instanceof IHaveCheckType){
final CheckType refType = ((IHaveCheckType) rmd).getCheckType();
if (refType == checkType || APIUtils.isParent(checkType, refType)){
if (rmd.removeData(PlayerName) != null) removed = true;
}
}
}
return removed;
}
/**
* Clear all stored (check) config instances.<br>
* This does not cleanup ConfigManager, i.e. stored yml-versions.
*/
public static void clearConfigs() {
// The dirty bit !
BlockBreakConfig.clear();
BlockInteractConfig.clear();
BlockPlaceConfig.clear();
ChatConfig.clear();
CombinedConfig.clear();
FightConfig.clear();
InventoryConfig.clear();
MovingConfig.clear();
}
/**
* This gets an online player by exact player name or lower-case player name only [subject to change].
* @param playerName
* @return
*/
public static Player getPlayerExact(final String playerName){
return instance.onlinePlayers.get(playerName);
}
/**
* This gets the online player with the exact name, but transforms the input to lower case.
* @param playerName
* @return
*/
public static Player getPlayer(final String playerName){
return instance.onlinePlayers.get(playerName.toLowerCase());
}
@Override
public boolean addComponent(IRemoveData obj) {
if (iRemoveData.contains(obj)){
return false;
}
else{
iRemoveData.add((IRemoveData) obj);
return true;
}
}
public static boolean removeData(final String playerName, CheckType checkType) {
if (checkType == null) {
checkType = CheckType.ALL;
}
boolean had = false;
@Override
public void removeComponent(IRemoveData obj) {
iRemoveData.remove((IRemoveData) obj);
}
/**
* Initializing with online players.
*/
public void onEnable(){
final Player[] players = Bukkit.getOnlinePlayers();
for (final Player player : players){
addOnlinePlayer(player);
}
}
/**
* Add mappings for player names variations.
* @param player
*/
private void addOnlinePlayer(final Player player){
final String name = player.getName();
onlinePlayers.put(name, player);
onlinePlayers.put(name.toLowerCase(), player);
}
/**
* Remove mappings for player names variations.
* @param player
*/
private void removeOnlinePlayer(final Player player){
final String name = player.getName();
onlinePlayers.remove(name);
onlinePlayers.remove(name.toLowerCase());
}
/**
* Cleanup method, removes all data and config, but does not call ConfigManager.cleanup.
*/
@Override
public void onDisable() {
clearData(CheckType.ALL);
iRemoveData.clear();
clearConfigs();
lastLogout.clear();
executionHistories.clear();
onlinePlayers.clear();
// Finally alert (summary) if inconsistencies found.
if (foundInconsistencies > 0){
LogUtil.logWarning("[NoCheatPlus] DataMan found " + foundInconsistencies + " inconsistencies (warnings suppressed).");
foundInconsistencies = 0;
}
}
// Check extended registered components.
if (clearComponentData(checkType, playerName)) {
had = true;
}
@Override
public String getComponentName() {
return "NoCheatPlus_DataManager";
}
// Collect factories.
final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
for (CheckType otherType : APIUtils.getWithChildren(checkType)) {
final CheckDataFactory otherFactory = otherType.getDataFactory();
if (otherFactory != null) {
factories.add(otherFactory);
}
}
// Remove data.
for (final CheckDataFactory otherFactory : factories) {
if (otherFactory.removeData(playerName) != null) {
had = true;
}
}
if (checkType == CheckType.ALL) {
instance.playerData.remove(playerName.toLowerCase());
}
return had;
}
/**
* Clear player related data, only for registered components (not execution history, violation history, normal check data).<br>
* That should at least go for chat engine data.
* @param CheckType
* @param PlayerName
* @return If something was removed.
*/
public static boolean clearComponentData(final CheckType checkType, final String PlayerName) {
boolean removed = false;
for (final IRemoveData rmd : instance.iRemoveData) {
if (checkType == CheckType.ALL) {
// Not sure this is really good, though.
if (rmd.removeData(PlayerName) != null) {
removed = true;
}
}
else if (rmd instanceof IHaveCheckType) {
final CheckType refType = ((IHaveCheckType) rmd).getCheckType();
if (refType == checkType || APIUtils.isParent(checkType, refType)) {
if (rmd.removeData(PlayerName) != null) {
removed = true;
}
}
}
}
return removed;
}
/**
* Clear all stored (check) config instances.<br>
* This does not cleanup ConfigManager, i.e. stored yml-versions.
*/
public static void clearConfigs() {
// The dirty bit !
BlockBreakConfig.clear();
BlockInteractConfig.clear();
BlockPlaceConfig.clear();
ChatConfig.clear();
CombinedConfig.clear();
FightConfig.clear();
InventoryConfig.clear();
MovingConfig.clear();
}
/**
* This gets an online player by exact player name or lower-case player name only [subject to change].
* @param playerName
* @return
*/
public static Player getPlayerExact(final String playerName) {
return instance.onlinePlayers.get(playerName);
}
/**
* This gets the online player with the exact name, but transforms the input to lower case.
* @param playerName
* @return
*/
public static Player getPlayer(final String playerName) {
return instance.onlinePlayers.get(playerName.toLowerCase());
}
@Override
public boolean addComponent(IRemoveData obj) {
if (iRemoveData.contains(obj)) {
return false;
}
else {
iRemoveData.add((IRemoveData) obj);
return true;
}
}
@Override
public void removeComponent(IRemoveData obj) {
iRemoveData.remove((IRemoveData) obj);
}
/**
* Initializing with online players.
*/
public void onEnable() {
for (final Player player : Bukkit.getOnlinePlayers()) {
addOnlinePlayer(player);
}
}
/**
* Add mappings for player names variations.
* @param player
*/
private void addOnlinePlayer(final Player player) {
final String name = player.getName();
onlinePlayers.put(name, player);
onlinePlayers.put(name.toLowerCase(), player);
}
/**
* Remove mappings for player names variations.
* @param player
*/
private void removeOnlinePlayer(final Player player) {
final String name = player.getName();
onlinePlayers.remove(name);
onlinePlayers.remove(name.toLowerCase());
}
/**
* Cleanup method, removes all data and config, but does not call ConfigManager.cleanup.
*/
@Override
public void onDisable() {
clearData(CheckType.ALL);
iRemoveData.clear();
clearConfigs();
lastLogout.clear();
executionHistories.clear();
onlinePlayers.clear();
// Finally alert (summary) if inconsistencies found.
if (foundInconsistencies > 0) {
LogUtil.logWarning("[NoCheatPlus] DataMan found " + foundInconsistencies + " inconsistencies (warnings suppressed).");
foundInconsistencies = 0;
}
}
@Override
public String getComponentName() {
return "NoCheatPlus_DataManager";
}
@Override
public void checkConsistency(final Player[] onlinePlayers) {
// Check online player tracking consistency.
int missing = 0;
int changed = 0;
int expectedSize = 0;
for (int i = 0; i < onlinePlayers.length; i++) {
final Player player = onlinePlayers[i];
final String name = player.getName();
// if (player.isOnline()) {
expectedSize += 1 + (name.equals(name.toLowerCase()) ? 0 : 1);
if (!this.onlinePlayers.containsKey(name)) {
missing ++;
// TODO: Add the player [problem: messy NPC plugins?]?
}
if (player != this.onlinePlayers.get(name)) {
changed ++;
// Update the reference.
addOnlinePlayer(player);
// }
}
}
// TODO: Consider checking lastLogout for too long gone players.
final int storedSize = this.onlinePlayers.size();
if (missing != 0 || changed != 0 || expectedSize != storedSize) {
foundInconsistencies ++;
if (!ConfigManager.getConfigFile().getBoolean(ConfPaths.DATA_CONSISTENCYCHECKS_SUPPRESSWARNINGS)) {
final List<String> details = new LinkedList<String>();
if (missing != 0) {
details.add("missing online players (" + missing + ")");
}
if (expectedSize != storedSize) {
// TODO: Consider checking for not online players and remove them.
details.add("wrong number of online players (" + storedSize + " instead of " + expectedSize + ")");
}
if (changed != 0) {
details.add("changed player instances (" + changed + ")");
}
LogUtil.logWarning("[NoCheatPlus] DataMan inconsistencies: " + StringUtil.join(details, " | "));
}
}
}
/**
* Convenience method, also hiding how player data is stored for a Player instance - always creates a PlayerData instance, if not already present.
* @param player
* @return
*/
public static PlayerData getPlayerData(final Player player) {
return getPlayerData(player.getName(), true);
}
/**
*
* @param playerName
* @param create
* @return
*/
public static PlayerData getPlayerData(final String playerName, final boolean create) {
final String lcName = playerName.toLowerCase(); // TODO: Store by both lower case and exact case (also store the Player reference).
final PlayerData data = instance.playerData.get(lcName);
if (data != null) {
return data;
}
else if (!create) {
return null;
}
else {
final PlayerData newData = new PlayerData(lcName);
instance.playerData.put(lcName, newData);
return newData;
}
}
@Override
public void checkConsistency(final Player[] onlinePlayers) {
// Check online player tracking consistency.
int missing = 0;
int changed = 0;
int expectedSize = 0;
for (int i = 0; i < onlinePlayers.length; i++){
final Player player = onlinePlayers[i];
final String name = player.getName();
// if (player.isOnline()){
expectedSize += 1 + (name.equals(name.toLowerCase()) ? 0 : 1);
if (!this.onlinePlayers.containsKey(name)){
missing ++;
// TODO: Add the player [problem: messy NPC plugins?]?
}
if (player != this.onlinePlayers.get(name)){
changed ++;
// Update the reference.
addOnlinePlayer(player);
// }
}
}
// TODO: Consider checking lastLogout for too long gone players.
final int storedSize = this.onlinePlayers.size();
if (missing != 0 || changed != 0 || expectedSize != storedSize){
foundInconsistencies ++;
if (!ConfigManager.getConfigFile().getBoolean(ConfPaths.DATA_CONSISTENCYCHECKS_SUPPRESSWARNINGS)){
final List<String> details = new LinkedList<String>();
if (missing != 0){
details.add("missing online players (" + missing + ")");
}
if (expectedSize != storedSize){
// TODO: Consider checking for not online players and remove them.
details.add("wrong number of online players (" + storedSize + " instead of " + expectedSize + ")");
}
if (changed != 0){
details.add("changed player instances (" + changed + ")");
}
LogUtil.logWarning("[NoCheatPlus] DataMan inconsistencies: " + StringUtil.join(details, " | "));
}
}
}
/**
* Convenience method, also hiding how player data is stored for a Player instance - always creates a PlayerData instance, if not already present.
* @param player
* @return
*/
public static PlayerData getPlayerData(final Player player) {
return getPlayerData(player.getName(), true);
}
/**
*
* @param playerName
* @param create
* @return
*/
public static PlayerData getPlayerData(final String playerName, final boolean create){
final String lcName = playerName.toLowerCase(); // TODO: Store by both lower case and exact case (also store the Player reference).
final PlayerData data = instance.playerData.get(lcName);
if (data != null) return data;
else if (!create){
return null;
}
else{
final PlayerData newData = new PlayerData(lcName);
instance.playerData.put(lcName, newData);
return newData;
}
}
}

View File

@ -28,87 +28,87 @@ import fr.neatmonster.nocheatplus.components.IData;
*
*/
public class PlayerData implements IData {
public static final String TAG_NOTIFY_OFF = "notify_off";
public final PlayerTask task;
/** Not sure this is the future of extra properties. */
protected Set<String> tags = null;
/** Lower case name of the player. */
final String lcName;
/**
*
* @param playerName Accurate case not (yet) demanded.
*/
public PlayerData(final String playerName){
this.lcName = playerName.toLowerCase();
this.task = new PlayerTask(this.lcName);
}
/**
* Test if present.
* @param tag
* @return
*/
public boolean hasTag(final String tag){
return tags != null && tags.contains(tag);
}
/**
* Add the tag.
* @param tag
*/
public void addTag(final String tag){
if (tags == null){
tags = new HashSet<String>();
}
tags.add(tag);
}
/**
* Remove the tag.
* @param tag
*/
public void removeTag(final String tag) {
if (tags != null){
tags.remove(tag);
if (tags.isEmpty()){
tags = null;
}
}
}
/**
* Add tag or remove tag, based on arguments.
* @param tag
* @param add The tag will be added, if set to true. If set to false, the tag will be removed.
*/
public void setTag(final String tag, final boolean add){
if (add){
addTag(tag);
}
else{
removeTag(tag);
}
}
/**
* Check if notifications are turned off, this does not bypass permission checks.
* @return
*/
public boolean getNotifyOff(){
return hasTag(TAG_NOTIFY_OFF);
}
/**
* Allow or turn off notifications. A player must have the admin.notify permission to receive notifications.
* @param notifyOff set to true to turn off notifications.
*/
public void setNotifyOff(final boolean notifyOff){
setTag(TAG_NOTIFY_OFF, notifyOff);
}
public static final String TAG_NOTIFY_OFF = "notify_off";
public final PlayerTask task;
/** Not sure this is the future of extra properties. */
protected Set<String> tags = null;
/** Lower case name of the player. */
final String lcName;
/**
*
* @param playerName Accurate case not (yet) demanded.
*/
public PlayerData(final String playerName) {
this.lcName = playerName.toLowerCase();
this.task = new PlayerTask(this.lcName);
}
/**
* Test if present.
* @param tag
* @return
*/
public boolean hasTag(final String tag) {
return tags != null && tags.contains(tag);
}
/**
* Add the tag.
* @param tag
*/
public void addTag(final String tag) {
if (tags == null) {
tags = new HashSet<String>();
}
tags.add(tag);
}
/**
* Remove the tag.
* @param tag
*/
public void removeTag(final String tag) {
if (tags != null) {
tags.remove(tag);
if (tags.isEmpty()) {
tags = null;
}
}
}
/**
* Add tag or remove tag, based on arguments.
* @param tag
* @param add The tag will be added, if set to true. If set to false, the tag will be removed.
*/
public void setTag(final String tag, final boolean add) {
if (add) {
addTag(tag);
}
else {
removeTag(tag);
}
}
/**
* Check if notifications are turned off, this does not bypass permission checks.
* @return
*/
public boolean getNotifyOff() {
return hasTag(TAG_NOTIFY_OFF);
}
/**
* Allow or turn off notifications. A player must have the admin.notify permission to receive notifications.
* @param notifyOff set to true to turn off notifications.
*/
public void setNotifyOff(final boolean notifyOff) {
setTag(TAG_NOTIFY_OFF, notifyOff);
}
}