diff --git a/src/main/java/net/minecraftforge/server/command/CommandTreeBase.java b/src/main/java/net/minecraftforge/server/command/CommandTreeBase.java new file mode 100644 index 0000000000..3c7911ca08 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/command/CommandTreeBase.java @@ -0,0 +1,138 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.command; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommand; +import net.minecraft.command.ICommandSender; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentString; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +/** + * Base class for commands that has subcommands. + *

+ * E.g. /team settings set [value] + * settings is subcommand of team and set is subcommand of settings + */ +public abstract class CommandTreeBase extends CommandBase +{ + private final HashMap commandMap = new HashMap(); + + public void addSubcommand(ICommand c) + { + commandMap.put(c.getCommandName(), c); + } + + public Collection getSubCommands() + { + return Collections.unmodifiableCollection(commandMap.values()); + } + + private static String[] shiftArgs(String[] s) + { + if(s == null || s.length == 0) + { + return new String[0]; + } + + String[] s1 = new String[s.length - 1]; + System.arraycopy(s, 1, s1, 0, s1.length); + return s1; + } + + @Override + public List getTabCompletionOptions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos pos) + { + if(args.length == 1) + { + List keys = new ArrayList(); + + for(ICommand c : commandMap.values()) + { + if(c.checkPermission(server, sender)) + { + keys.add(c.getCommandName()); + } + } + + Collections.sort(keys, null); + return getListOfStringsMatchingLastWord(args, keys); + } + + ICommand cmd = commandMap.get(args[0]); + + if(cmd != null) + { + return cmd.getTabCompletionOptions(server, sender, shiftArgs(args), pos); + } + + return super.getTabCompletionOptions(server, sender, args, pos); + } + + @Override + public boolean isUsernameIndex(String[] args, int index) + { + if(index > 0 && args.length > 1) + { + ICommand cmd = commandMap.get(args[0]); + if(cmd != null) + { + return cmd.isUsernameIndex(shiftArgs(args), index - 1); + } + } + + return false; + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + if(args.length < 1) + { + sender.addChatMessage(new TextComponentString(CommandBase.joinNiceStringFromCollection(commandMap.keySet()))); + } + else + { + ICommand cmd = commandMap.get(args[0]); + + if(cmd == null) + { + throw new CommandException("commands.tree_base.invalid_cmd", args[0]); + } + else if(!cmd.checkPermission(server, sender)) + { + throw new CommandException("commands.generic.permission"); + } + else + { + cmd.execute(server, sender, shiftArgs(args)); + } + } + } +} diff --git a/src/main/resources/assets/forge/lang/en_US.lang b/src/main/resources/assets/forge/lang/en_US.lang index 55dd14dfc0..02c81a52e1 100644 --- a/src/main/resources/assets/forge/lang/en_US.lang +++ b/src/main/resources/assets/forge/lang/en_US.lang @@ -3,6 +3,7 @@ commands.forge.usage.tracking=Use /forge track . Valid types ar commands.forge.tps.summary=%s : Mean tick time: %d ms. Mean TPS: %d commands.forge.tracking.te.enabled=Tile Entity tracking enabled for %d seconds. +commands.tree_base.invalid_cmd=Invalid subcommand '%s'! forge.texture.preload.warning=Warning: Texture %s not preloaded, will cause render glitches! forge.client.shutdown.internal=Shutting down internal server... forge.update.newversion=New Forge version available: %s diff --git a/src/test/java/net/minecraftforge/test/CommandTreeBaseTest.java b/src/test/java/net/minecraftforge/test/CommandTreeBaseTest.java new file mode 100644 index 0000000000..c46c5cc415 --- /dev/null +++ b/src/test/java/net/minecraftforge/test/CommandTreeBaseTest.java @@ -0,0 +1,133 @@ +package net.minecraftforge.test; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.text.TextComponentString; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.event.FMLServerStartingEvent; +import net.minecraftforge.server.command.CommandTreeBase; + +@Mod(modid = CommandTreeBaseTest.MOD_ID, name = "CommandTreeBaseTest", version = "1.0.0") +public class CommandTreeBaseTest +{ + public static final String MOD_ID = "CommandTreeBaseTest"; + + @Mod.Instance(CommandTreeBaseTest.MOD_ID) + public static CommandTreeBaseTest inst; + + @Mod.EventHandler + public void onServerStarted(FMLServerStartingEvent event) + { + event.registerServerCommand(new CommandTreeTest()); + } + + public static class CommandTreeTest extends CommandTreeBase + { + public CommandTreeTest() + { + addSubcommand(new CommandPing()); + addSubcommand(new CommandValue()); + } + + @Override + public String getCommandName() + { + return "treecommand_test"; + } + + @Override + public String getCommandUsage(ICommandSender sender) + { + return "commands.treecommand_test.usage"; + } + + public static class CommandPing extends CommandBase + { + @Override + public String getCommandName() + { + return "ping"; + } + + @Override + public String getCommandUsage(ICommandSender sender) + { + return "commands.treecommand_test.ping.usage"; + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + sender.addChatMessage(new TextComponentString("Pong!")); + } + } + + public static class CommandValue extends CommandTreeBase + { + private static int value = 0; + + public CommandValue() + { + addSubcommand(new CommandSet()); + addSubcommand(new CommandGet()); + } + + @Override + public String getCommandName() + { + return "value"; + } + + @Override + public String getCommandUsage(ICommandSender sender) + { + return "commands.treecommand_test.value.usage"; + } + + public static class CommandSet extends CommandBase + { + @Override + public String getCommandName() + { + return "set"; + } + + @Override + public String getCommandUsage(ICommandSender sender) + { + return "commands.treecommand_test.value.set.usage"; + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + value = CommandTreeTest.parseInt(args[0]); + sender.addChatMessage(new TextComponentString("Test value set to: " + value)); + } + } + + public static class CommandGet extends CommandBase + { + @Override + public String getCommandName() + { + return "get"; + } + + @Override + public String getCommandUsage(ICommandSender sender) + { + return "commands.treecommand_test.value.get.usage"; + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + sender.addChatMessage(new TextComponentString("Test value: " + value)); + } + } + } + } +}