mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-03-02 10:31:25 +01:00
New check "chat.spam" with configuration and permissions
This commit is contained in:
parent
af2242844f
commit
1480ebb3db
10
plugin.yml
10
plugin.yml
@ -20,6 +20,7 @@ permissions:
|
||||
nocheat.checks.blockbreak.*: true
|
||||
nocheat.checks.blockplace.*: true
|
||||
nocheat.checks.interact.*: true
|
||||
nocheat.checks.chat.*: true
|
||||
|
||||
nocheat.checks.moving.*:
|
||||
description: Allow the player to bypass all moving checks
|
||||
@ -47,6 +48,11 @@ permissions:
|
||||
description: Allow the player to bypass all interact checks
|
||||
children:
|
||||
nocheat.checks.interact.durability: true
|
||||
|
||||
nocheat.checks.chat.*:
|
||||
description: Allow the player to bypass all chat checks
|
||||
children:
|
||||
nocheat.checks.chat.spam: true
|
||||
|
||||
nocheat.checks.moving.flying:
|
||||
description: Allow a player to move free through the air (if given, the "running" check will be ignored anyway)
|
||||
@ -84,6 +90,10 @@ permissions:
|
||||
nocheat.checks.interact.durability:
|
||||
description: Allow a player to use an infinite durability item hack
|
||||
default: op
|
||||
|
||||
nocheat.checks.chat.spam:
|
||||
description: Allow a player to send an infinite amount of chat messages
|
||||
default: op
|
||||
|
||||
nocheat.admin.*:
|
||||
description: Give a player all admin rights
|
||||
|
@ -231,6 +231,30 @@ public class DefaultConfiguration {
|
||||
actions.add(0, "durabilityLog interactCancel");
|
||||
}
|
||||
}
|
||||
|
||||
/****** CHAT ******/
|
||||
{
|
||||
ParentOption chatNode = new ParentOption("chat");
|
||||
root.add(chatNode);
|
||||
|
||||
chatNode.add(new BooleanOption("check", true, true));
|
||||
|
||||
/**** CHAT.SPAM ****/
|
||||
{
|
||||
ParentOption spamNode = new ParentOption("spam");
|
||||
chatNode.add(spamNode);
|
||||
|
||||
spamNode.add(new BooleanOption("check", false, true));
|
||||
spamNode.add(new IntegerOption("timeframe", 5));
|
||||
spamNode.add(new IntegerOption("limit", 5));
|
||||
|
||||
ActionListOption actions = new ActionListOption("actions");
|
||||
|
||||
spamNode.add(actions);
|
||||
|
||||
actions.add(0, "spamLog spamCancel");
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -312,6 +336,7 @@ public class DefaultConfiguration {
|
||||
w(w, "log directionLog 2 1 med NC: [player] failed [check]: tried to destroy a block out of line of sight.");
|
||||
w(w, "log durabilityLog 0 1 med NC: [player] failed [check]: tried to use infinity durability hack.");
|
||||
w(w, "log onliquidLog 2 1 med NC: [player] failed [check]: tried to place a block on liquids.");
|
||||
w(w, "log spamLog 0 4 med NC: [player] failed [check]: Last sent message \"[text]\".");
|
||||
w(w, "");
|
||||
w(w, "# SPECIAL Actions: They will do something check dependant, usually cancel an event.");
|
||||
w(w, "# - They start with the word 'special'");
|
||||
@ -325,6 +350,7 @@ public class DefaultConfiguration {
|
||||
w(w, "special blockbreakCancel 0 0");
|
||||
w(w, "special blockplaceCancel 0 0");
|
||||
w(w, "special interactCancel 0 0");
|
||||
w(w, "special spamCancel 0 0");
|
||||
w(w, "");
|
||||
w(w, "# CONSOLECOMMAND Actions: They will execute a command as if it were typed into the console.");
|
||||
w(w, "# - They start with the word 'consolecommand'");
|
||||
|
@ -66,6 +66,14 @@ public class Explainations {
|
||||
|
||||
set("interact.durability.check", "If true, check if a player is using a hack that provides infinite durability items.");
|
||||
set("interact.durability.actions", "What should be done if a player is trying to use the hack.\nUnit is number of uses or attempts to use the hack.");
|
||||
|
||||
set("chat.check", "If true, do various checks on PlayerChat events.");
|
||||
|
||||
set("chat.spam.check", "If true, check if a player is spamming the chat.");
|
||||
set("interact.spam.timeframe", "Over what timeframe (in seconds) should the messages be counted?");
|
||||
set("interact.spam.limit", "How many messages per timeframe may the player send?");
|
||||
set("interact.spam.actions", "What should be done if a player is trying to spam the chat.\nUnit is number of chat messages above the given limit.");
|
||||
|
||||
}
|
||||
|
||||
private static void set(String id, String text) {
|
||||
|
@ -9,6 +9,7 @@ import cc.co.evenprime.bukkit.nocheat.data.DataManager;
|
||||
|
||||
import cc.co.evenprime.bukkit.nocheat.events.BlockPlaceEventManager;
|
||||
import cc.co.evenprime.bukkit.nocheat.events.BlockBreakEventManager;
|
||||
import cc.co.evenprime.bukkit.nocheat.events.PlayerChatEventManager;
|
||||
import cc.co.evenprime.bukkit.nocheat.events.PlayerItemDropEventManager;
|
||||
import cc.co.evenprime.bukkit.nocheat.events.PlayerInteractEventManager;
|
||||
import cc.co.evenprime.bukkit.nocheat.events.PlayerMoveEventManager;
|
||||
@ -37,6 +38,7 @@ public class NoCheat extends JavaPlugin {
|
||||
private BlockPlaceEventManager eventBlockPlaceManager;
|
||||
private PlayerInteractEventManager eventPlayerInteractManager;
|
||||
private PlayerItemDropEventManager eventPlayerItemDropManager;
|
||||
private PlayerChatEventManager eventPlayerChatManager;
|
||||
|
||||
private int taskId = -1;
|
||||
private int ingameseconds = 0;
|
||||
@ -81,6 +83,7 @@ public class NoCheat extends JavaPlugin {
|
||||
eventBlockPlaceManager = new BlockPlaceEventManager(this);
|
||||
eventPlayerItemDropManager = new PlayerItemDropEventManager(this);
|
||||
eventPlayerInteractManager = new PlayerInteractEventManager(this);
|
||||
eventPlayerChatManager = new PlayerChatEventManager(this);
|
||||
|
||||
PluginDescriptionFile pdfFile = this.getDescription();
|
||||
|
||||
|
@ -15,6 +15,7 @@ public class Permissions {
|
||||
private final static String _BLOCKBREAK = _CHECKS + ".blockbreak";
|
||||
private final static String _BLOCKPLACE = _CHECKS + ".blockplace";
|
||||
private final static String _INTERACT = _CHECKS + ".interact";
|
||||
private final static String _CHAT = _CHECKS + ".chat";
|
||||
|
||||
public final static String MOVE = _CHECKS + ".moving.*";
|
||||
public final static String MOVE_FLY = _MOVE + ".flying";
|
||||
@ -33,9 +34,11 @@ public class Permissions {
|
||||
|
||||
public final static String BLOCKPLACE = _CHECKS + ".blockplace.*";
|
||||
public final static String BLOCKPLACE_ONLIQUID = _BLOCKPLACE + ".onliquid";
|
||||
public static final String BLOCKPLACE_REACH = _BLOCKPLACE + ".reach";
|
||||
|
||||
public final static String BLOCKPLACE_REACH = _BLOCKPLACE + ".reach";
|
||||
|
||||
public final static String CHAT = _CHECKS + ".chat.*";
|
||||
public final static String CHAT_SPAM = _CHAT + ".spam";
|
||||
|
||||
public final static String ADMIN_CHATLOG = _ADMIN + ".chatlog";
|
||||
|
||||
private Permissions() {}
|
||||
|
@ -23,7 +23,8 @@ public class LogAction extends Action {
|
||||
public static final String DISTANCE = "\\[distance\\]";
|
||||
public static final String LOCATION_TO = "\\[locationto\\]";
|
||||
public static final String CHECK = "\\[check\\]";
|
||||
public static final String PACKETS = "\\[packets\\]"; ;
|
||||
public static final String PACKETS = "\\[packets\\]";
|
||||
public static final String TEXT = "\\[text\\]";
|
||||
|
||||
public final LogLevel level;
|
||||
private final String message;
|
||||
|
@ -0,0 +1,62 @@
|
||||
package cc.co.evenprime.bukkit.nocheat.checks.chat;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import cc.co.evenprime.bukkit.nocheat.NoCheat;
|
||||
import cc.co.evenprime.bukkit.nocheat.Permissions;
|
||||
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutor;
|
||||
import cc.co.evenprime.bukkit.nocheat.actions.ActionExecutorWithHistory;
|
||||
import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction;
|
||||
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
|
||||
import cc.co.evenprime.bukkit.nocheat.data.ChatData;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Evenprime
|
||||
*
|
||||
*/
|
||||
public class ChatCheck {
|
||||
|
||||
private final ActionExecutor action;
|
||||
private final NoCheat plugin;
|
||||
|
||||
public ChatCheck(NoCheat plugin) {
|
||||
|
||||
action = new ActionExecutorWithHistory(plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public boolean check(Player player, String message, ChatData data, ConfigurationCache cc) {
|
||||
|
||||
boolean cancel = false;
|
||||
|
||||
boolean spamCheck = cc.chat.spamCheck && !player.hasPermission(Permissions.CHAT_SPAM);
|
||||
|
||||
if(spamCheck) {
|
||||
|
||||
int time = plugin.getIngameSeconds();
|
||||
|
||||
if(data.spamLasttime + cc.chat.spamTimeframe <= plugin.getIngameSeconds()) {
|
||||
data.spamLasttime = time;
|
||||
data.messageCount = 0;
|
||||
}
|
||||
|
||||
data.messageCount++;
|
||||
|
||||
if(data.messageCount > cc.chat.spamLimit) {
|
||||
|
||||
// Prepare some event-specific values for logging and custom
|
||||
// actions
|
||||
HashMap<String, String> params = new HashMap<String, String>();
|
||||
params.put(LogAction.CHECK, "chat.spam");
|
||||
params.put(LogAction.TEXT, message);
|
||||
cancel = action.executeActions(player, cc.chat.spamActions, data.messageCount - cc.chat.spamLimit, params, cc);
|
||||
}
|
||||
}
|
||||
|
||||
return cancel;
|
||||
}
|
||||
|
||||
}
|
23
src/cc/co/evenprime/bukkit/nocheat/config/cache/CCChat.java
vendored
Normal file
23
src/cc/co/evenprime/bukkit/nocheat/config/cache/CCChat.java
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
package cc.co.evenprime.bukkit.nocheat.config.cache;
|
||||
|
||||
import cc.co.evenprime.bukkit.nocheat.actions.ActionList;
|
||||
import cc.co.evenprime.bukkit.nocheat.config.Configuration;
|
||||
|
||||
public class CCChat {
|
||||
|
||||
public final boolean check;
|
||||
public final boolean spamCheck;
|
||||
public final int spamTimeframe;
|
||||
public final int spamLimit;
|
||||
public final ActionList spamActions;
|
||||
|
||||
public CCChat(Configuration data) {
|
||||
|
||||
check = data.getBoolean("chat.check");
|
||||
spamCheck = data.getBoolean("chat.spam.check");
|
||||
spamTimeframe = data.getInteger("chat.spam.timeframe");
|
||||
spamLimit = data.getInteger("chat.spam.limit");
|
||||
spamActions = data.getActionList("chat.spam.actions");
|
||||
|
||||
}
|
||||
}
|
@ -13,11 +13,12 @@ import cc.co.evenprime.bukkit.nocheat.config.Configuration;
|
||||
*/
|
||||
public class ConfigurationCache {
|
||||
|
||||
public final CCMoving moving;
|
||||
public final CCLogging logging;
|
||||
public final CCMoving moving;
|
||||
public final CCLogging logging;
|
||||
public final CCBlockBreak blockbreak;
|
||||
public final CCInteract interact;
|
||||
public final CCBlockPlace blockplace;
|
||||
public final CCInteract interact;
|
||||
public final CCBlockPlace blockplace;
|
||||
public final CCChat chat;
|
||||
|
||||
/**
|
||||
* Instantiate a config cache and populate it with the data of a
|
||||
@ -31,6 +32,7 @@ public class ConfigurationCache {
|
||||
blockbreak = new CCBlockBreak(data);
|
||||
blockplace = new CCBlockPlace(data);
|
||||
interact = new CCInteract(data);
|
||||
chat = new CCChat(data);
|
||||
logging = new CCLogging(data, worldSpecificFileLogger);
|
||||
|
||||
}
|
||||
|
13
src/cc/co/evenprime/bukkit/nocheat/data/ChatData.java
Normal file
13
src/cc/co/evenprime/bukkit/nocheat/data/ChatData.java
Normal file
@ -0,0 +1,13 @@
|
||||
package cc.co.evenprime.bukkit.nocheat.data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Evenprime
|
||||
*
|
||||
*/
|
||||
public class ChatData {
|
||||
|
||||
public int messageCount = 0;
|
||||
public int spamLasttime = 0;
|
||||
|
||||
}
|
@ -5,7 +5,6 @@ import java.util.Map;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
|
||||
/**
|
||||
* Provide secure access to player-specific data objects for various checks or
|
||||
* check groups
|
||||
@ -19,7 +18,8 @@ public class DataManager {
|
||||
private final Map<Player, MovingData> movingData = new HashMap<Player, MovingData>();
|
||||
private final Map<Player, BlockBreakData> blockbreakData = new HashMap<Player, BlockBreakData>();
|
||||
private final Map<Player, InteractData> interactData = new HashMap<Player, InteractData>();
|
||||
private final Map<Player, BlockPlaceData> blockPlaceData = new HashMap<Player, BlockPlaceData>();
|
||||
private final Map<Player, BlockPlaceData> blockPlaceData = new HashMap<Player, BlockPlaceData>();
|
||||
private final Map<Player, ChatData> chatData = new HashMap<Player, ChatData>();
|
||||
|
||||
public DataManager() {
|
||||
|
||||
@ -86,4 +86,20 @@ public class DataManager {
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public ChatData getChatData(Player player) {
|
||||
ChatData data;
|
||||
|
||||
// intentionally not thread-safe, because bukkit events are handled
|
||||
// in sequence anyway, so zero chance of two events of the same
|
||||
// player being handled at the same time
|
||||
// And if it still happens by accident, it's no real loss anyway
|
||||
data = chatData.get(player);
|
||||
if(data == null) {
|
||||
data = new ChatData();
|
||||
chatData.put(player, data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
package cc.co.evenprime.bukkit.nocheat.events;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.Event.Priority;
|
||||
import org.bukkit.event.player.PlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerListener;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import cc.co.evenprime.bukkit.nocheat.NoCheat;
|
||||
import cc.co.evenprime.bukkit.nocheat.Permissions;
|
||||
import cc.co.evenprime.bukkit.nocheat.checks.chat.ChatCheck;
|
||||
import cc.co.evenprime.bukkit.nocheat.config.ConfigurationManager;
|
||||
import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
|
||||
import cc.co.evenprime.bukkit.nocheat.data.ChatData;
|
||||
import cc.co.evenprime.bukkit.nocheat.data.DataManager;
|
||||
|
||||
public class PlayerChatEventManager extends PlayerListener {
|
||||
|
||||
private final ChatCheck chatCheck;
|
||||
private final DataManager data;
|
||||
private final ConfigurationManager config;
|
||||
|
||||
public PlayerChatEventManager(NoCheat plugin) {
|
||||
|
||||
this.data = plugin.getDataManager();
|
||||
this.config = plugin.getConfigurationManager();
|
||||
this.chatCheck = new ChatCheck(plugin);
|
||||
|
||||
PluginManager pm = Bukkit.getServer().getPluginManager();
|
||||
|
||||
pm.registerEvent(Event.Type.PLAYER_CHAT, this, Priority.High, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerChat(PlayerChatEvent event) {
|
||||
|
||||
if(event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Player player = event.getPlayer();
|
||||
final ConfigurationCache cc = config.getConfigurationCacheForWorld(player.getWorld().getName());
|
||||
|
||||
// Find out if checks need to be done for that player
|
||||
if(cc.chat.check && !player.hasPermission(Permissions.CHAT)) {
|
||||
|
||||
boolean cancel = false;
|
||||
|
||||
// Get the player-specific stored data that applies here
|
||||
final ChatData data = this.data.getChatData(player);
|
||||
|
||||
cancel = chatCheck.check(player, event.getMessage(), data, cc);
|
||||
|
||||
if(cancel) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ import cc.co.evenprime.bukkit.nocheat.data.InteractData;
|
||||
/**
|
||||
*
|
||||
* @author Evenprime
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class PlayerInteractEventManager extends PlayerListener {
|
||||
|
||||
@ -29,18 +29,18 @@ public class PlayerInteractEventManager extends PlayerListener {
|
||||
|
||||
public PlayerInteractEventManager(NoCheat plugin) {
|
||||
|
||||
this.data = plugin.getDataManager();
|
||||
this.config = plugin.getConfigurationManager();
|
||||
this.interactCheck = new InteractCheck(plugin);
|
||||
|
||||
PluginManager pm = Bukkit.getServer().getPluginManager();
|
||||
this.data = plugin.getDataManager();
|
||||
this.config = plugin.getConfigurationManager();
|
||||
this.interactCheck = new InteractCheck(plugin);
|
||||
|
||||
pm.registerEvent(Event.Type.PLAYER_INTERACT, this, Priority.Lowest, plugin);
|
||||
PluginManager pm = Bukkit.getServer().getPluginManager();
|
||||
|
||||
pm.registerEvent(Event.Type.PLAYER_INTERACT, this, Priority.Lowest, plugin);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
|
||||
|
||||
if(event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
@ -52,17 +52,17 @@ public class PlayerInteractEventManager extends PlayerListener {
|
||||
if(cc.interact.check && !player.hasPermission(Permissions.INTERACT)) {
|
||||
|
||||
boolean cancel = false;
|
||||
|
||||
|
||||
// Get the player-specific stored data that applies here
|
||||
final InteractData data = this.data.getInteractData(player);
|
||||
|
||||
|
||||
cancel = interactCheck.check(player, data, cc);
|
||||
|
||||
if(cancel) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ public class FlatConfigGenerator {
|
||||
String s = "# Want to know what these options do? Read the descriptions.txt file.\r\n\r\n";
|
||||
|
||||
for(Option option : o.getChildOptions()) {
|
||||
s += optionToFlatString(option);
|
||||
s += optionToFlatString(option) + "\r\n";
|
||||
}
|
||||
|
||||
return s;
|
||||
|
Loading…
Reference in New Issue
Block a user