feat(config-commands): add client-side command for modifying your own configs
This commit is contained in:
parent
e5e8522f8b
commit
2c52a5a63b
@ -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<FabricClientCommandSource> dispatcher) implements CommandEnv<FabricClientCommandSource> {
|
||||
@Override
|
||||
public LiteralArgumentBuilder<FabricClientCommandSource> literal(String name) {
|
||||
return ClientCommandManager.literal(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> RequiredArgumentBuilder<FabricClientCommandSource, T> argument(String name, ArgumentType<T> type) {
|
||||
return ClientCommandManager.argument(name, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOperator(FabricClientCommandSource source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFeedback(CommandContext<FabricClientCommandSource> context, net.minecraft.text.Text text, boolean broadcast) {
|
||||
context.getSource().sendFeedback(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(CommandContext<FabricClientCommandSource> context, net.minecraft.text.Text text) {
|
||||
context.getSource().sendError(text);
|
||||
}
|
||||
}
|
@ -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"));
|
||||
}
|
||||
}
|
@ -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<S extends CommandSource> {
|
||||
LiteralArgumentBuilder<S> literal(String name);
|
||||
<T> RequiredArgumentBuilder<S, T> argument(String name, ArgumentType<T> type);
|
||||
|
||||
boolean isOperator(S source);
|
||||
|
||||
CommandDispatcher<S> dispatcher();
|
||||
void sendFeedback(CommandContext<S> context, Text text, boolean broadcast);
|
||||
void sendError(CommandContext<S> context, Text text);
|
||||
}
|
@ -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<ServerCommandSource> c_libjf = literal(LibJf.MOD_ID);
|
||||
LiteralArgumentBuilder<ServerCommandSource> c_config = literal("config")
|
||||
.requires((serverCommandSource) -> serverCommandSource.hasPermissionLevel(4))
|
||||
public static <S extends CommandSource> void register(CommandEnv<S> env, String name) {
|
||||
LiteralArgumentBuilder<S> c_root = env.literal(name);
|
||||
LiteralArgumentBuilder<S> 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));
|
||||
context.getSource().sendFeedback(() -> text, false);
|
||||
env.sendFeedback(context, text, false);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
});
|
||||
LiteralArgumentBuilder<ServerCommandSource> c_reload = literal("reload").executes(context -> {
|
||||
LiteralArgumentBuilder<S> c_reload = env.literal("reload").executes(context -> {
|
||||
ConfigHolder.getInstance().getRegistered().forEach((mod, config) -> config.load());
|
||||
context.getSource().sendFeedback(() -> text("Reloaded configs"), true);
|
||||
env.sendFeedback(context, text("Reloaded configs"), true);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
});
|
||||
LiteralArgumentBuilder<ServerCommandSource> c_reset = literal("reset").executes(context -> {
|
||||
context.getSource().sendError(text("Please specify a config to reset"));
|
||||
LiteralArgumentBuilder<S> 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(literal(id).executes(context -> {
|
||||
c_reload.then(env.literal(id).executes(context -> {
|
||||
config.load();
|
||||
context.getSource().sendFeedback(() -> text("Reloaded config for " + id), true);
|
||||
env.sendFeedback(context, text("Reloaded config for " + id), true);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}));
|
||||
registerEntries(config, id, c_config, c_reset, cns -> {
|
||||
LiteralArgumentBuilder<ServerCommandSource> c_instance = literal(id);
|
||||
registerEntries(env, config, id, c_config, c_reset, cns -> {
|
||||
LiteralArgumentBuilder<S> c_instance = env.literal(id);
|
||||
cns.accept(c_instance);
|
||||
return c_instance;
|
||||
});
|
||||
});
|
||||
dispatcher.register(c_libjf.then(c_config.then(c_reload).then(c_reset)));
|
||||
});
|
||||
env.dispatcher().register(c_root.then(c_config.then(c_reload).then(c_reset)));
|
||||
}
|
||||
|
||||
private void registerEntries(ConfigCategory config, String subpath, LiteralArgumentBuilder<ServerCommandSource> c_config, LiteralArgumentBuilder<ServerCommandSource> c_reset, Function<Consumer<LiteralArgumentBuilder<ServerCommandSource>>, LiteralArgumentBuilder<ServerCommandSource>> pathGen) {
|
||||
private static <S extends CommandSource> void registerEntries(
|
||||
CommandEnv<S> env,
|
||||
ConfigCategory config,
|
||||
String subpath,
|
||||
LiteralArgumentBuilder<S> c_config,
|
||||
LiteralArgumentBuilder<S> c_reset,
|
||||
Function<Consumer<LiteralArgumentBuilder<S>>, LiteralArgumentBuilder<S>> 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<ServerCommandSource> c_instance2 = literal(id2);
|
||||
LiteralArgumentBuilder<S> 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 <T> void registerEntry(ConfigCategory config, String subpath, LiteralArgumentBuilder<ServerCommandSource> cns, EntryInfo<T> entry) {
|
||||
private static <T, S extends CommandSource> void registerEntry(
|
||||
CommandEnv<S> env,
|
||||
ConfigCategory config,
|
||||
String subpath,
|
||||
LiteralArgumentBuilder<S> cns,
|
||||
EntryInfo<T> entry
|
||||
) {
|
||||
if (!entry.supportsRepresentation()) return;
|
||||
LiteralArgumentBuilder<ServerCommandSource> c_entry = literal(entry.getName()).executes(context -> {
|
||||
LiteralArgumentBuilder<S> 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<T>) 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<T>)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 <T> Text visualizeOption(ConfigCategory config, EntryInfo<T> entry, T value) {
|
||||
private static <T> Text visualizeOption(ConfigCategory config, EntryInfo<T> 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 <T> ArgumentType<?> getType(EntryInfo<T> info) {
|
||||
private static <T> ArgumentType<?> getType(EntryInfo<T> 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> T tryRun(ThrowingSupplier<T, ?> supplier) throws CommandSyntaxException {
|
||||
private static <T> T tryRun(ThrowingSupplier<T, ?> 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();
|
||||
}
|
||||
}
|
||||
|
@ -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<ServerCommandSource> dispatcher) implements CommandEnv<ServerCommandSource> {
|
||||
@Override
|
||||
public LiteralArgumentBuilder<ServerCommandSource> literal(String name) {
|
||||
return CommandManager.literal(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> RequiredArgumentBuilder<ServerCommandSource, T> argument(String name, ArgumentType<T> type) {
|
||||
return CommandManager.argument(name, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOperator(ServerCommandSource source) {
|
||||
return source.hasPermissionLevel(4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFeedback(CommandContext<ServerCommandSource> context, Text text, boolean broadcast) {
|
||||
context.getSource().sendFeedback(() -> text, broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(CommandContext<ServerCommandSource> context, Text text) {
|
||||
context.getSource().sendError(text);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user