diff --git a/Instructions.txt b/Instructions.txt
index 3a55d225..858a0504 100644
--- a/Instructions.txt
+++ b/Instructions.txt
@@ -961,6 +961,26 @@
number of messages/commands that were sent beyond the specified limits.
It gets increased for every message/command by 1 and reset to zero when
the "timeframe" has passed.
+
+ 3) SPAMJOINS:
+
+ This check limits the number of new players joining every X seconds to
+ prevent the usage of softwares like PWN4G3.
+
+ active:
+ Should players get checked for that kind of spam.
+
+ playerslimit:
+ The number of new players allowed to join during the interval defined
+ in the configuration.
+
+ timelimit:
+ The interval in milliseconds during which the number of new players
+ defined in the configuration are allowed to join.
+
+ cooldown:
+ The number of milliseconds during which new players won't be allowed
+ to join if too many new players have been detected.
------------------------------ FIGHT Subsection --------------------------------
diff --git a/pom.xml b/pom.xml
index 33a685f9..a762a071 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
NoCheatPlus
- 3.5.4_1
+ 3.5.5
Detect and fight the exploitation of various flaws/bugs in Minecraft.
http://dev.bukkit.org/server-mods/nocheatplus
diff --git a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java
index eeb77792..25919bb8 100644
--- a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java
+++ b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java
@@ -56,6 +56,8 @@ public class BlockPlaceCheckListener implements Listener, EventManager {
s.add("blockplace.reach");
if (bp.directionCheck)
s.add("blockplace.direction");
+ if (bp.projectileCheck)
+ s.add("blockplace.projectileCheck");
return s;
}
@@ -127,8 +129,10 @@ public class BlockPlaceCheckListener implements Listener, EventManager {
public void otherProjectiles(final ProjectileLaunchEvent event) {
// We are only interested by enderpears, endersignals, eggs, snowballs and expbottles
- if (event.getEntityType() != EntityType.ENDER_PEARL && event.getEntityType() != EntityType.ENDER_SIGNAL
- && event.getEntityType() != EntityType.EGG && event.getEntityType() != EntityType.SNOWBALL
+ // of course thrown by a player
+ if (!(event.getEntity().getShooter() instanceof Player) || event.getEntityType() != EntityType.ENDER_PEARL
+ && event.getEntityType() != EntityType.ENDER_SIGNAL && event.getEntityType() != EntityType.EGG
+ && event.getEntityType() != EntityType.SNOWBALL
&& event.getEntityType() != EntityType.THROWN_EXP_BOTTLE)
return;
diff --git a/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java b/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java
index f20d8d78..cab5ec62 100644
--- a/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java
+++ b/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java
@@ -14,6 +14,7 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
/**
* Central location to listen to events that are
@@ -22,16 +23,18 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent;
*/
public class ChatCheckListener implements Listener, EventManager {
- private final SpamCheck spamCheck;
- private final ColorCheck colorCheck;
+ private final SpamCheck spamCheck;
+ private final SpamJoinsCheck spamJoinsCheck;
+ private final ColorCheck colorCheck;
- private final NoCheatPlus plugin;
+ private final NoCheatPlus plugin;
public ChatCheckListener(final NoCheatPlus plugin) {
this.plugin = plugin;
spamCheck = new SpamCheck(plugin);
+ spamJoinsCheck = new SpamJoinsCheck(plugin);
colorCheck = new ColorCheck(plugin);
}
@@ -95,8 +98,27 @@ public class ChatCheckListener implements Listener, EventManager {
final ChatConfig c = ChatCheck.getConfig(cc);
if (c.spamCheck)
s.add("chat.spam");
+ if (c.spamJoinsCheck)
+ s.add("chat.spamjoins");
if (c.colorCheck)
s.add("chat.color");
return s;
}
+
+ @EventHandler(
+ ignoreCancelled = true, priority = EventPriority.LOWEST)
+ public void join(final PlayerJoinEvent event) {
+
+ // Only check new players (who has joined less than 10 minutes ago)
+ if (System.currentTimeMillis() - event.getPlayer().getFirstPlayed() > 600000L)
+ return;
+
+ final NoCheatPlusPlayer player = plugin.getPlayer(event.getPlayer());
+ final ChatConfig cc = ChatCheck.getConfig(player);
+ final ChatData data = ChatCheck.getData(player);
+
+ if (cc.spamJoinsCheck && spamJoinsCheck.check(player, data, cc))
+ // If the player failed the check, kick it
+ event.getPlayer().kickPlayer(cc.spamJoinsKickMessage);
+ }
}
diff --git a/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java b/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java
index 6b3dae96..b8db4e1f 100644
--- a/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java
+++ b/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java
@@ -24,6 +24,12 @@ public class ChatConfig implements ConfigItem {
public final int spamCommandLimit;
public final ActionList spamActions;
+ public final boolean spamJoinsCheck;
+ public final int spamJoinsPlayersLimit;
+ public final int spamJoinsTimeLimit;
+ public final int spamJoinsCooldown;
+ public final String spamJoinsKickMessage;
+
public final boolean colorCheck;
public final ActionList colorActions;
@@ -35,6 +41,11 @@ public class ChatConfig implements ConfigItem {
spamMessageLimit = data.getInt(ConfPaths.CHAT_SPAM_MESSAGELIMIT);
spamCommandLimit = data.getInt(ConfPaths.CHAT_SPAM_COMMANDLIMIT);
spamActions = data.getActionList(ConfPaths.CHAT_SPAM_ACTIONS, Permissions.CHAT_SPAM);
+ spamJoinsCheck = data.getBoolean(ConfPaths.CHAT_SPAMJOINS_CHECK);
+ spamJoinsPlayersLimit = data.getInt(ConfPaths.CHAT_SPAMJOINS_PLAYERSLIMIT);
+ spamJoinsTimeLimit = data.getInt(ConfPaths.CHAT_SPAMJOINS_TIMELIMIT);
+ spamJoinsCooldown = data.getInt(ConfPaths.CHAT_SPAMJOINS_COOLDOWN);
+ spamJoinsKickMessage = data.getString(ConfPaths.CHAT_SPAMJOINS_KICKMESSAGE);
colorCheck = data.getBoolean(ConfPaths.CHAT_COLOR_CHECK);
colorActions = data.getActionList(ConfPaths.CHAT_COLOR_ACTIONS, Permissions.CHAT_COLOR);
}
diff --git a/src/me/neatmonster/nocheatplus/checks/chat/ChatData.java b/src/me/neatmonster/nocheatplus/checks/chat/ChatData.java
index eb5e22da..94be82cd 100644
--- a/src/me/neatmonster/nocheatplus/checks/chat/ChatData.java
+++ b/src/me/neatmonster/nocheatplus/checks/chat/ChatData.java
@@ -10,6 +10,7 @@ public class ChatData implements DataItem {
// Keep track of the violation levels for the two checks
public int spamVL;
+ public int spamJoinsVL;
public int colorVL;
// Count messages and commands
diff --git a/src/me/neatmonster/nocheatplus/checks/chat/SpamJoinsCheck.java b/src/me/neatmonster/nocheatplus/checks/chat/SpamJoinsCheck.java
new file mode 100644
index 00000000..dc21ccd4
--- /dev/null
+++ b/src/me/neatmonster/nocheatplus/checks/chat/SpamJoinsCheck.java
@@ -0,0 +1,55 @@
+package me.neatmonster.nocheatplus.checks.chat;
+
+import me.neatmonster.nocheatplus.NoCheatPlus;
+import me.neatmonster.nocheatplus.NoCheatPlusPlayer;
+
+public class SpamJoinsCheck extends ChatCheck {
+
+ // Used to know if the cooldown is enabled and since when
+ private boolean cooldown = false;
+ private long cooldownStartTime = 0L;
+
+ // Used to remember the latest joins;
+ private long[] joins = null;
+
+ public SpamJoinsCheck(final NoCheatPlus plugin) {
+ super(plugin, "chat.spamjoins");
+ }
+
+ public boolean check(final NoCheatPlusPlayer player, final ChatData data, final ChatConfig cc) {
+
+ // Initialize the joins array
+ if (joins == null)
+ joins = new long[cc.spamJoinsPlayersLimit];
+
+ boolean kick = false;
+
+ // If the new players cooldown is over
+ if (cooldown && System.currentTimeMillis() - cooldownStartTime > cc.spamJoinsCooldown) {
+ // Stop the new players cooldown
+ cooldown = false;
+ cooldownStartTime = 0L;
+ }
+
+ // If the new players cooldown is active
+ else if (cooldown)
+ // Kick the player who joined
+ kick = true;
+
+ // If more than limit new players have joined in less than limit time
+ else if (System.currentTimeMillis() - joins[0] < cc.spamJoinsTimeLimit) {
+ // Enable the new players cooldown
+ cooldown = true;
+ cooldownStartTime = System.currentTimeMillis();
+ // Kick the player who joined
+ kick = true;
+ }
+
+ // Fill the joining times array
+ for (int i = 0; i < cc.spamJoinsPlayersLimit - 1; i++)
+ joins[i] = joins[i + 1];
+ joins[cc.spamJoinsPlayersLimit - 1] = System.currentTimeMillis();
+
+ return kick;
+ }
+}
diff --git a/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java b/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java
index 96b81eb3..9b63d624 100644
--- a/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java
+++ b/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java
@@ -71,19 +71,17 @@ public class MovingCheckListener implements Listener, EventManager {
final MovingData data = MovingCheck.getData(player);
// Do not do the check if it's disabled, if flying is allowed, if the player is
- // allowed to fly because of its game mode or if he has the required permission.
+ // allowed to fly because of its game mode, if he has the required permission,
+ // if he is in water or in vines.
if (!cc.tracker || cc.allowFlying || bukkitPlayer.getGameMode() == GameMode.CREATIVE
- || bukkitPlayer.getAllowFlight() || bukkitPlayer.hasPermission(Permissions.MOVING_RUNFLY)) {
- data.fallingSince = 0;
- return;
- }
-
- // If the player is in water or in vines, then do not run the check
- if (bukkitPlayer.getLocation().getBlock().getType() == Material.WATER
+ || bukkitPlayer.getAllowFlight() || bukkitPlayer.hasPermission(Permissions.MOVING_RUNFLY)
+ || bukkitPlayer.hasPermission(Permissions.MOVING_FLYING)
+ || bukkitPlayer.getLocation().getBlock().getType() == Material.WATER
|| bukkitPlayer.getLocation().getBlock().getType() == Material.STATIONARY_WATER
+ || bukkitPlayer.getLocation().getBlock().getType() == Material.LADDER
|| bukkitPlayer.getLocation().getBlock().getType() == Material.VINE) {
data.fallingSince = 0;
- return;
+ continue;
}
// If the player isn't falling or jumping
@@ -176,10 +174,14 @@ public class MovingCheckListener implements Listener, EventManager {
s.add("moving.sneaking");
if (m.nofallCheck)
s.add("moving.nofall");
+ if (m.waterWalkCheck)
+ s.add("moving.waterwalk");
} else
s.add("moving.flying");
if (m.morePacketsCheck)
s.add("moving.morepackets");
+ if (m.morePacketsVehicleCheck)
+ s.add("moving.morepacketsvehicle");
return s;
}
diff --git a/src/me/neatmonster/nocheatplus/config/ConfPaths.java b/src/me/neatmonster/nocheatplus/config/ConfPaths.java
index 17757801..5e10257e 100644
--- a/src/me/neatmonster/nocheatplus/config/ConfPaths.java
+++ b/src/me/neatmonster/nocheatplus/config/ConfPaths.java
@@ -142,6 +142,13 @@ public abstract class ConfPaths {
public final static String CHAT_SPAM_COMMANDLIMIT = CHAT_SPAM + "commandlimit";
public final static String CHAT_SPAM_ACTIONS = CHAT_SPAM + "actions";
+ private final static String CHAT_SPAMJOINS = CHAT + "spamjoins.";
+ public final static String CHAT_SPAMJOINS_CHECK = CHAT_SPAMJOINS + "active";
+ public final static String CHAT_SPAMJOINS_PLAYERSLIMIT = CHAT_SPAMJOINS + "playerslimit";
+ public final static String CHAT_SPAMJOINS_TIMELIMIT = CHAT_SPAMJOINS + "timelimit";
+ public final static String CHAT_SPAMJOINS_COOLDOWN = CHAT_SPAMJOINS + "cooldown";
+ public final static String CHAT_SPAMJOINS_KICKMESSAGE = CHAT_SPAMJOINS + "kickmessage";
+
private final static String FIGHT = CHECKS + "fight.";
private final static String FIGHT_DIRECTION = FIGHT + "direction.";
diff --git a/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java b/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java
index 69e73a45..93a5d80e 100644
--- a/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java
+++ b/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java
@@ -125,6 +125,12 @@ public class DefaultConfiguration extends NoCheatPlusConfiguration {
set(ConfPaths.CHAT_SPAM_COMMANDLIMIT, 12);
set(ConfPaths.CHAT_SPAM_ACTIONS, "log:spam:0:3:if cancel vl>30 log:spam:0:3:cif cancel cmd:kick");
+ set(ConfPaths.CHAT_SPAMJOINS_CHECK, true);
+ set(ConfPaths.CHAT_SPAMJOINS_PLAYERSLIMIT, 3);
+ set(ConfPaths.CHAT_SPAMJOINS_TIMELIMIT, 5000);
+ set(ConfPaths.CHAT_SPAMJOINS_COOLDOWN, 5000);
+ set(ConfPaths.CHAT_SPAMJOINS_KICKMESSAGE, "SpamBot?!");
+
/*** FIGHT ***/
set(ConfPaths.FIGHT_DIRECTION_CHECK, true);