From 0f39d64d721e9e3a2dc096b61fd88b396122ef03 Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 9 Mar 2021 03:07:02 -0700 Subject: [PATCH] sort of working Fabric commands --- .../terra/api/command/CommandManager.java | 4 +- .../api/command/TerraCommandManager.java | 19 +++ .../com/dfsek/terra/commands/CommandUtil.java | 12 ++ common/src/test/java/command/CommandTest.java | 2 + .../dfsek/terra/bukkit/TerraBukkitPlugin.java | 6 +- .../dfsek/terra/fabric/TerraFabricPlugin.java | 109 ++++++++++++++---- .../fabric/command/FabricCommandAdapter.java | 7 ++ .../command/StringListArgumentType.java | 17 +++ .../terra/fabric/world/FabricAdapter.java | 10 ++ .../world/entity/FabricCommandSender.java | 23 ++++ .../fabric/world/entity/FabricPlayer.java | 37 ++++++ 11 files changed, 216 insertions(+), 30 deletions(-) create mode 100644 common/src/main/java/com/dfsek/terra/commands/CommandUtil.java create mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/command/FabricCommandAdapter.java create mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/command/StringListArgumentType.java create mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/entity/FabricCommandSender.java create mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/entity/FabricPlayer.java diff --git a/common/src/main/java/com/dfsek/terra/api/command/CommandManager.java b/common/src/main/java/com/dfsek/terra/api/command/CommandManager.java index d2ff2c820..a33d70921 100644 --- a/common/src/main/java/com/dfsek/terra/api/command/CommandManager.java +++ b/common/src/main/java/com/dfsek/terra/api/command/CommandManager.java @@ -11,5 +11,7 @@ public interface CommandManager { void register(String name, Class clazz) throws MalformedCommandException; - List tabComplete(String command, CommandSender sender, List args) throws MalformedCommandException, CommandException; + List tabComplete(String command, CommandSender sender, List args) throws CommandException; + + int getMaxArgumentDepth(); } diff --git a/common/src/main/java/com/dfsek/terra/api/command/TerraCommandManager.java b/common/src/main/java/com/dfsek/terra/api/command/TerraCommandManager.java index ec2a46c42..bc729e041 100644 --- a/common/src/main/java/com/dfsek/terra/api/command/TerraCommandManager.java +++ b/common/src/main/java/com/dfsek/terra/api/command/TerraCommandManager.java @@ -21,6 +21,7 @@ import com.dfsek.terra.api.platform.CommandSender; import com.dfsek.terra.api.platform.entity.Player; import com.dfsek.terra.api.util.ReflectionUtil; import com.dfsek.terra.world.TerraWorld; +import net.jafama.FastMath; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -182,6 +183,24 @@ public class TerraCommandManager implements CommandManager { return tabComplete(commands.get(command), sender, new ArrayList<>(args)).stream().filter(s -> s.toLowerCase().startsWith(args.get(args.size() - 1).toLowerCase())).sorted(String::compareTo).collect(Collectors.toList()); } + @Override + public int getMaxArgumentDepth() { + int max = 0; + for(CommandHolder value : commands.values()) { + max = FastMath.max(getMaxArgumentDepth(value), max); + } + return max; + } + + private int getMaxArgumentDepth(CommandHolder holder) { + int max = 0; + max = FastMath.max(holder.arguments.size(), max); + for(CommandHolder value : holder.subcommands.values()) { + max = FastMath.max(max, getMaxArgumentDepth(value) + 1); + } + return max; + } + private List tabComplete(CommandHolder holder, CommandSender sender, List args) throws CommandException { if(args.isEmpty()) return Collections.emptyList(); List completions = new ArrayList<>(); diff --git a/common/src/main/java/com/dfsek/terra/commands/CommandUtil.java b/common/src/main/java/com/dfsek/terra/commands/CommandUtil.java new file mode 100644 index 000000000..bac8bc882 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/commands/CommandUtil.java @@ -0,0 +1,12 @@ +package com.dfsek.terra.commands; + +import com.dfsek.terra.api.command.CommandManager; +import com.dfsek.terra.api.command.exception.MalformedCommandException; +import com.dfsek.terra.commands.profiler.ProfileCommand; + +public final class CommandUtil { + public static void registerAll(CommandManager manager) throws MalformedCommandException { + manager.register("structure", StructureCommand.class); + manager.register("profile", ProfileCommand.class); + } +} diff --git a/common/src/test/java/command/CommandTest.java b/common/src/test/java/command/CommandTest.java index 343b4971a..f3cd29337 100644 --- a/common/src/test/java/command/CommandTest.java +++ b/common/src/test/java/command/CommandTest.java @@ -34,6 +34,8 @@ public class CommandTest { manager.execute("test", null, Arrays.asList("sub1", "first", "2", "3.4")); manager.execute("test", null, Arrays.asList("sub2", "first", "2")); manager.execute("test", null, Arrays.asList("first", "2")); // Parent command args + + System.out.println("ARGS: " + manager.getMaxArgumentDepth()); } @Test diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java index 5b436b084..7a4a3ed5b 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java @@ -32,8 +32,7 @@ import com.dfsek.terra.bukkit.listeners.SpigotListener; import com.dfsek.terra.bukkit.listeners.TerraListener; import com.dfsek.terra.bukkit.util.PaperUtil; import com.dfsek.terra.bukkit.world.BukkitBiome; -import com.dfsek.terra.commands.StructureCommand; -import com.dfsek.terra.commands.profiler.ProfileCommand; +import com.dfsek.terra.commands.CommandUtil; import com.dfsek.terra.config.GenericLoaders; import com.dfsek.terra.config.PluginConfig; import com.dfsek.terra.config.lang.LangUtil; @@ -173,8 +172,7 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin { try { - manager.register("structure", StructureCommand.class); - manager.register("profile", ProfileCommand.class); + CommandUtil.registerAll(manager); } catch(MalformedCommandException e) { // This should never happen. logger().severe("Errors occurred while registering commands."); e.printStackTrace(); diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java index 8f83ecea1..7f0ad0871 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java @@ -6,6 +6,10 @@ import com.dfsek.terra.api.addons.TerraAddon; import com.dfsek.terra.api.addons.annotations.Addon; import com.dfsek.terra.api.addons.annotations.Author; import com.dfsek.terra.api.addons.annotations.Version; +import com.dfsek.terra.api.command.CommandManager; +import com.dfsek.terra.api.command.TerraCommandManager; +import com.dfsek.terra.api.command.exception.CommandException; +import com.dfsek.terra.api.command.exception.MalformedCommandException; import com.dfsek.terra.api.event.EventListener; import com.dfsek.terra.api.event.EventManager; import com.dfsek.terra.api.event.TerraEventManager; @@ -23,6 +27,7 @@ import com.dfsek.terra.api.transform.Transformer; import com.dfsek.terra.api.util.logging.DebugLogger; import com.dfsek.terra.api.util.logging.Logger; import com.dfsek.terra.api.world.tree.Tree; +import com.dfsek.terra.commands.CommandUtil; import com.dfsek.terra.config.GenericLoaders; import com.dfsek.terra.config.PluginConfig; import com.dfsek.terra.config.builder.BiomeBuilder; @@ -31,6 +36,7 @@ import com.dfsek.terra.config.lang.Language; import com.dfsek.terra.config.pack.ConfigPack; import com.dfsek.terra.fabric.inventory.FabricItemHandle; import com.dfsek.terra.fabric.mixin.GeneratorTypeAccessor; +import com.dfsek.terra.fabric.world.FabricAdapter; import com.dfsek.terra.fabric.world.FabricBiome; import com.dfsek.terra.fabric.world.FabricTree; import com.dfsek.terra.fabric.world.FabricWorldHandle; @@ -42,11 +48,16 @@ import com.dfsek.terra.registry.exception.DuplicateEntryException; import com.dfsek.terra.registry.master.AddonRegistry; import com.dfsek.terra.registry.master.ConfigRegistry; import com.dfsek.terra.world.TerraWorld; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.block.Blocks; import net.minecraft.client.world.GeneratorType; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.LiteralText; import net.minecraft.util.Identifier; import net.minecraft.util.registry.BuiltinRegistries; @@ -75,29 +86,24 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; public class TerraFabricPlugin implements TerraPlugin, ModInitializer { - private final Map worldMap = new HashMap<>(); - private static TerraFabricPlugin instance; - - private final EventManager eventManager = new TerraEventManager(this); - - - public static TerraFabricPlugin getInstance() { - return instance; - } - public static final PopulatorFeature POPULATOR_FEATURE = new PopulatorFeature(DefaultFeatureConfig.CODEC); public static final ConfiguredFeature POPULATOR_CONFIGURED_FEATURE = POPULATOR_FEATURE.configure(FeatureConfig.DEFAULT).decorate(Decorator.NOPE.configure(NopeDecoratorConfig.INSTANCE)); - + private static TerraFabricPlugin instance; + private final Map worldMap = new HashMap<>(); + private final EventManager eventManager = new TerraEventManager(this); private final GenericLoaders genericLoaders = new GenericLoaders(this); private final Logger logger = new Logger() { private final org.apache.logging.log4j.Logger logger = LogManager.getLogger(); + @Override public void info(String message) { logger.info(message); @@ -114,20 +120,25 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { } }; private final DebugLogger debugLogger = new DebugLogger(logger); - - private final ItemHandle itemHandle = new FabricItemHandle(); private final WorldHandle worldHandle = new FabricWorldHandle(); private final ConfigRegistry registry = new ConfigRegistry(); private final CheckedRegistry checkedRegistry = new CheckedRegistry<>(registry); - private final AddonRegistry addonRegistry = new AddonRegistry(new FabricAddon(this), this); private final LockedRegistry addonLockedRegistry = new LockedRegistry<>(addonRegistry); - - + private final PluginConfig plugin = new PluginConfig(); + private final Transformer biomeFixer = new Transformer.Builder() + .addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse(id)), new NotNullValidator<>()) + .addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse("minecraft:" + id.toLowerCase())), new NotNullValidator<>()).build(); private File config; - private final PluginConfig plugin = new PluginConfig(); + public static TerraFabricPlugin getInstance() { + return instance; + } + + public static String createBiomeID(ConfigPack pack, String biomeID) { + return pack.getTemplate().getID().toLowerCase() + "/" + biomeID.toLowerCase(Locale.ROOT); + } @Override public WorldHandle getWorldHandle() { @@ -208,10 +219,6 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { return debugLogger; } - private final Transformer biomeFixer = new Transformer.Builder() - .addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse(id)), new NotNullValidator<>()) - .addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse("minecraft:" + id.toLowerCase())), new NotNullValidator<>()).build(); - @Override public void register(TypeRegistry registry) { genericLoaders.register(registry); @@ -220,10 +227,6 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { .registerLoader(com.dfsek.terra.api.platform.world.Biome.class, (t, o, l) -> new FabricBiome(biomeFixer.translate((String) o))); } - public static String createBiomeID(ConfigPack pack, String biomeID) { - return pack.getTemplate().getID().toLowerCase() + "/" + biomeID.toLowerCase(Locale.ROOT); - } - private Biome createBiome(BiomeBuilder biome) { SpawnSettings.Builder spawnSettings = new SpawnSettings.Builder(); DefaultBiomeFeatures.addFarmAnimals(spawnSettings); @@ -258,6 +261,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { .build(); } + @SuppressWarnings("unchecked") @Override public void onInitialize() { instance = this; @@ -299,6 +303,61 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { }); } + CommandManager manager = new TerraCommandManager(this); + try { + CommandUtil.registerAll(manager); + } catch(MalformedCommandException e) { + e.printStackTrace(); // TODO do something here even though this should literally never happen + } + + + CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { + LiteralArgumentBuilder argumentBuilder = net.minecraft.server.command.CommandManager.literal("terra").executes(context -> { + System.out.println(context.getNodes()); + System.out.println(context); + System.out.println(context.getInput()); + return 1; + }); + + int max = manager.getMaxArgumentDepth(); + System.out.println("MAX:" + max); + RequiredArgumentBuilder arg = RequiredArgumentBuilder.argument("arg0", StringArgumentType.string()); + for(int i = 0; i < max; i++) { + System.out.println("arg " + i); + int finalI = i; + RequiredArgumentBuilder next = RequiredArgumentBuilder.argument("arg" + i, StringArgumentType.string()); + + arg = arg.then(next.suggests((context, builder) -> { + List args = parseCommand(context.getInput()); + System.out.println("Tab completing " + finalI); + System.out.println(args); + try { + manager.tabComplete(args.remove(0), FabricAdapter.adapt(context.getSource()), args).forEach(builder::suggest); + } catch(CommandException e) { + e.printStackTrace(); + } + return builder.buildFuture(); + }).executes(context -> { + List args = parseCommand(context.getInput()); + try { + manager.execute(args.remove(0), FabricAdapter.adapt(context.getSource()), args); + } catch(CommandException e) { + e.printStackTrace(); + return -1; + } + return 1; + })); + } + dispatcher.register(argumentBuilder.then(arg)); + } + ); + + } + + private List parseCommand(String command) { + if(command.startsWith("/terra ")) command = command.substring("/terra ".length()); + else if(command.startsWith("/te ")) command = command.substring("/te ".length()); + return new ArrayList<>(Arrays.asList(command.split(" "))); } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/command/FabricCommandAdapter.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/command/FabricCommandAdapter.java new file mode 100644 index 000000000..a8db1bb54 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/command/FabricCommandAdapter.java @@ -0,0 +1,7 @@ +package com.dfsek.terra.fabric.command; + +public class FabricCommandAdapter { + public static void register() { + + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/command/StringListArgumentType.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/command/StringListArgumentType.java new file mode 100644 index 000000000..392aaf1af --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/command/StringListArgumentType.java @@ -0,0 +1,17 @@ +package com.dfsek.terra.fabric.command; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class StringListArgumentType implements ArgumentType> { + @Override + public List parse(StringReader reader) { + final String text = reader.getRemaining(); + reader.setCursor(reader.getTotalLength()); + return new ArrayList<>(Arrays.asList(text.split(" "))); + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/FabricAdapter.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/FabricAdapter.java index eb73af5a7..e151013f0 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/FabricAdapter.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/FabricAdapter.java @@ -1,6 +1,7 @@ package com.dfsek.terra.fabric.world; import com.dfsek.terra.api.math.vector.Vector3; +import com.dfsek.terra.api.platform.CommandSender; import com.dfsek.terra.api.platform.block.BlockFace; import com.dfsek.terra.api.platform.block.BlockType; import com.dfsek.terra.api.platform.entity.EntityType; @@ -17,13 +18,17 @@ import com.dfsek.terra.fabric.world.block.data.FabricRotatable; import com.dfsek.terra.fabric.world.block.data.FabricSlab; import com.dfsek.terra.fabric.world.block.data.FabricStairs; import com.dfsek.terra.fabric.world.block.data.FabricWaterlogged; +import com.dfsek.terra.fabric.world.entity.FabricCommandSender; import com.dfsek.terra.fabric.world.entity.FabricEntityType; +import com.dfsek.terra.fabric.world.entity.FabricPlayer; import com.dfsek.terra.fabric.world.handles.world.FabricWorldHandle; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.state.property.Properties; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -60,6 +65,11 @@ public final class FabricAdapter { return new FabricBlockData(state); } + public static CommandSender adapt(ServerCommandSource serverCommandSource) { + if(serverCommandSource.getEntity() instanceof PlayerEntity) return new FabricPlayer((PlayerEntity) serverCommandSource.getEntity()); + return new FabricCommandSender(serverCommandSource); + } + public static Direction adapt(BlockFace face) { switch(face) { case NORTH: diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/entity/FabricCommandSender.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/entity/FabricCommandSender.java new file mode 100644 index 000000000..e7f946008 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/entity/FabricCommandSender.java @@ -0,0 +1,23 @@ +package com.dfsek.terra.fabric.world.entity; + +import com.dfsek.terra.api.platform.CommandSender; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.LiteralText; + +public class FabricCommandSender implements CommandSender { + private final ServerCommandSource delegate; + + public FabricCommandSender(ServerCommandSource delegate) { + this.delegate = delegate; + } + + @Override + public void sendMessage(String message) { + delegate.sendFeedback(new LiteralText(message), true); + } + + @Override + public Object getHandle() { + return delegate; + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/entity/FabricPlayer.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/entity/FabricPlayer.java new file mode 100644 index 000000000..d57d9d642 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/world/entity/FabricPlayer.java @@ -0,0 +1,37 @@ +package com.dfsek.terra.fabric.world.entity; + +import com.dfsek.terra.api.math.vector.Location; +import com.dfsek.terra.api.platform.entity.Player; +import com.dfsek.terra.api.platform.world.World; +import com.dfsek.terra.fabric.world.FabricAdapter; +import com.dfsek.terra.fabric.world.handles.world.FabricWorldAccess; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.text.LiteralText; + +public class FabricPlayer implements Player { + private final PlayerEntity delegate; + + public FabricPlayer(PlayerEntity delegate) { + this.delegate = delegate; + } + + @Override + public void sendMessage(String message) { + delegate.sendMessage(new LiteralText(message), false); + } + + @Override + public Object getHandle() { + return delegate; + } + + @Override + public Location getLocation() { + return FabricAdapter.adapt(delegate.getBlockPos()).toLocation(new FabricWorldAccess(delegate.world)); + } + + @Override + public World getWorld() { + return new FabricWorldAccess(delegate.world); + } +}