From 56c14f8f07248478960ace6d6106ddbb5e79180b Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 12 Jan 2016 23:00:58 -0600 Subject: [PATCH] Force commands to be dispatched synchronously [22:29:12] just add that [22:29:17] that forces it fixed [22:29:31] and then when his users spam him hell fix it :P --- ...83-Ensure-commands-are-not-ran-async.patch | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Spigot-Server-Patches/0083-Ensure-commands-are-not-ran-async.patch diff --git a/Spigot-Server-Patches/0083-Ensure-commands-are-not-ran-async.patch b/Spigot-Server-Patches/0083-Ensure-commands-are-not-ran-async.patch new file mode 100644 index 000000000..50e5d8ebb --- /dev/null +++ b/Spigot-Server-Patches/0083-Ensure-commands-are-not-ran-async.patch @@ -0,0 +1,86 @@ +From 3d5bf73817dbd5e89595cc27a80a9cfe0b5860eb Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Wed, 8 Oct 2014 19:51:28 -0400 +Subject: [PATCH] Ensure commands are not ran async + +Plugins calling Player.chat("/foo") or Server.dispatchCommand() could +trigger the server to execute a command while on another thread. + +These commands would then process EXPECTING to be on the main thread, leaving to +very hard to trace concurrency issues. + +This change will synchronize the command execution back to the main thread, causing a +big slowdown in execution but throwing an exception at same time to raise awareness +that it is happening so that plugin authors can fix their code to stop executing commands async. + +diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java +index 1138042..4391ad7 100644 +--- a/src/main/java/net/minecraft/server/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/PlayerConnection.java +@@ -1079,6 +1079,29 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList + } + + if (!async && s.startsWith("/")) { ++ // PaperSpigot Start ++ if (!org.bukkit.Bukkit.isPrimaryThread()) { ++ final String fCommandLine = s; ++ MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Command Dispatched Async: " + fCommandLine); ++ MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable()); ++ Waitable wait = new Waitable() { ++ @Override ++ protected Object evaluate() { ++ chat(fCommandLine, false); ++ return null; ++ } ++ }; ++ minecraftServer.processQueue.add(wait); ++ try { ++ wait.get(); ++ return; ++ } catch (InterruptedException e) { ++ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on! ++ } catch (Exception e) { ++ throw new RuntimeException("Exception processing chat command", e.getCause()); ++ } ++ } ++ // PaperSpigot End + this.handleCommand(s); + } else if (this.player.getChatFlags() == EntityHuman.EnumChatVisibility.SYSTEM) { + // Do nothing, this is coming from a plugin +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 97f9f96..a54b3e8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -639,6 +639,29 @@ public final class CraftServer implements Server { + Validate.notNull(sender, "Sender cannot be null"); + Validate.notNull(commandLine, "CommandLine cannot be null"); + ++ // PaperSpigot Start ++ if (!Bukkit.isPrimaryThread()) { ++ final CommandSender fSender = sender; ++ final String fCommandLine = commandLine; ++ Bukkit.getLogger().log(Level.SEVERE, "Command Dispatched Async: " + commandLine); ++ Bukkit.getLogger().log(Level.SEVERE, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable()); ++ org.bukkit.craftbukkit.util.Waitable wait = new org.bukkit.craftbukkit.util.Waitable() { ++ @Override ++ protected Boolean evaluate() { ++ return dispatchCommand(fSender, fCommandLine); ++ } ++ }; ++ net.minecraft.server.MinecraftServer.getServer().processQueue.add(wait); ++ try { ++ return wait.get(); ++ } catch (InterruptedException e) { ++ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on! ++ } catch (Exception e) { ++ throw new RuntimeException("Exception processing dispatch command", e.getCause()); ++ } ++ } ++ // PaperSpigot End ++ + if (commandMap.dispatch(sender, commandLine)) { + return true; + } +-- +2.7.0 +