NoCheatPlus/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Text.java

347 lines
14 KiB
Java
Raw Normal View History

/*
* 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.checks.chat;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.chat.analysis.MessageLetterCount;
import fr.neatmonster.nocheatplus.checks.chat.analysis.WordLetterCount;
import fr.neatmonster.nocheatplus.checks.chat.analysis.engine.LetterEngine;
import fr.neatmonster.nocheatplus.checks.combined.CombinedData;
import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
import fr.neatmonster.nocheatplus.components.registry.feature.INotifyReload;
import fr.neatmonster.nocheatplus.config.ConfigFile;
import fr.neatmonster.nocheatplus.config.ConfigManager;
[BROKEN] Data storage overhaul (basics). (+) (SAFETY COMMIT) Largely breaking change. * Interfaces in front of data types (and 'managers'), some interfaces removed. * Data and configuration fetching. * Check activation checking (config flags, isEnabled, hasBypass). * CheckType (activation checks, factories removed). * Lots of collateral signature changes, including IPlayerData. The (I)WorldDataManager stores per-world data (+ per world per check type). * Raw configurations. * Typical flags: check activation, debug, lag adaption. * Generic data, such as check configurations or per world check data. The (I)PlayerDataManager stores per player data. * Check Data. * Typical flags: debug * Exemption * Check data (and config cache). * Further mappings and later OfflinePlayerData. * The registration interface will allow defining, how instances are handled for registered types (factory, proxy, what on world change, what on logout, global removal handler, per player removal handler). (I)PlayerData is intended to be/become the central access point. * External interface is IPlayerData now. * Per player debug flags, exemptions. * Fetching configuration and data: local cache, relaying fetching to registered factories and proxy-registries/storage (e.g. fetching configuration from per world storage). Other fixes/changes: (+) Extend the debug player command (set true/false, reset to world default, arbitrary check types). (+) PlayerData maintains a currentWorldIdentifier (to be used instead of ChatData in future). (+) The WorldConfigProvider getAll implementation returns a LinkedHashSet now, avoiding duplicates. (+) Move DefaultGenericInstanceRegistry to NCPCore. (+) Thread-safety considerations for DefaultGenericInstanceRegistry. (+) Don't log errors on hasBypass checking. TBD: Instead intercept during listener methods (or even as a feature within the listener node: e.g. @ThreadContext(primaryThread=true, skipOffContext=true, cancelOffContext=true). (+) Add fight.wrongturn permissions to plugin.yml. (+) Missing GPLv3 headers. Broken/Missing: * WorldData inheritance from default: propagate all changes done directly to the default config to children (all worlds that don't have an explicit world_config.yml set) - possibly add an OverrideState or similar, (NONE, FROM_DEFAULT, EXPLICIT) and don't override EXPLICIT if coming from the default. Calling override on the default WorldData is not to be confused with calling override for WorldDataManager (override for all worlds as EXPLICIT). * Organize overriding for special circumstances (version dependent activation and the like). Might want to add registered override handlers to be called on reload automatically. * Store generic per check type per world data in the WorldDataManager, such as configurations and per-world check data. TBD: Factories, cleanup (!). * Most efficient referencing (IWorldCheckTypeNode, IHandle<something>?). * All the registry stuff (see PlayerData). * Use interfaces for auto registry (and a flag within RegistrationContext?) - world unload, world change, player join / leave. * (Data expiration handling including transition to IOfflinePlayerData, because now data is a little heavier.) * Further details.
2018-02-13 15:15:23 +01:00
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.ColorUtil;
import fr.neatmonster.nocheatplus.utilities.StringUtil;
/**
* Some alternative more or less advanced analysis methods.
* @author mc_dev
*
*/
public class Text extends Check implements INotifyReload {
2014-11-04 00:20:18 +01:00
private LetterEngine engine = null;
/** Not really cancelled but above threshold for actions. */
private String lastCancelledMessage = "";
private long lastCancelledTime = 0;
private String lastGlobalMessage = "";
private long lastGlobalTime = 0;
public Text() {
super(CheckType.CHAT_TEXT);
init();
}
/**
* Start analysis.
* @param player
* The player who issued the message.
* @param message
* The message to check.
* @param captcha
* Used for starting captcha on failure, if configured so.
* @param alreadyCancelled
* @return
*/
[BLEEDING][BREAKING][INSTABLE] Swiftly throw in permission caching. Benefits: * Improves performance, where permission lookup has major impact, with timeout based lookup, static permissions (skip permission check entirely), and world/offline based invalidation. (Once fully implemented.) * Hopefully more efficient: use Bukkit Permission for faster defaults. * (Allows control over how which permission is to be updated/invalidated, which is useful per se.) Risks: * Complex changes yield bugs. * Other plugins depending on NCP might break. * Cache incoherence might happen (permissions are changed dynamically +- unintended malconfiguration, or in case of bugs). * (Endless loops certainly have all been fixed.) Breaking: * Lots of more or less internal API has been changed or removed: Check, CheckType, CheckUtils, TickTask, ... * Permission checking behavior has been altered. Rough points: * Implement a permission cache within PlayerData. * Remove the player tasks and permission updates in favour of handling those within DataManager and PlayerData. * Adjust everything else to it (partly TBD). * Updating sets of permissions (e.g. for CHAT) is done more lazily now, i.e. one per 10 ticks). An actual permission check would still yield an update next tick (asynchronous). * Fixed/extended random spots (DualCollection, MiniListener registration support, StringUtil). Missing: * Basic implementation * Cleanup after logout (stages: 1. non-essential like permissions, 2. unrecoverable like set-back location, 3. complete data removal). * Coverage * Might have missed spots. * NoCheatPlus.nameSetPerms should be replaced by caching + default config for world-wise updating. * Command permissions are always checked. At least for players, cache based lookup should get implemented. * More unit tests. * Extended configurability: Per-world settings/policies. * Efficiency * Not all parts of the implementation are 100%/optimal yet.
2018-01-28 18:52:51 +01:00
public boolean check(final Player player, final String message,
[BROKEN] Data storage overhaul (basics). (+) (SAFETY COMMIT) Largely breaking change. * Interfaces in front of data types (and 'managers'), some interfaces removed. * Data and configuration fetching. * Check activation checking (config flags, isEnabled, hasBypass). * CheckType (activation checks, factories removed). * Lots of collateral signature changes, including IPlayerData. The (I)WorldDataManager stores per-world data (+ per world per check type). * Raw configurations. * Typical flags: check activation, debug, lag adaption. * Generic data, such as check configurations or per world check data. The (I)PlayerDataManager stores per player data. * Check Data. * Typical flags: debug * Exemption * Check data (and config cache). * Further mappings and later OfflinePlayerData. * The registration interface will allow defining, how instances are handled for registered types (factory, proxy, what on world change, what on logout, global removal handler, per player removal handler). (I)PlayerData is intended to be/become the central access point. * External interface is IPlayerData now. * Per player debug flags, exemptions. * Fetching configuration and data: local cache, relaying fetching to registered factories and proxy-registries/storage (e.g. fetching configuration from per world storage). Other fixes/changes: (+) Extend the debug player command (set true/false, reset to world default, arbitrary check types). (+) PlayerData maintains a currentWorldIdentifier (to be used instead of ChatData in future). (+) The WorldConfigProvider getAll implementation returns a LinkedHashSet now, avoiding duplicates. (+) Move DefaultGenericInstanceRegistry to NCPCore. (+) Thread-safety considerations for DefaultGenericInstanceRegistry. (+) Don't log errors on hasBypass checking. TBD: Instead intercept during listener methods (or even as a feature within the listener node: e.g. @ThreadContext(primaryThread=true, skipOffContext=true, cancelOffContext=true). (+) Add fight.wrongturn permissions to plugin.yml. (+) Missing GPLv3 headers. Broken/Missing: * WorldData inheritance from default: propagate all changes done directly to the default config to children (all worlds that don't have an explicit world_config.yml set) - possibly add an OverrideState or similar, (NONE, FROM_DEFAULT, EXPLICIT) and don't override EXPLICIT if coming from the default. Calling override on the default WorldData is not to be confused with calling override for WorldDataManager (override for all worlds as EXPLICIT). * Organize overriding for special circumstances (version dependent activation and the like). Might want to add registered override handlers to be called on reload automatically. * Store generic per check type per world data in the WorldDataManager, such as configurations and per-world check data. TBD: Factories, cleanup (!). * Most efficient referencing (IWorldCheckTypeNode, IHandle<something>?). * All the registry stuff (see PlayerData). * Use interfaces for auto registry (and a flag within RegistrationContext?) - world unload, world change, player join / leave. * (Data expiration handling including transition to IOfflinePlayerData, because now data is a little heavier.) * Further details.
2018-02-13 15:15:23 +01:00
final ChatConfig cc, final IPlayerData pData,
[BLEEDING][BREAKING][INSTABLE] Swiftly throw in permission caching. Benefits: * Improves performance, where permission lookup has major impact, with timeout based lookup, static permissions (skip permission check entirely), and world/offline based invalidation. (Once fully implemented.) * Hopefully more efficient: use Bukkit Permission for faster defaults. * (Allows control over how which permission is to be updated/invalidated, which is useful per se.) Risks: * Complex changes yield bugs. * Other plugins depending on NCP might break. * Cache incoherence might happen (permissions are changed dynamically +- unintended malconfiguration, or in case of bugs). * (Endless loops certainly have all been fixed.) Breaking: * Lots of more or less internal API has been changed or removed: Check, CheckType, CheckUtils, TickTask, ... * Permission checking behavior has been altered. Rough points: * Implement a permission cache within PlayerData. * Remove the player tasks and permission updates in favour of handling those within DataManager and PlayerData. * Adjust everything else to it (partly TBD). * Updating sets of permissions (e.g. for CHAT) is done more lazily now, i.e. one per 10 ticks). An actual permission check would still yield an update next tick (asynchronous). * Fixed/extended random spots (DualCollection, MiniListener registration support, StringUtil). Missing: * Basic implementation * Cleanup after logout (stages: 1. non-essential like permissions, 2. unrecoverable like set-back location, 3. complete data removal). * Coverage * Might have missed spots. * NoCheatPlus.nameSetPerms should be replaced by caching + default config for world-wise updating. * Command permissions are always checked. At least for players, cache based lookup should get implemented. * More unit tests. * Extended configurability: Per-world settings/policies. * Efficiency * Not all parts of the implementation are 100%/optimal yet.
2018-01-28 18:52:51 +01:00
final ICaptcha captcha, boolean isMainThread, final boolean alreadyCancelled) {
[BROKEN] Data storage overhaul (basics). (+) (SAFETY COMMIT) Largely breaking change. * Interfaces in front of data types (and 'managers'), some interfaces removed. * Data and configuration fetching. * Check activation checking (config flags, isEnabled, hasBypass). * CheckType (activation checks, factories removed). * Lots of collateral signature changes, including IPlayerData. The (I)WorldDataManager stores per-world data (+ per world per check type). * Raw configurations. * Typical flags: check activation, debug, lag adaption. * Generic data, such as check configurations or per world check data. The (I)PlayerDataManager stores per player data. * Check Data. * Typical flags: debug * Exemption * Check data (and config cache). * Further mappings and later OfflinePlayerData. * The registration interface will allow defining, how instances are handled for registered types (factory, proxy, what on world change, what on logout, global removal handler, per player removal handler). (I)PlayerData is intended to be/become the central access point. * External interface is IPlayerData now. * Per player debug flags, exemptions. * Fetching configuration and data: local cache, relaying fetching to registered factories and proxy-registries/storage (e.g. fetching configuration from per world storage). Other fixes/changes: (+) Extend the debug player command (set true/false, reset to world default, arbitrary check types). (+) PlayerData maintains a currentWorldIdentifier (to be used instead of ChatData in future). (+) The WorldConfigProvider getAll implementation returns a LinkedHashSet now, avoiding duplicates. (+) Move DefaultGenericInstanceRegistry to NCPCore. (+) Thread-safety considerations for DefaultGenericInstanceRegistry. (+) Don't log errors on hasBypass checking. TBD: Instead intercept during listener methods (or even as a feature within the listener node: e.g. @ThreadContext(primaryThread=true, skipOffContext=true, cancelOffContext=true). (+) Add fight.wrongturn permissions to plugin.yml. (+) Missing GPLv3 headers. Broken/Missing: * WorldData inheritance from default: propagate all changes done directly to the default config to children (all worlds that don't have an explicit world_config.yml set) - possibly add an OverrideState or similar, (NONE, FROM_DEFAULT, EXPLICIT) and don't override EXPLICIT if coming from the default. Calling override on the default WorldData is not to be confused with calling override for WorldDataManager (override for all worlds as EXPLICIT). * Organize overriding for special circumstances (version dependent activation and the like). Might want to add registered override handlers to be called on reload automatically. * Store generic per check type per world data in the WorldDataManager, such as configurations and per-world check data. TBD: Factories, cleanup (!). * Most efficient referencing (IWorldCheckTypeNode, IHandle<something>?). * All the registry stuff (see PlayerData). * Use interfaces for auto registry (and a flag within RegistrationContext?) - world unload, world change, player join / leave. * (Data expiration handling including transition to IOfflinePlayerData, because now data is a little heavier.) * Further details.
2018-02-13 15:15:23 +01:00
final ChatData data = pData.getGenericInstance(ChatData.class);
2014-11-04 00:20:18 +01:00
synchronized (data) {
[BLEEDING][BREAKING][INSTABLE] Swiftly throw in permission caching. Benefits: * Improves performance, where permission lookup has major impact, with timeout based lookup, static permissions (skip permission check entirely), and world/offline based invalidation. (Once fully implemented.) * Hopefully more efficient: use Bukkit Permission for faster defaults. * (Allows control over how which permission is to be updated/invalidated, which is useful per se.) Risks: * Complex changes yield bugs. * Other plugins depending on NCP might break. * Cache incoherence might happen (permissions are changed dynamically +- unintended malconfiguration, or in case of bugs). * (Endless loops certainly have all been fixed.) Breaking: * Lots of more or less internal API has been changed or removed: Check, CheckType, CheckUtils, TickTask, ... * Permission checking behavior has been altered. Rough points: * Implement a permission cache within PlayerData. * Remove the player tasks and permission updates in favour of handling those within DataManager and PlayerData. * Adjust everything else to it (partly TBD). * Updating sets of permissions (e.g. for CHAT) is done more lazily now, i.e. one per 10 ticks). An actual permission check would still yield an update next tick (asynchronous). * Fixed/extended random spots (DualCollection, MiniListener registration support, StringUtil). Missing: * Basic implementation * Cleanup after logout (stages: 1. non-essential like permissions, 2. unrecoverable like set-back location, 3. complete data removal). * Coverage * Might have missed spots. * NoCheatPlus.nameSetPerms should be replaced by caching + default config for world-wise updating. * Command permissions are always checked. At least for players, cache based lookup should get implemented. * More unit tests. * Extended configurability: Per-world settings/policies. * Efficiency * Not all parts of the implementation are 100%/optimal yet.
2018-01-28 18:52:51 +01:00
return unsafeCheck(player, message, captcha, cc, data, pData, isMainThread, alreadyCancelled);
2014-11-04 00:20:18 +01:00
}
}
private void init() {
// Set some things from the global config.
final ConfigFile config = ConfigManager.getConfigFile();
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
if (engine != null) {
engine.clear();
api.removeComponent(engine);
}
engine = new LetterEngine(config);
api.addComponent(engine);
}
@Override
public void onReload() {
synchronized(engine) {
engine.clear();
}
init();
}
/**
* Check without further synchronization.
* @param player
* @param message
* @param captcha
* @param cc
* @param data
* @param isMainThread
* @param alreadyCancelled
* @return
*/
private boolean unsafeCheck(final Player player, final String message, final ICaptcha captcha,
[BROKEN] Data storage overhaul (basics). (+) (SAFETY COMMIT) Largely breaking change. * Interfaces in front of data types (and 'managers'), some interfaces removed. * Data and configuration fetching. * Check activation checking (config flags, isEnabled, hasBypass). * CheckType (activation checks, factories removed). * Lots of collateral signature changes, including IPlayerData. The (I)WorldDataManager stores per-world data (+ per world per check type). * Raw configurations. * Typical flags: check activation, debug, lag adaption. * Generic data, such as check configurations or per world check data. The (I)PlayerDataManager stores per player data. * Check Data. * Typical flags: debug * Exemption * Check data (and config cache). * Further mappings and later OfflinePlayerData. * The registration interface will allow defining, how instances are handled for registered types (factory, proxy, what on world change, what on logout, global removal handler, per player removal handler). (I)PlayerData is intended to be/become the central access point. * External interface is IPlayerData now. * Per player debug flags, exemptions. * Fetching configuration and data: local cache, relaying fetching to registered factories and proxy-registries/storage (e.g. fetching configuration from per world storage). Other fixes/changes: (+) Extend the debug player command (set true/false, reset to world default, arbitrary check types). (+) PlayerData maintains a currentWorldIdentifier (to be used instead of ChatData in future). (+) The WorldConfigProvider getAll implementation returns a LinkedHashSet now, avoiding duplicates. (+) Move DefaultGenericInstanceRegistry to NCPCore. (+) Thread-safety considerations for DefaultGenericInstanceRegistry. (+) Don't log errors on hasBypass checking. TBD: Instead intercept during listener methods (or even as a feature within the listener node: e.g. @ThreadContext(primaryThread=true, skipOffContext=true, cancelOffContext=true). (+) Add fight.wrongturn permissions to plugin.yml. (+) Missing GPLv3 headers. Broken/Missing: * WorldData inheritance from default: propagate all changes done directly to the default config to children (all worlds that don't have an explicit world_config.yml set) - possibly add an OverrideState or similar, (NONE, FROM_DEFAULT, EXPLICIT) and don't override EXPLICIT if coming from the default. Calling override on the default WorldData is not to be confused with calling override for WorldDataManager (override for all worlds as EXPLICIT). * Organize overriding for special circumstances (version dependent activation and the like). Might want to add registered override handlers to be called on reload automatically. * Store generic per check type per world data in the WorldDataManager, such as configurations and per-world check data. TBD: Factories, cleanup (!). * Most efficient referencing (IWorldCheckTypeNode, IHandle<something>?). * All the registry stuff (see PlayerData). * Use interfaces for auto registry (and a flag within RegistrationContext?) - world unload, world change, player join / leave. * (Data expiration handling including transition to IOfflinePlayerData, because now data is a little heavier.) * Further details.
2018-02-13 15:15:23 +01:00
final ChatConfig cc, final ChatData data, final IPlayerData pData,
[BLEEDING][BREAKING][INSTABLE] Swiftly throw in permission caching. Benefits: * Improves performance, where permission lookup has major impact, with timeout based lookup, static permissions (skip permission check entirely), and world/offline based invalidation. (Once fully implemented.) * Hopefully more efficient: use Bukkit Permission for faster defaults. * (Allows control over how which permission is to be updated/invalidated, which is useful per se.) Risks: * Complex changes yield bugs. * Other plugins depending on NCP might break. * Cache incoherence might happen (permissions are changed dynamically +- unintended malconfiguration, or in case of bugs). * (Endless loops certainly have all been fixed.) Breaking: * Lots of more or less internal API has been changed or removed: Check, CheckType, CheckUtils, TickTask, ... * Permission checking behavior has been altered. Rough points: * Implement a permission cache within PlayerData. * Remove the player tasks and permission updates in favour of handling those within DataManager and PlayerData. * Adjust everything else to it (partly TBD). * Updating sets of permissions (e.g. for CHAT) is done more lazily now, i.e. one per 10 ticks). An actual permission check would still yield an update next tick (asynchronous). * Fixed/extended random spots (DualCollection, MiniListener registration support, StringUtil). Missing: * Basic implementation * Cleanup after logout (stages: 1. non-essential like permissions, 2. unrecoverable like set-back location, 3. complete data removal). * Coverage * Might have missed spots. * NoCheatPlus.nameSetPerms should be replaced by caching + default config for world-wise updating. * Command permissions are always checked. At least for players, cache based lookup should get implemented. * More unit tests. * Extended configurability: Per-world settings/policies. * Efficiency * Not all parts of the implementation are 100%/optimal yet.
2018-01-28 18:52:51 +01:00
boolean isMainThread, final boolean alreadyCancelled) {
2014-11-04 00:20:18 +01:00
// Test captcha.
// TODO: Skip captcha for "handleaschat" commands? [controversial potential]
[BLEEDING][BREAKING][INSTABLE] Swiftly throw in permission caching. Benefits: * Improves performance, where permission lookup has major impact, with timeout based lookup, static permissions (skip permission check entirely), and world/offline based invalidation. (Once fully implemented.) * Hopefully more efficient: use Bukkit Permission for faster defaults. * (Allows control over how which permission is to be updated/invalidated, which is useful per se.) Risks: * Complex changes yield bugs. * Other plugins depending on NCP might break. * Cache incoherence might happen (permissions are changed dynamically +- unintended malconfiguration, or in case of bugs). * (Endless loops certainly have all been fixed.) Breaking: * Lots of more or less internal API has been changed or removed: Check, CheckType, CheckUtils, TickTask, ... * Permission checking behavior has been altered. Rough points: * Implement a permission cache within PlayerData. * Remove the player tasks and permission updates in favour of handling those within DataManager and PlayerData. * Adjust everything else to it (partly TBD). * Updating sets of permissions (e.g. for CHAT) is done more lazily now, i.e. one per 10 ticks). An actual permission check would still yield an update next tick (asynchronous). * Fixed/extended random spots (DualCollection, MiniListener registration support, StringUtil). Missing: * Basic implementation * Cleanup after logout (stages: 1. non-essential like permissions, 2. unrecoverable like set-back location, 3. complete data removal). * Coverage * Might have missed spots. * NoCheatPlus.nameSetPerms should be replaced by caching + default config for world-wise updating. * Command permissions are always checked. At least for players, cache based lookup should get implemented. * More unit tests. * Extended configurability: Per-world settings/policies. * Efficiency * Not all parts of the implementation are 100%/optimal yet.
2018-01-28 18:52:51 +01:00
if (captcha.shouldCheckCaptcha(player, cc, data, pData)) {
2014-11-04 00:20:18 +01:00
captcha.checkCaptcha(player, message, cc, data, isMainThread);
return true;
} else if (alreadyCancelled) {
// Skip checking.
return true;
}
// Take time once:
final long time = System.currentTimeMillis();
final String lcMessage = message.trim().toLowerCase();
boolean cancel = false;
[BROKEN] Data storage overhaul (basics). (+) (SAFETY COMMIT) Largely breaking change. * Interfaces in front of data types (and 'managers'), some interfaces removed. * Data and configuration fetching. * Check activation checking (config flags, isEnabled, hasBypass). * CheckType (activation checks, factories removed). * Lots of collateral signature changes, including IPlayerData. The (I)WorldDataManager stores per-world data (+ per world per check type). * Raw configurations. * Typical flags: check activation, debug, lag adaption. * Generic data, such as check configurations or per world check data. The (I)PlayerDataManager stores per player data. * Check Data. * Typical flags: debug * Exemption * Check data (and config cache). * Further mappings and later OfflinePlayerData. * The registration interface will allow defining, how instances are handled for registered types (factory, proxy, what on world change, what on logout, global removal handler, per player removal handler). (I)PlayerData is intended to be/become the central access point. * External interface is IPlayerData now. * Per player debug flags, exemptions. * Fetching configuration and data: local cache, relaying fetching to registered factories and proxy-registries/storage (e.g. fetching configuration from per world storage). Other fixes/changes: (+) Extend the debug player command (set true/false, reset to world default, arbitrary check types). (+) PlayerData maintains a currentWorldIdentifier (to be used instead of ChatData in future). (+) The WorldConfigProvider getAll implementation returns a LinkedHashSet now, avoiding duplicates. (+) Move DefaultGenericInstanceRegistry to NCPCore. (+) Thread-safety considerations for DefaultGenericInstanceRegistry. (+) Don't log errors on hasBypass checking. TBD: Instead intercept during listener methods (or even as a feature within the listener node: e.g. @ThreadContext(primaryThread=true, skipOffContext=true, cancelOffContext=true). (+) Add fight.wrongturn permissions to plugin.yml. (+) Missing GPLv3 headers. Broken/Missing: * WorldData inheritance from default: propagate all changes done directly to the default config to children (all worlds that don't have an explicit world_config.yml set) - possibly add an OverrideState or similar, (NONE, FROM_DEFAULT, EXPLICIT) and don't override EXPLICIT if coming from the default. Calling override on the default WorldData is not to be confused with calling override for WorldDataManager (override for all worlds as EXPLICIT). * Organize overriding for special circumstances (version dependent activation and the like). Might want to add registered override handlers to be called on reload automatically. * Store generic per check type per world data in the WorldDataManager, such as configurations and per-world check data. TBD: Factories, cleanup (!). * Most efficient referencing (IWorldCheckTypeNode, IHandle<something>?). * All the registry stuff (see PlayerData). * Use interfaces for auto registry (and a flag within RegistrationContext?) - world unload, world change, player join / leave. * (Data expiration handling including transition to IOfflinePlayerData, because now data is a little heavier.) * Further details.
2018-02-13 15:15:23 +01:00
final boolean debug = pData.isDebugActive(type);
2014-11-04 00:20:18 +01:00
final List<String> debugParts;
if (debug) {
debugParts = new LinkedList<String>();
debugParts.add("Message (length=" + message.length()+"): ");
2014-11-04 00:20:18 +01:00
}
else debugParts = null;
// Update the frequency interval weights.
data.chatFrequency.update(time);
// Score for this message (violation score).
float score = 0;
final MessageLetterCount letterCounts = new MessageLetterCount(message);
final int msgLen = message.length();
// (Following: random/made up criteria.)
// TODO: Create tests for all methods with wordlists, fake chat (refactor for that).
// Full message processing. ------------
// Upper case.
if (letterCounts.fullCount.upperCase > msgLen / 3) {
// TODO: Regard chunks of 48 or so letters of the message for this?
2014-11-04 00:20:18 +01:00
final float wUpperCase = 0.6f * letterCounts.fullCount.getUpperCaseRatio();
score += wUpperCase * cc.textMessageUpperCase;
}
// Letters vs. word length.
if (msgLen > 4) {
final float fullRep = letterCounts.fullCount.getLetterCountRatio();
// Long messages: very small and very big are bad !
/*
* TODO: 128 is a quick attempt to make one long message possible on
* 1.11.
*/
final float wRepetition = (float) Math.min(msgLen, 128) / 15.0f * Math.abs(0.5f - fullRep);
2014-11-04 00:20:18 +01:00
score += wRepetition * cc.textMessageLetterCount;
// Number of words vs. length of message
final float fnWords = (float) letterCounts.words.length / (float) msgLen;
if (fnWords > 0.75f) { // TODO: balance or configure or remove ?
score += fnWords * cc.textMessagePartition;
}
}
[BROKEN] Data storage overhaul (basics). (+) (SAFETY COMMIT) Largely breaking change. * Interfaces in front of data types (and 'managers'), some interfaces removed. * Data and configuration fetching. * Check activation checking (config flags, isEnabled, hasBypass). * CheckType (activation checks, factories removed). * Lots of collateral signature changes, including IPlayerData. The (I)WorldDataManager stores per-world data (+ per world per check type). * Raw configurations. * Typical flags: check activation, debug, lag adaption. * Generic data, such as check configurations or per world check data. The (I)PlayerDataManager stores per player data. * Check Data. * Typical flags: debug * Exemption * Check data (and config cache). * Further mappings and later OfflinePlayerData. * The registration interface will allow defining, how instances are handled for registered types (factory, proxy, what on world change, what on logout, global removal handler, per player removal handler). (I)PlayerData is intended to be/become the central access point. * External interface is IPlayerData now. * Per player debug flags, exemptions. * Fetching configuration and data: local cache, relaying fetching to registered factories and proxy-registries/storage (e.g. fetching configuration from per world storage). Other fixes/changes: (+) Extend the debug player command (set true/false, reset to world default, arbitrary check types). (+) PlayerData maintains a currentWorldIdentifier (to be used instead of ChatData in future). (+) The WorldConfigProvider getAll implementation returns a LinkedHashSet now, avoiding duplicates. (+) Move DefaultGenericInstanceRegistry to NCPCore. (+) Thread-safety considerations for DefaultGenericInstanceRegistry. (+) Don't log errors on hasBypass checking. TBD: Instead intercept during listener methods (or even as a feature within the listener node: e.g. @ThreadContext(primaryThread=true, skipOffContext=true, cancelOffContext=true). (+) Add fight.wrongturn permissions to plugin.yml. (+) Missing GPLv3 headers. Broken/Missing: * WorldData inheritance from default: propagate all changes done directly to the default config to children (all worlds that don't have an explicit world_config.yml set) - possibly add an OverrideState or similar, (NONE, FROM_DEFAULT, EXPLICIT) and don't override EXPLICIT if coming from the default. Calling override on the default WorldData is not to be confused with calling override for WorldDataManager (override for all worlds as EXPLICIT). * Organize overriding for special circumstances (version dependent activation and the like). Might want to add registered override handlers to be called on reload automatically. * Store generic per check type per world data in the WorldDataManager, such as configurations and per-world check data. TBD: Factories, cleanup (!). * Most efficient referencing (IWorldCheckTypeNode, IHandle<something>?). * All the registry stuff (see PlayerData). * Use interfaces for auto registry (and a flag within RegistrationContext?) - world unload, world change, player join / leave. * (Data expiration handling including transition to IOfflinePlayerData, because now data is a little heavier.) * Further details.
2018-02-13 15:15:23 +01:00
final CombinedData cData = pData.getGenericInstance(CombinedData.class);
2014-11-04 00:20:18 +01:00
final long timeout = 8000; // TODO: maybe set dynamically in data.
// Repetition of last message.
if (cc.textMsgRepeatSelf != 0f && time - data.chatLastTime < timeout) {
if (StringUtil.isSimilar(lcMessage, data.chatLastMessage, 0.8f)) {
final float timeWeight = (float) (timeout - (time - data.chatLastTime)) / (float) timeout;
score += cc.textMsgRepeatSelf * timeWeight;
}
}
// Repetition of last global message.
if (cc.textMsgRepeatGlobal != 0f && time - lastGlobalTime < timeout) {
if (StringUtil.isSimilar(lcMessage, lastGlobalMessage, 0.8f)) {
final float timeWeight = (float) (timeout - (time - lastGlobalTime)) / (float) timeout;
score += cc.textMsgRepeatGlobal * timeWeight;
}
}
// Repetition of last cancelled message.
2014-11-04 00:20:18 +01:00
if (cc.textMsgRepeatCancel != 0f && time - lastCancelledTime < timeout) {
if (StringUtil.isSimilar(lcMessage, lastCancelledMessage, 0.8f)) {
final float timeWeight = (float) (timeout - (time - lastCancelledTime)) / (float) timeout;
score += cc.textMsgRepeatCancel * timeWeight;
}
}
// Chat quickly after join.
if (cc.textMsgAfterJoin != 0f && time - cData.lastJoinTime < timeout) {
final float timeWeight = (float) (timeout - (time - cData.lastJoinTime)) / (float) timeout;
score += cc.textMsgAfterJoin * timeWeight;
}
// Chat without moving.
if (cc.textMsgNoMoving != 0f && time - cData.lastMoveTime > timeout) {
score += cc.textMsgNoMoving;
}
2014-11-04 00:20:18 +01:00
// Per word checks. -------------------
float wWords = 0.0f;
final float avwLen = (float) msgLen / (float) letterCounts.words.length;
for (final WordLetterCount word: letterCounts.words) {
float wWord = 0.0f;
final int wLen = word.word.length();
// TODO: ? used letters vs. word length.
// Length of word vs. av. word length.
final float fLenAv = Math.abs(avwLen - (float) wLen) / avwLen;
wWord += fLenAv * cc.textMessageLengthAv;
// Length of word vs. message length;
final float fLenMsg = (float) wLen / (float) msgLen;
wWord += fLenMsg * cc.textMessageLengthMsg;
// Not letter:
float notLetter = word.getNotLetterRatio();
notLetter *= notLetter;
wWord += notLetter * cc.textMessageNoLetter;
wWord *= wWord; // TODO: quadratic ? (configurable)
wWords += wWord;
}
wWords /= (float) letterCounts.words.length;
score += wWords;
if (debug && score > 0f) {
debugParts.add("Simple score: " + StringUtil.fdec3.format(score));
}
2014-11-04 00:20:18 +01:00
// Engine:
// TODO: more fine grained sync !
float wEngine = 0f;
final Map<String, Float> engMap;
synchronized (engine) {
engMap = engine.process(letterCounts, player.getName(), cc, data);
// TODO: more fine grained sync !s
// TODO: different methods (add or max or add+max or something else).
for (final Float res : engMap.values()) {
if (cc.textEngineMaximum) {
wEngine = Math.max(wEngine, res.floatValue());
}
else {
wEngine += res.floatValue();
}
2014-11-04 00:20:18 +01:00
}
}
score += wEngine;
// Wrapping it up. --------------------
// Add weight to frequency counts.
final float normalScore = Math.max(cc.textFreqNormMin, score);
data.chatFrequency.add(time, normalScore);
final float accumulated = cc.textFreqNormWeight * data.chatFrequency.score(cc.textFreqNormFactor);
final boolean normalViolation = accumulated > cc.textFreqNormLevel;
final float shortTermScore = Math.max(cc.textFreqShortTermMin, score);
data.chatShortTermFrequency.add(time, shortTermScore);
// TODO: very short term (1st bucket) or do it indirectly.
final float shortTermAccumulated = cc.textFreqShortTermWeight * data.chatShortTermFrequency.score(cc.textFreqShortTermFactor);
final boolean shortTermViolation = shortTermAccumulated > cc.textFreqShortTermLevel;
if (normalViolation || shortTermViolation) {
lastCancelledMessage = lcMessage;
lastCancelledTime = time;
final double added;
if (shortTermViolation) {
added = (shortTermAccumulated - cc.textFreqShortTermLevel)/ 3.0;
} else {
added = (accumulated - cc.textFreqNormLevel) / 10.0;
}
data.textVL += added;
[BLEEDING][BREAKING][INSTABLE] Swiftly throw in permission caching. Benefits: * Improves performance, where permission lookup has major impact, with timeout based lookup, static permissions (skip permission check entirely), and world/offline based invalidation. (Once fully implemented.) * Hopefully more efficient: use Bukkit Permission for faster defaults. * (Allows control over how which permission is to be updated/invalidated, which is useful per se.) Risks: * Complex changes yield bugs. * Other plugins depending on NCP might break. * Cache incoherence might happen (permissions are changed dynamically +- unintended malconfiguration, or in case of bugs). * (Endless loops certainly have all been fixed.) Breaking: * Lots of more or less internal API has been changed or removed: Check, CheckType, CheckUtils, TickTask, ... * Permission checking behavior has been altered. Rough points: * Implement a permission cache within PlayerData. * Remove the player tasks and permission updates in favour of handling those within DataManager and PlayerData. * Adjust everything else to it (partly TBD). * Updating sets of permissions (e.g. for CHAT) is done more lazily now, i.e. one per 10 ticks). An actual permission check would still yield an update next tick (asynchronous). * Fixed/extended random spots (DualCollection, MiniListener registration support, StringUtil). Missing: * Basic implementation * Cleanup after logout (stages: 1. non-essential like permissions, 2. unrecoverable like set-back location, 3. complete data removal). * Coverage * Might have missed spots. * NoCheatPlus.nameSetPerms should be replaced by caching + default config for world-wise updating. * Command permissions are always checked. At least for players, cache based lookup should get implemented. * More unit tests. * Extended configurability: Per-world settings/policies. * Efficiency * Not all parts of the implementation are 100%/optimal yet.
2018-01-28 18:52:51 +01:00
if (captcha.shouldStartCaptcha(player, cc, data, pData)) {
2014-11-04 00:20:18 +01:00
captcha.sendNewCaptcha(player, cc, data);
cancel = true;
}
else{
if (shortTermViolation) {
2016-02-10 00:05:11 +01:00
if (executeActions(player, data.textVL, added, cc.textFreqShortTermActions).willCancel()) {
2014-11-04 00:20:18 +01:00
cancel = true;
}
}
2014-11-04 00:20:18 +01:00
else if (normalViolation) {
2016-02-10 00:05:11 +01:00
if (executeActions(player, data.textVL, added, cc.textFreqNormActions).willCancel()) {
2014-11-04 00:20:18 +01:00
cancel = true;
}
}
}
}
else if (cc.chatWarningCheck && time - data.chatWarningTime > cc.chatWarningTimeout && (100f * accumulated / cc.textFreqNormLevel > cc.chatWarningLevel || 100f * shortTermAccumulated / cc.textFreqShortTermLevel > cc.chatWarningLevel)) {
NCPAPIProvider.getNoCheatPlusAPI().sendMessageOnTick(player.getName(), ColorUtil.replaceColors(cc.chatWarningMessage));
data.chatWarningTime = time;
2014-11-04 00:20:18 +01:00
}
else {
data.textVL *= 0.95;
if (cc.textAllowVLReset && normalScore < 2.0f * cc.textFreqNormWeight && shortTermScore < 2.0f * cc.textFreqShortTermWeight) {
2014-11-04 00:20:18 +01:00
// Reset the VL.
// TODO: maybe elaborate on resetting conditions (after some timeout just divide by two or so?).
data.textVL = 0.0;
}
}
2014-11-04 00:20:18 +01:00
if (debug) {
final List<String> keys = new LinkedList<String>(engMap.keySet());
Collections.sort(keys);
for (String key : keys) {
Float s = engMap.get(key);
if (s.floatValue() > 0.0f)
debugParts.add(key + ":" + StringUtil.fdec3.format(s));
}
if (wEngine > 0.0f)
debugParts.add("Engine score (" + (cc.textEngineMaximum?"max":"sum") + "): " + StringUtil.fdec3.format(wEngine));
debugParts.add("Final score: " + StringUtil.fdec3.format(score));
debugParts.add("Normal: min=" + StringUtil.fdec3.format(cc.textFreqNormMin) +", weight=" + StringUtil.fdec3.format(cc.textFreqNormWeight) + " => accumulated=" + StringUtil.fdec3.format(accumulated));
debugParts.add("Short-term: min=" + StringUtil.fdec3.format(cc.textFreqShortTermMin) +", weight=" + StringUtil.fdec3.format(cc.textFreqShortTermWeight) + " => accumulated=" + StringUtil.fdec3.format(shortTermAccumulated));
debugParts.add("vl: " + StringUtil.fdec3.format(data.textVL));
debug(player, StringUtil.join(debugParts, " | "));
2014-11-04 00:20:18 +01:00
debugParts.clear();
}
lastGlobalMessage = data.chatLastMessage = lcMessage;
lastGlobalTime = data.chatLastTime = time;
return cancel;
}
}