--- a/net/minecraft/server/CommandBlockListenerAbstract.java +++ b/net/minecraft/server/CommandBlockListenerAbstract.java @@ -4,6 +4,13 @@ import java.util.Date; import javax.annotation.Nullable; +// CraftBukkit start +import java.util.ArrayList; +import org.bukkit.craftbukkit.command.VanillaCommandWrapper; +import com.google.common.base.Joiner; +import java.util.logging.Level; +// CraftBukkit end + public abstract class CommandBlockListenerAbstract implements ICommandListener { private static final SimpleDateFormat a = new SimpleDateFormat("HH:mm:ss"); @@ -13,6 +20,7 @@ private String e = ""; private String f = "@"; private final CommandObjectiveExecutor g = new CommandObjectiveExecutor(); + protected org.bukkit.command.CommandSender sender; // CraftBukkit - add sender public CommandBlockListenerAbstract() {} @@ -92,7 +100,9 @@ try { this.d = null; - this.b = icommandhandler.a(this, this.e); + // CraftBukkit start - Handle command block commands using Bukkit dispatcher + this.b = executeSafely(this, sender, this.e); + // CraftBukkit end } catch (Throwable throwable) { CrashReport crashreport = CrashReport.a(throwable, "Executing command block"); CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Command to be executed"); @@ -124,6 +134,138 @@ } } + public static int executeSafely(ICommandListener sender, org.bukkit.command.CommandSender bSender, String command) { + try { + return executeCommand(sender, bSender, command); + } catch (CommandException commandexception) { + // Taken from CommandHandler + ChatMessage chatmessage = new ChatMessage(commandexception.getMessage(), commandexception.getArgs()); + chatmessage.getChatModifier().setColor(EnumChatFormat.RED); + sender.sendMessage(chatmessage); + } + + return 0; + } + + // CraftBukkit start + public static int executeCommand(ICommandListener sender, org.bukkit.command.CommandSender bSender, String command) throws CommandException { + org.bukkit.command.SimpleCommandMap commandMap = sender.getWorld().getServer().getCommandMap(); + Joiner joiner = Joiner.on(" "); + if (command.startsWith("/")) { + command = command.substring(1); + } + String[] args = command.split(" "); + ArrayList<String[]> commands = new ArrayList<String[]>(); + + String cmd = args[0]; + if (cmd.startsWith("minecraft:")) cmd = cmd.substring("minecraft:".length()); + if (cmd.startsWith("bukkit:")) cmd = cmd.substring("bukkit:".length()); + + // Block disallowed commands + if (cmd.equalsIgnoreCase("stop") || cmd.equalsIgnoreCase("kick") || cmd.equalsIgnoreCase("op") + || cmd.equalsIgnoreCase("deop") || cmd.equalsIgnoreCase("ban") || cmd.equalsIgnoreCase("ban-ip") + || cmd.equalsIgnoreCase("pardon") || cmd.equalsIgnoreCase("pardon-ip") || cmd.equalsIgnoreCase("reload")) { + return 0; + } + + // Handle vanilla commands; + org.bukkit.command.Command commandBlockCommand = commandMap.getCommand(args[0]); + if (sender.getWorld().getServer().getCommandBlockOverride(args[0])) { + commandBlockCommand = commandMap.getCommand("minecraft:" + args[0]); + } + if (commandBlockCommand instanceof VanillaCommandWrapper) { + command = command.trim(); + if (command.startsWith("/")) { + command = command.substring(1); + } + String as[] = command.split(" "); + as = VanillaCommandWrapper.dropFirstArgument(as); + if (!((VanillaCommandWrapper) commandBlockCommand).testPermission(bSender)) { + return 0; + } + return ((VanillaCommandWrapper) commandBlockCommand).dispatchVanillaCommand(bSender, sender, as); + } + + // Make sure this is a valid command + if (commandMap.getCommand(args[0]) == null) { + return 0; + } + + commands.add(args); + + // Find positions of command block syntax, if any + WorldServer[] prev = MinecraftServer.getServer().worldServer; + MinecraftServer server = MinecraftServer.getServer(); + server.worldServer = new WorldServer[server.worlds.size()]; + server.worldServer[0] = (WorldServer) sender.getWorld(); + int bpos = 0; + for (int pos = 1; pos < server.worldServer.length; pos++) { + WorldServer world = server.worlds.get(bpos++); + if (server.worldServer[0] == world) { + pos--; + continue; + } + server.worldServer[pos] = world; + } + try { + ArrayList<String[]> newCommands = new ArrayList<String[]>(); + for (int i = 0; i < args.length; i++) { + if (PlayerSelector.isPattern(args[i])) { + for (int j = 0; j < commands.size(); j++) { + newCommands.addAll(buildCommands(sender, commands.get(j), i)); + } + ArrayList<String[]> temp = commands; + commands = newCommands; + newCommands = temp; + newCommands.clear(); + } + } + } finally { + MinecraftServer.getServer().worldServer = prev; + } + + int completed = 0; + + // Now dispatch all of the commands we ended up with + for (int i = 0; i < commands.size(); i++) { + try { + if (commandMap.dispatch(bSender, joiner.join(java.util.Arrays.asList(commands.get(i))))) { + completed++; + } + } catch (Throwable exception) { + if (sender.f() instanceof EntityMinecartCommandBlock) { + MinecraftServer.getServer().server.getLogger().log(Level.WARNING, String.format("MinecartCommandBlock at (%d,%d,%d) failed to handle command", sender.getChunkCoordinates().getX(), sender.getChunkCoordinates().getY(), sender.getChunkCoordinates().getZ()), exception); + } else if (sender instanceof CommandBlockListenerAbstract) { + CommandBlockListenerAbstract listener = (CommandBlockListenerAbstract) sender; + MinecraftServer.getServer().server.getLogger().log(Level.WARNING, String.format("CommandBlock at (%d,%d,%d) failed to handle command", listener.getChunkCoordinates().getX(), listener.getChunkCoordinates().getY(), listener.getChunkCoordinates().getZ()), exception); + } else { + MinecraftServer.getServer().server.getLogger().log(Level.WARNING, String.format("Unknown CommandBlock failed to handle command"), exception); + } + } + } + + return completed; + } + + private static ArrayList<String[]> buildCommands(ICommandListener sender, String[] args, int pos) throws CommandException { + ArrayList<String[]> commands = new ArrayList<String[]>(); + java.util.List<EntityPlayer> players = (java.util.List<EntityPlayer>)PlayerSelector.getPlayers(sender, args[pos], EntityPlayer.class); + + if (players != null) { + for (EntityPlayer player : players) { + if (player.world != sender.getWorld()) { + continue; + } + String[] command = args.clone(); + command[pos] = player.getName(); + commands.add(command); + } + } + + return commands; + } + // CraftBukkit end + public String getName() { return this.f; }