From 2c52a5a63b7f3797fc861c6bc5c2012e7cd9214e Mon Sep 17 00:00:00 2001 From: JFronny Date: Wed, 31 Jul 2024 17:24:04 +0200 Subject: [PATCH] feat(config-commands): add client-side command for modifying your own configs --- .../commands/client/ClientCommandEnv.java | 37 +++++ .../commands/client/ClientConfigCommand.java | 13 ++ .../config/impl/commands/CommandEnv.java | 20 +++ .../config/impl/commands/JfConfigCommand.java | 126 +++++++++--------- .../commands/server/ServerCommandEnv.java | 38 ++++++ .../commands/server/ServerConfigCommand.java | 13 ++ .../src/main/resources/fabric.mod.json | 3 +- 7 files changed, 188 insertions(+), 62 deletions(-) create mode 100644 libjf-config-commands/src/client/java/io/gitlab/jfronny/libjf/config/impl/commands/client/ClientCommandEnv.java create mode 100644 libjf-config-commands/src/client/java/io/gitlab/jfronny/libjf/config/impl/commands/client/ClientConfigCommand.java create mode 100644 libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/CommandEnv.java create mode 100644 libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/server/ServerCommandEnv.java create mode 100644 libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/server/ServerConfigCommand.java diff --git a/libjf-config-commands/src/client/java/io/gitlab/jfronny/libjf/config/impl/commands/client/ClientCommandEnv.java b/libjf-config-commands/src/client/java/io/gitlab/jfronny/libjf/config/impl/commands/client/ClientCommandEnv.java new file mode 100644 index 0000000..38696b9 --- /dev/null +++ b/libjf-config-commands/src/client/java/io/gitlab/jfronny/libjf/config/impl/commands/client/ClientCommandEnv.java @@ -0,0 +1,37 @@ +package io.gitlab.jfronny.libjf.config.impl.commands.client; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import io.gitlab.jfronny.libjf.config.impl.commands.CommandEnv; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; + +public record ClientCommandEnv(CommandDispatcher dispatcher) implements CommandEnv { + @Override + public LiteralArgumentBuilder literal(String name) { + return ClientCommandManager.literal(name); + } + + @Override + public RequiredArgumentBuilder argument(String name, ArgumentType type) { + return ClientCommandManager.argument(name, type); + } + + @Override + public boolean isOperator(FabricClientCommandSource source) { + return true; + } + + @Override + public void sendFeedback(CommandContext context, net.minecraft.text.Text text, boolean broadcast) { + context.getSource().sendFeedback(text); + } + + @Override + public void sendError(CommandContext context, net.minecraft.text.Text text) { + context.getSource().sendError(text); + } +} diff --git a/libjf-config-commands/src/client/java/io/gitlab/jfronny/libjf/config/impl/commands/client/ClientConfigCommand.java b/libjf-config-commands/src/client/java/io/gitlab/jfronny/libjf/config/impl/commands/client/ClientConfigCommand.java new file mode 100644 index 0000000..4e7e9f3 --- /dev/null +++ b/libjf-config-commands/src/client/java/io/gitlab/jfronny/libjf/config/impl/commands/client/ClientConfigCommand.java @@ -0,0 +1,13 @@ +package io.gitlab.jfronny.libjf.config.impl.commands.client; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.config.impl.commands.JfConfigCommand; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; + +public class ClientConfigCommand implements ClientModInitializer { + @Override + public void onInitializeClient() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> JfConfigCommand.register(new ClientCommandEnv(dispatcher), LibJf.MOD_ID + "c")); + } +} diff --git a/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/CommandEnv.java b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/CommandEnv.java new file mode 100644 index 0000000..06ddf4e --- /dev/null +++ b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/CommandEnv.java @@ -0,0 +1,20 @@ +package io.gitlab.jfronny.libjf.config.impl.commands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.command.CommandSource; +import net.minecraft.text.Text; + +public interface CommandEnv { + LiteralArgumentBuilder literal(String name); + RequiredArgumentBuilder argument(String name, ArgumentType type); + + boolean isOperator(S source); + + CommandDispatcher dispatcher(); + void sendFeedback(CommandContext context, Text text, boolean broadcast); + void sendError(CommandContext context, Text text); +} diff --git a/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java index 5675342..f18e7b3 100644 --- a/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java +++ b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/JfConfigCommand.java @@ -7,13 +7,10 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import io.gitlab.jfronny.commons.throwable.ThrowingRunnable; import io.gitlab.jfronny.commons.throwable.ThrowingSupplier; -import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.ConfigCore; -import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; -import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.command.CommandSource; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Language; @@ -21,81 +18,82 @@ import net.minecraft.util.Language; import java.util.function.Consumer; import java.util.function.Function; -import static net.minecraft.server.command.CommandManager.argument; -import static net.minecraft.server.command.CommandManager.literal; - -public class JfConfigCommand implements ModInitializer { +public class JfConfigCommand { private static final String MOD_ID = "libjf-config-commands"; - private MutableText text(String text) { + private static MutableText text(String text) { return Text.literal("[" + MOD_ID + "] " + text); } - @Override - public void onInitialize() { - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { - LiteralArgumentBuilder c_libjf = literal(LibJf.MOD_ID); - LiteralArgumentBuilder c_config = literal("config") - .requires((serverCommandSource) -> serverCommandSource.hasPermissionLevel(4)) - .executes(context -> { - MutableText text = text("Loaded configs for:"); - ConfigHolder.getInstance().getRegistered().forEach((s, config) -> text.append("\n- " + s)); - context.getSource().sendFeedback(() -> text, false); - return Command.SINGLE_SUCCESS; - }); - LiteralArgumentBuilder c_reload = literal("reload").executes(context -> { - ConfigHolder.getInstance().getRegistered().forEach((mod, config) -> config.load()); - context.getSource().sendFeedback(() -> text("Reloaded configs"), true); - return Command.SINGLE_SUCCESS; - }); - LiteralArgumentBuilder c_reset = literal("reset").executes(context -> { - context.getSource().sendError(text("Please specify a config to reset")); - return Command.SINGLE_SUCCESS; - }); - ConfigHolder.getInstance().getRegistered().forEach((id, config) -> { - c_reload.then(literal(id).executes(context -> { - config.load(); - context.getSource().sendFeedback(() -> text("Reloaded config for " + id), true); + public static void register(CommandEnv env, String name) { + LiteralArgumentBuilder c_root = env.literal(name); + LiteralArgumentBuilder c_config = env.literal("config") + .requires(env::isOperator) + .executes(context -> { + MutableText text = text("Loaded configs for:"); + ConfigHolder.getInstance().getRegistered().forEach((s, config) -> text.append("\n- " + s)); + env.sendFeedback(context, text, false); return Command.SINGLE_SUCCESS; - })); - registerEntries(config, id, c_config, c_reset, cns -> { - LiteralArgumentBuilder c_instance = literal(id); - cns.accept(c_instance); - return c_instance; }); - }); - dispatcher.register(c_libjf.then(c_config.then(c_reload).then(c_reset))); + LiteralArgumentBuilder c_reload = env.literal("reload").executes(context -> { + ConfigHolder.getInstance().getRegistered().forEach((mod, config) -> config.load()); + env.sendFeedback(context, text("Reloaded configs"), true); + return Command.SINGLE_SUCCESS; }); + LiteralArgumentBuilder c_reset = env.literal("reset").executes(context -> { + env.sendError(context, text("Please specify a config to reset")); + return Command.SINGLE_SUCCESS; + }); + ConfigHolder.getInstance().getRegistered().forEach((id, config) -> { + c_reload.then(env.literal(id).executes(context -> { + config.load(); + env.sendFeedback(context, text("Reloaded config for " + id), true); + return Command.SINGLE_SUCCESS; + })); + registerEntries(env, config, id, c_config, c_reset, cns -> { + LiteralArgumentBuilder c_instance = env.literal(id); + cns.accept(c_instance); + return c_instance; + }); + }); + env.dispatcher().register(c_root.then(c_config.then(c_reload).then(c_reset))); } - private void registerEntries(ConfigCategory config, String subpath, LiteralArgumentBuilder c_config, LiteralArgumentBuilder c_reset, Function>, LiteralArgumentBuilder> pathGen) { + private static void registerEntries( + CommandEnv env, + ConfigCategory config, + String subpath, + LiteralArgumentBuilder c_config, + LiteralArgumentBuilder c_reset, + Function>, LiteralArgumentBuilder> pathGen + ) { c_config.then(pathGen.apply(cns -> { cns.executes(context -> { - context.getSource().sendFeedback(() -> text(subpath + " is a category"), false); + env.sendFeedback(context, text(subpath + " is a category"), false); return Command.SINGLE_SUCCESS; }); for (EntryInfo entry : config.getEntries()) { - registerEntry(config, subpath, cns, entry); + registerEntry(env, config, subpath, cns, entry); } })); c_reset.then(pathGen.apply(cns -> { cns.executes(context -> { config.reset(); - context.getSource().sendFeedback(() -> text("Reset config for " + subpath), true); + env.sendFeedback(context, text("Reset config for " + subpath), true); return Command.SINGLE_SUCCESS; }); config.getPresets().forEach((id2, preset) -> { - cns.then(literal(id2).executes(context -> { + cns.then(env.literal(id2).executes(context -> { preset.run(); - context.getSource().sendFeedback(() -> text("Loaded preset " + id2 + " for " + subpath), true); + env.sendFeedback(context, text("Loaded preset " + id2 + " for " + subpath), true); return Command.SINGLE_SUCCESS; })); }); })); config.getCategories().forEach((id2, cfg) -> { - registerEntries(cfg, cfg.getCategoryPath(), c_config, c_reset, cns -> { + registerEntries(env, cfg, cfg.getCategoryPath(), c_config, c_reset, cns -> { return pathGen.apply(cns1 -> { - LiteralArgumentBuilder c_instance2 = literal(id2); + LiteralArgumentBuilder c_instance2 = env.literal(id2); cns.accept(c_instance2); cns1.then(c_instance2); }); @@ -103,41 +101,47 @@ public class JfConfigCommand implements ModInitializer { }); } - private final DynamicCommandExceptionType eType = new DynamicCommandExceptionType(o -> { + private static final DynamicCommandExceptionType eType = new DynamicCommandExceptionType(o -> { if (o instanceof Throwable throwable) { return Text.literal("Could not execute command: " + throwable.getMessage()); } else return Text.literal("Could not execute command"); }); - private void registerEntry(ConfigCategory config, String subpath, LiteralArgumentBuilder cns, EntryInfo entry) { + private static void registerEntry( + CommandEnv env, + ConfigCategory config, + String subpath, + LiteralArgumentBuilder cns, + EntryInfo entry + ) { if (!entry.supportsRepresentation()) return; - LiteralArgumentBuilder c_entry = literal(entry.getName()).executes(context -> { + LiteralArgumentBuilder c_entry = env.literal(entry.getName()).executes(context -> { String msg = "The value of " + subpath + "." + entry.getName() + " is "; Text visualized = visualizeOption(config, entry, tryRun(entry::getValue)); - context.getSource().sendFeedback(() -> text(msg).append(visualized), false); + env.sendFeedback(context, text(msg).append(visualized), false); return Command.SINGLE_SUCCESS; }); ArgumentType type = getType(entry); if (type != null) { - c_entry.then(argument("value", type).executes(context -> { + c_entry.then(env.argument("value", type).executes(context -> { @SuppressWarnings("unchecked") T value = context.getArgument("value", (Class) entry.getValueType().asClass()); tryRun(() -> { entry.setValue(value); config.getRoot().write(); }); - context.getSource().sendFeedback(() -> text("Set " + subpath + "." + entry.getName() + " to ") + env.sendFeedback(context, text("Set " + subpath + "." + entry.getName() + " to ") .append(visualizeOption(config, entry, value)), true); return Command.SINGLE_SUCCESS; })); } else if (entry.getValueType().isEnum()) { for (T enumConstant : ((Type.TEnum)entry.getValueType()).options()) { - c_entry.then(literal(enumConstant.toString()).executes(context -> { + c_entry.then(env.literal(enumConstant.toString()).executes(context -> { tryRun(() -> { entry.setValue(enumConstant); config.getRoot().write(); }); - context.getSource().sendFeedback(() -> text("Set " + subpath + "." + entry.getName() + " to " + enumConstant) + env.sendFeedback(context, text("Set " + subpath + "." + entry.getName() + " to " + enumConstant) .append(visualizeOption(config, entry, enumConstant)), true); return Command.SINGLE_SUCCESS; })); @@ -146,7 +150,7 @@ public class JfConfigCommand implements ModInitializer { cns.then(c_entry); } - private Text visualizeOption(ConfigCategory config, EntryInfo entry, T value) { + private static Text visualizeOption(ConfigCategory config, EntryInfo entry, T value) { Language lang = Language.getInstance(); String key = null; Type type = entry.getValueType(); @@ -167,7 +171,7 @@ public class JfConfigCommand implements ModInitializer { else return Text.translatableWithFallback(key, String.valueOf(value)); } - private ArgumentType getType(EntryInfo info) { + private static ArgumentType getType(EntryInfo info) { Type type = info.getValueType(); if (type.isInt()) return IntegerArgumentType.integer((int) info.getMinValue(), (int) info.getMaxValue()); else if (type.isLong()) return LongArgumentType.longArg((long) info.getMinValue(), (long) info.getMaxValue()); @@ -178,11 +182,11 @@ public class JfConfigCommand implements ModInitializer { else return null; } - private T tryRun(ThrowingSupplier supplier) throws CommandSyntaxException { + private static T tryRun(ThrowingSupplier supplier) throws CommandSyntaxException { return supplier.orThrow(eType::create).get(); } - private void tryRun(ThrowingRunnable supplier) throws CommandSyntaxException { + private static void tryRun(ThrowingRunnable supplier) throws CommandSyntaxException { supplier.orThrow(eType::create).run(); } } diff --git a/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/server/ServerCommandEnv.java b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/server/ServerCommandEnv.java new file mode 100644 index 0000000..29fbd56 --- /dev/null +++ b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/server/ServerCommandEnv.java @@ -0,0 +1,38 @@ +package io.gitlab.jfronny.libjf.config.impl.commands.server; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import io.gitlab.jfronny.libjf.config.impl.commands.CommandEnv; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; + +public record ServerCommandEnv(CommandDispatcher dispatcher) implements CommandEnv { + @Override + public LiteralArgumentBuilder literal(String name) { + return CommandManager.literal(name); + } + + @Override + public RequiredArgumentBuilder argument(String name, ArgumentType type) { + return CommandManager.argument(name, type); + } + + @Override + public boolean isOperator(ServerCommandSource source) { + return source.hasPermissionLevel(4); + } + + @Override + public void sendFeedback(CommandContext context, Text text, boolean broadcast) { + context.getSource().sendFeedback(() -> text, broadcast); + } + + @Override + public void sendError(CommandContext context, Text text) { + context.getSource().sendError(text); + } +} diff --git a/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/server/ServerConfigCommand.java b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/server/ServerConfigCommand.java new file mode 100644 index 0000000..4d3f13a --- /dev/null +++ b/libjf-config-commands/src/main/java/io/gitlab/jfronny/libjf/config/impl/commands/server/ServerConfigCommand.java @@ -0,0 +1,13 @@ +package io.gitlab.jfronny.libjf.config.impl.commands.server; + +import io.gitlab.jfronny.libjf.LibJf; +import io.gitlab.jfronny.libjf.config.impl.commands.JfConfigCommand; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; + +public class ServerConfigCommand implements ModInitializer { + @Override + public void onInitialize() { + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> JfConfigCommand.register(new ServerCommandEnv(dispatcher), LibJf.MOD_ID)); + } +} diff --git a/libjf-config-commands/src/main/resources/fabric.mod.json b/libjf-config-commands/src/main/resources/fabric.mod.json index e5a8dff..b6958ba 100644 --- a/libjf-config-commands/src/main/resources/fabric.mod.json +++ b/libjf-config-commands/src/main/resources/fabric.mod.json @@ -13,7 +13,8 @@ "license": "MIT", "environment": "*", "entrypoints": { - "main": ["io.gitlab.jfronny.libjf.config.impl.commands.JfConfigCommand"] + "main": ["io.gitlab.jfronny.libjf.config.impl.commands.server.ServerConfigCommand"], + "client": ["io.gitlab.jfronny.libjf.config.impl.commands.client.ClientConfigCommand"] }, "depends": { "fabricloader": ">=0.12.0",