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

View File

@@ -11,5 +11,7 @@ public interface CommandManager {
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();
}

View File

@@ -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<String> tabComplete(CommandHolder holder, CommandSender sender, List<String> args) throws CommandException {
if(args.isEmpty()) return Collections.emptyList();
List<String> completions = new ArrayList<>();

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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();

View File

@@ -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<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 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 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<ConfigPack> checkedRegistry = new CheckedRegistry<>(registry);
private final AddonRegistry addonRegistry = new AddonRegistry(new FabricAddon(this), this);
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 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<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
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<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(" ")));
}

View File

@@ -0,0 +1,7 @@
package com.dfsek.terra.fabric.command;
public class FabricCommandAdapter {
public static void register() {
}
}

View File

@@ -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(" ")));
}
}

View File

@@ -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:

View File

@@ -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;
}
}

View File

@@ -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);
}
}