Posted March 2, 20232 yr I'm trying to create a mod that lets me define command aliases in MC. I currently have the following code: package com.extended_ui.commands; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.commons.io.IOUtils; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import net.minecraft.client.Minecraft; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.network.chat.Component; public class Alias { private static Map<String, String> aliases = new HashMap<String, String>(); public static void registerCommands(CommandDispatcher<CommandSourceStack> dispatcher) { loadAliasesFromFiles(); for (Map.Entry<String, String> entry : aliases.entrySet()) { registerAlias(dispatcher, entry.getKey(), entry.getValue()); } dispatcher.register(Commands.literal("alias") .then(Commands.literal("-l") .executes((command) -> { return listAliases(); })) .then(Commands.literal("-r") .then(Commands.argument("alias", StringArgumentType.word()) .executes((command) -> { return removeAlias(dispatcher, StringArgumentType.getString(command, "alias")); }))) .then(Commands.argument("alias", StringArgumentType.word()) .then(Commands.argument("command", StringArgumentType.greedyString()) .executes((command) -> { return addAlias(dispatcher, StringArgumentType.getString(command, "alias"), StringArgumentType.getString(command, "command")); }))) ); } private static int listAliases() { Minecraft mc = Minecraft.getInstance(); for (Map.Entry<String, String> entry : aliases.entrySet()) { mc.player.sendSystemMessage(Component.literal(entry.getKey() + ": " + entry.getValue())); } return Command.SINGLE_SUCCESS; } private static int addAlias(CommandDispatcher<CommandSourceStack> dispatcher, String alias, String command) { // Add alias to the map of aliases aliases.put(alias, command); // Save alias to file try { new File("config/aliases").mkdirs(); Files.write(Paths.get("config/aliases/" + alias), Collections.singletonList(command), StandardCharsets.UTF_8); } catch (IOException e) { e.printStackTrace(); } // Register new alias in the event dispatcher return registerAlias(dispatcher, alias, command); } private static int registerAlias(CommandDispatcher<CommandSourceStack> dispatcher, String alias, String command) { // dispatcher.register(Commands.literal(alias) // .then(Commands.argument("args", StringArgumentType.greedyString()) // .redirect(command))); return Command.SINGLE_SUCCESS; } private static int removeAlias(CommandDispatcher<CommandSourceStack> dispatcher, String alias) { // Remove alias from the map of aliases aliases.remove(alias); // Remove alias file new File("config/aliases/" + alias).delete(); // Remove alias from the event dispatcher // dispatcher.unregister(Commands.literal(alias)); // Not sure the dispatcher supports some way of unregistering commands. If it doesn't, then removing an alias properly will require a game restart return Command.SINGLE_SUCCESS; } private static void loadAliasesFromFiles() { File dir = new File("config/aliases"); if (!(dir.isDirectory())) return; for (File file : dir.listFiles()) { String alias = file.getName(); try (FileInputStream inputStream = new FileInputStream("foo.txt")) { String command = IOUtils.toString(inputStream, StandardCharsets.UTF_8).trim(); aliases.put(alias, command); } catch (IOException e) { e.printStackTrace(); } } } } The methods for adding, removing, loading, and listing aliases all work properly (i.e., they add/remove/list the aliases in the aliases Map, and save/remove/load the aliases to/from files). However, right now registering an alias doesn't work, as I can't find a way to register an alias to simply execute the command as if it was sent in the game console. How would I implement the registerAlias method to properly register such a simple forward with the CommandDispatcher? Edited March 8, 20232 yr by Frozen Storm
March 2, 20232 yr Author I managed to get basic aliases to work using: private static int registerAlias(CommandDispatcher<CommandSourceStack> dispatcher, String alias, String command) { dispatcher.register(Commands.literal(alias) .executes((commandContext) -> { dispatcher.execute(command, commandContext.getSource()); return Command.SINGLE_SUCCESS; }) ); } I also managed to add the possibility for arguments in the alias, and my entire method looks like this now: private static int registerAlias(CommandDispatcher<CommandSourceStack> dispatcher, String alias, String command) { Pattern argPattern = Pattern.compile("\\$\\{?(\\d+)}?"); if (argPattern.matcher(command).find()) { dispatcher.register(Commands.literal(alias) .then(Commands.argument("args", StringArgumentType.greedyString()) .executes((commandContext) -> { String commandString = command; String argString = StringArgumentType.getString(commandContext, "args"); String[] args = ArgumentTokenizer.tokenize(argString).toArray(new String[0]); commandString = argPattern.matcher(commandString).replaceAll( match -> args[Integer.parseInt(match.group(1))-1] ); dispatcher.execute(commandString, commandContext.getSource()); return Command.SINGLE_SUCCESS; })) ); } else { dispatcher.register(Commands.literal(alias) .executes((commandContext) -> { dispatcher.execute(command, commandContext.getSource()); return Command.SINGLE_SUCCESS; }) ); } return Command.SINGLE_SUCCESS; } This way if a command contains any $1, $2, $10, ${1}, etc., it gets registered as an alias with arguments, otherwise it gets registered as a standalone. ArgumentTokenizer is the class I found here. Edited March 2, 20232 yr by Frozen Storm Different question for different thread
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.