sort of working Fabric commands

This commit is contained in:
dfsek
2021-03-09 03:07:02 -07:00
parent 5fc012f7ba
commit 0f39d64d72
11 changed files with 216 additions and 30 deletions
@@ -11,5 +11,7 @@ public interface CommandManager {
void register(String name, Class<? extends CommandTemplate> clazz) throws MalformedCommandException; void register(String name, Class<? extends CommandTemplate> clazz) throws MalformedCommandException;
List<String> tabComplete(String command, CommandSender sender, List<String> args) throws MalformedCommandException, CommandException; List<String> tabComplete(String command, CommandSender sender, List<String> args) throws CommandException;
int getMaxArgumentDepth();
} }
@@ -21,6 +21,7 @@ import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player; import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.api.util.ReflectionUtil; import com.dfsek.terra.api.util.ReflectionUtil;
import com.dfsek.terra.world.TerraWorld; import com.dfsek.terra.world.TerraWorld;
import net.jafama.FastMath;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; 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()); 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<String> tabComplete(CommandHolder holder, CommandSender sender, List<String> args) throws CommandException { private List<String> tabComplete(CommandHolder holder, CommandSender sender, List<String> args) throws CommandException {
if(args.isEmpty()) return Collections.emptyList(); if(args.isEmpty()) return Collections.emptyList();
List<String> completions = new ArrayList<>(); List<String> completions = new ArrayList<>();
@@ -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);
}
}
@@ -34,6 +34,8 @@ public class CommandTest {
manager.execute("test", null, Arrays.asList("sub1", "first", "2", "3.4")); 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("sub2", "first", "2"));
manager.execute("test", null, Arrays.asList("first", "2")); // Parent command args manager.execute("test", null, Arrays.asList("first", "2")); // Parent command args
System.out.println("ARGS: " + manager.getMaxArgumentDepth());
} }
@Test @Test
@@ -32,8 +32,7 @@ import com.dfsek.terra.bukkit.listeners.SpigotListener;
import com.dfsek.terra.bukkit.listeners.TerraListener; import com.dfsek.terra.bukkit.listeners.TerraListener;
import com.dfsek.terra.bukkit.util.PaperUtil; import com.dfsek.terra.bukkit.util.PaperUtil;
import com.dfsek.terra.bukkit.world.BukkitBiome; import com.dfsek.terra.bukkit.world.BukkitBiome;
import com.dfsek.terra.commands.StructureCommand; import com.dfsek.terra.commands.CommandUtil;
import com.dfsek.terra.commands.profiler.ProfileCommand;
import com.dfsek.terra.config.GenericLoaders; import com.dfsek.terra.config.GenericLoaders;
import com.dfsek.terra.config.PluginConfig; import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.lang.LangUtil;
@@ -173,8 +172,7 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
try { try {
manager.register("structure", StructureCommand.class); CommandUtil.registerAll(manager);
manager.register("profile", ProfileCommand.class);
} catch(MalformedCommandException e) { // This should never happen. } catch(MalformedCommandException e) { // This should never happen.
logger().severe("Errors occurred while registering commands."); logger().severe("Errors occurred while registering commands.");
e.printStackTrace(); e.printStackTrace();
@@ -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.Addon;
import com.dfsek.terra.api.addons.annotations.Author; import com.dfsek.terra.api.addons.annotations.Author;
import com.dfsek.terra.api.addons.annotations.Version; 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.EventListener;
import com.dfsek.terra.api.event.EventManager; import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.event.TerraEventManager; 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.DebugLogger;
import com.dfsek.terra.api.util.logging.Logger; import com.dfsek.terra.api.util.logging.Logger;
import com.dfsek.terra.api.world.tree.Tree; 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.GenericLoaders;
import com.dfsek.terra.config.PluginConfig; import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.builder.BiomeBuilder; 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.config.pack.ConfigPack;
import com.dfsek.terra.fabric.inventory.FabricItemHandle; import com.dfsek.terra.fabric.inventory.FabricItemHandle;
import com.dfsek.terra.fabric.mixin.GeneratorTypeAccessor; 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.FabricBiome;
import com.dfsek.terra.fabric.world.FabricTree; import com.dfsek.terra.fabric.world.FabricTree;
import com.dfsek.terra.fabric.world.FabricWorldHandle; 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.AddonRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry; import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.world.TerraWorld; 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.EnvType;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.client.world.GeneratorType; import net.minecraft.client.world.GeneratorType;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.util.registry.BuiltinRegistries;
@@ -75,29 +86,24 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
public class TerraFabricPlugin implements TerraPlugin, ModInitializer { public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
private final Map<Long, TerraWorld> 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 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)); 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<Long, TerraWorld> worldMap = new HashMap<>();
private final EventManager eventManager = new TerraEventManager(this);
private final GenericLoaders genericLoaders = new GenericLoaders(this); private final GenericLoaders genericLoaders = new GenericLoaders(this);
private final Logger logger = new Logger() { private final Logger logger = new Logger() {
private final org.apache.logging.log4j.Logger logger = LogManager.getLogger(); private final org.apache.logging.log4j.Logger logger = LogManager.getLogger();
@Override @Override
public void info(String message) { public void info(String message) {
logger.info(message); logger.info(message);
@@ -114,20 +120,25 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
} }
}; };
private final DebugLogger debugLogger = new DebugLogger(logger); private final DebugLogger debugLogger = new DebugLogger(logger);
private final ItemHandle itemHandle = new FabricItemHandle(); private final ItemHandle itemHandle = new FabricItemHandle();
private final WorldHandle worldHandle = new FabricWorldHandle(); private final WorldHandle worldHandle = new FabricWorldHandle();
private final ConfigRegistry registry = new ConfigRegistry(); private final ConfigRegistry registry = new ConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedRegistry = new CheckedRegistry<>(registry); private final CheckedRegistry<ConfigPack> checkedRegistry = new CheckedRegistry<>(registry);
private final AddonRegistry addonRegistry = new AddonRegistry(new FabricAddon(this), this); private final AddonRegistry addonRegistry = new AddonRegistry(new FabricAddon(this), this);
private final LockedRegistry<TerraAddon> addonLockedRegistry = new LockedRegistry<>(addonRegistry); private final LockedRegistry<TerraAddon> addonLockedRegistry = new LockedRegistry<>(addonRegistry);
private final PluginConfig plugin = new PluginConfig();
private final Transformer<String, Biome> biomeFixer = new Transformer.Builder<String, Biome>()
.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 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 @Override
public WorldHandle getWorldHandle() { public WorldHandle getWorldHandle() {
@@ -208,10 +219,6 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
return debugLogger; return debugLogger;
} }
private final Transformer<String, Biome> biomeFixer = new Transformer.Builder<String, Biome>()
.addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse(id)), new NotNullValidator<>())
.addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse("minecraft:" + id.toLowerCase())), new NotNullValidator<>()).build();
@Override @Override
public void register(TypeRegistry registry) { public void register(TypeRegistry registry) {
genericLoaders.register(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))); .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) { private Biome createBiome(BiomeBuilder biome) {
SpawnSettings.Builder spawnSettings = new SpawnSettings.Builder(); SpawnSettings.Builder spawnSettings = new SpawnSettings.Builder();
DefaultBiomeFeatures.addFarmAnimals(spawnSettings); DefaultBiomeFeatures.addFarmAnimals(spawnSettings);
@@ -258,6 +261,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
.build(); .build();
} }
@SuppressWarnings("unchecked")
@Override @Override
public void onInitialize() { public void onInitialize() {
instance = this; 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<ServerCommandSource> 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<ServerCommandSource, String> arg = RequiredArgumentBuilder.argument("arg0", StringArgumentType.string());
for(int i = 0; i < max; i++) {
System.out.println("arg " + i);
int finalI = i;
RequiredArgumentBuilder<ServerCommandSource, String> next = RequiredArgumentBuilder.argument("arg" + i, StringArgumentType.string());
arg = arg.then(next.suggests((context, builder) -> {
List<String> 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<String> 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<String> 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(" ")));
} }
@@ -0,0 +1,7 @@
package com.dfsek.terra.fabric.command;
public class FabricCommandAdapter {
public static void register() {
}
}
@@ -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<List<String>> {
@Override
public List<String> parse(StringReader reader) {
final String text = reader.getRemaining();
reader.setCursor(reader.getTotalLength());
return new ArrayList<>(Arrays.asList(text.split(" ")));
}
}
@@ -1,6 +1,7 @@
package com.dfsek.terra.fabric.world; package com.dfsek.terra.fabric.world;
import com.dfsek.terra.api.math.vector.Vector3; 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.BlockFace;
import com.dfsek.terra.api.platform.block.BlockType; import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.api.platform.entity.EntityType; 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.FabricSlab;
import com.dfsek.terra.fabric.world.block.data.FabricStairs; import com.dfsek.terra.fabric.world.block.data.FabricStairs;
import com.dfsek.terra.fabric.world.block.data.FabricWaterlogged; 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.FabricEntityType;
import com.dfsek.terra.fabric.world.entity.FabricPlayer;
import com.dfsek.terra.fabric.world.handles.world.FabricWorldHandle; import com.dfsek.terra.fabric.world.handles.world.FabricWorldHandle;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.state.property.Properties; import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
@@ -60,6 +65,11 @@ public final class FabricAdapter {
return new FabricBlockData(state); 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) { public static Direction adapt(BlockFace face) {
switch(face) { switch(face) {
case NORTH: case NORTH:
@@ -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;
}
}
@@ -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);
}
}