diff --git a/Instructions.txt b/Instructions.txt
index 858a0504..5e1d802b 100644
--- a/Instructions.txt
+++ b/Instructions.txt
@@ -907,6 +907,12 @@
------------------------------- CHAT Subsection --------------------------------
Checks that at least technically have to do with chat or commands.
+
+ hidenocheatplus:
+
+ Setting this to true will hide NoCheatPlus for the /plugins (or /pl) command
+ of Bukkit (only if typed by a player). This command might be used by some
+ griefing clients to try to detect and to apply bypasses to NoCheatPlus.
1) COLOR:
diff --git a/pom.xml b/pom.xml
index a762a071..18b249a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
NoCheatPlus
- 3.5.5
+ 3.5.5_1
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/chat/ChatCheckListener.java b/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java
index cab5ec62..e8940af5 100644
--- a/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java
+++ b/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java
@@ -9,12 +9,15 @@ import me.neatmonster.nocheatplus.NoCheatPlusPlayer;
import me.neatmonster.nocheatplus.config.ConfigurationCacheStore;
import me.neatmonster.nocheatplus.config.Permissions;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
import org.bukkit.event.EventHandler;
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;
+import org.bukkit.plugin.Plugin;
/**
* Central location to listen to events that are
@@ -86,6 +89,46 @@ public class ChatCheckListener implements Listener, EventManager {
@EventHandler(
priority = EventPriority.LOWEST)
public void commandPreprocess(final PlayerCommandPreprocessEvent event) {
+
+ final NoCheatPlusPlayer player = plugin.getPlayer(event.getPlayer());
+ final ChatConfig cc = ChatCheck.getConfig(player);
+
+ // If the command is /plugins or /pl
+ if ((event.getMessage().equalsIgnoreCase("/plugins")
+ || event.getMessage().toLowerCase().startsWith("/plugins ")
+ || event.getMessage().equalsIgnoreCase("/pl") || event.getMessage().toLowerCase().startsWith("/pl "))
+ && cc.hideNoCheatPlus) {
+ // If the player isn't allowed to use this command
+ if (!event.getPlayer().hasPermission("bukkit.command.plugins"))
+ // Fake the permissions error message
+ event.getPlayer().sendMessage(
+ ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. "
+ + "Please contact the server administrators if you believe that this is in error.");
+ else {
+ // Fake the plugins list
+ final StringBuilder pluginList = new StringBuilder();
+ final Plugin[] plugins = Bukkit.getPluginManager().getPlugins();
+
+ for (final Plugin plugin : plugins) {
+ // But make sure to hide NoCheatPlus
+ if (plugin.getName().equals("NoCheatPlus"))
+ continue;
+ if (pluginList.length() > 0) {
+ pluginList.append(ChatColor.WHITE);
+ pluginList.append(", ");
+ }
+
+ pluginList.append(plugin.isEnabled() ? ChatColor.GREEN : ChatColor.RED);
+ pluginList.append(plugin.getDescription().getName());
+ }
+
+ // Of course decrease the number of plugins
+ event.getPlayer().sendMessage("Plugins (" + (plugins.length - 1) + "): " + pluginList.toString());
+ }
+ // Cancel the event, we have already replied to the player
+ event.setCancelled(true);
+ }
+
// This type of event is derived from PlayerChatEvent, therefore
// just treat it like that
chat(event);
diff --git a/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java b/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java
index b8db4e1f..884389a4 100644
--- a/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java
+++ b/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java
@@ -17,6 +17,8 @@ import me.neatmonster.nocheatplus.config.Permissions;
*/
public class ChatConfig implements ConfigItem {
+ public final boolean hideNoCheatPlus;
+
public final boolean spamCheck;
public final String[] spamWhitelist;
public final long spamTimeframe;
@@ -35,6 +37,7 @@ public class ChatConfig implements ConfigItem {
public ChatConfig(final NoCheatPlusConfiguration data) {
+ hideNoCheatPlus = data.getBoolean(ConfPaths.CHAT_HIDENOCHEATPLUS);
spamCheck = data.getBoolean(ConfPaths.CHAT_SPAM_CHECK);
spamWhitelist = splitWhitelist(data.getString(ConfPaths.CHAT_SPAM_WHITELIST));
spamTimeframe = data.getInt(ConfPaths.CHAT_SPAM_TIMEFRAME) * 1000L;
diff --git a/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java b/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java
index 9b63d624..dcf40522 100644
--- a/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java
+++ b/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java
@@ -70,16 +70,22 @@ public class MovingCheckListener implements Listener, EventManager {
final MovingConfig cc = MovingCheck.getConfig(player);
final MovingData data = MovingCheck.getData(player);
+ final PreciseLocation location = new PreciseLocation();
+ location.x = bukkitPlayer.getLocation().getX();
+ location.y = bukkitPlayer.getLocation().getY();
+ location.z = bukkitPlayer.getLocation().getZ();
+ final int type = CheckUtil.evaluateLocation(bukkitPlayer.getWorld(), location);
+ final boolean isLiquid = CheckUtil.isLiquid(type);
+
// 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, 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)
- || bukkitPlayer.hasPermission(Permissions.MOVING_FLYING)
- || bukkitPlayer.getLocation().getBlock().getType() == Material.WATER
- || bukkitPlayer.getLocation().getBlock().getType() == Material.STATIONARY_WATER
+ || bukkitPlayer.hasPermission(Permissions.MOVING_FLYING) || isLiquid
|| bukkitPlayer.getLocation().getBlock().getType() == Material.LADDER
- || bukkitPlayer.getLocation().getBlock().getType() == Material.VINE) {
+ || bukkitPlayer.getLocation().getBlock().getType() == Material.VINE
+ || bukkitPlayer.getLocation().getX() < 0D) {
data.fallingSince = 0;
continue;
}
diff --git a/src/me/neatmonster/nocheatplus/config/ConfPaths.java b/src/me/neatmonster/nocheatplus/config/ConfPaths.java
index 5e10257e..54cedf86 100644
--- a/src/me/neatmonster/nocheatplus/config/ConfPaths.java
+++ b/src/me/neatmonster/nocheatplus/config/ConfPaths.java
@@ -130,6 +130,8 @@ public abstract class ConfPaths {
private final static String CHAT = CHECKS + "chat.";
+ public final static String CHAT_HIDENOCHEATPLUS = CHAT + "hidenocheatplus";
+
private final static String CHAT_COLOR = CHAT + "color.";
public final static String CHAT_COLOR_CHECK = CHAT_COLOR + "active";
public final static String CHAT_COLOR_ACTIONS = CHAT_COLOR + "actions";
diff --git a/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java b/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java
index 93a5d80e..1145b360 100644
--- a/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java
+++ b/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java
@@ -115,6 +115,8 @@ public class DefaultConfiguration extends NoCheatPlusConfiguration {
/*** CHAT ***/
+ set(ConfPaths.CHAT_HIDENOCHEATPLUS, true);
+
set(ConfPaths.CHAT_COLOR_CHECK, true);
set(ConfPaths.CHAT_COLOR_ACTIONS, "log:color:0:1:if cancel");