package io.gitlab.jfronny.libjf.config.impl.commands; import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.*; import com.mojang.brigadier.builder.LiteralArgumentBuilder; 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.v1.*; import io.gitlab.jfronny.libjf.config.api.v1.type.Type; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; 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 { @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 -> { context.getSource().sendFeedback(Text.literal("[libjf-config-v1] Loaded configs for:"), false); ConfigHolder.getInstance().getRegistered().forEach((s, config) -> { context.getSource().sendFeedback(Text.literal("- " + s), false); }); return Command.SINGLE_SUCCESS; }); LiteralArgumentBuilder c_reload = literal("reload").executes(context -> { ConfigHolder.getInstance().getRegistered().forEach((mod, config) -> config.load()); context.getSource().sendFeedback(Text.literal("[libjf-config-v1] Reloaded configs"), true); return Command.SINGLE_SUCCESS; }); LiteralArgumentBuilder c_reset = literal("reset").executes(context -> { context.getSource().sendError(Text.literal("[libjf-config-v1] 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.literal("[libjf-config-v1] Reloaded config for " + id), true); 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))); }); } private void registerEntries(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.literal("[libjf-config-v1] " + subpath + " is a category"), false); return Command.SINGLE_SUCCESS; }); for (EntryInfo entry : config.getEntries()) { registerEntry(config, subpath, cns, entry); } })); c_reset.then(pathGen.apply(cns -> { cns.executes(context -> { config.reset(); context.getSource().sendFeedback(Text.literal("[libjf-config-v1] Reset config for " + subpath), true); return Command.SINGLE_SUCCESS; }); config.getPresets().forEach((id2, preset) -> { cns.then(literal(id2).executes(context -> { preset.run(); context.getSource().sendFeedback(Text.literal("[libjf-config-v1] Loaded preset " + id2 + " for " + subpath), true); return Command.SINGLE_SUCCESS; })); }); })); config.getCategories().forEach((id2, cfg) -> { registerEntries(cfg, cfg.getCategoryPath(), c_config, c_reset, cns -> { return pathGen.apply(cns1 -> { LiteralArgumentBuilder c_instance2 = literal(id2); cns.accept(c_instance2); cns1.then(c_instance2); }); }); }); } private 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) { LiteralArgumentBuilder c_entry = literal(entry.getName()).executes(context -> { context.getSource().sendFeedback(Text.literal("[libjf-config-v1] The value of " + subpath + "." + entry.getName() + " is " + tryRun(entry::getValue)), false); return Command.SINGLE_SUCCESS; }); ArgumentType type = getType(entry); if (type != null) { c_entry.then(argument("value", type).executes(context -> { @SuppressWarnings("unchecked") T value = context.getArgument("value", (Class) entry.getValueType().asClass()); tryRun(() -> entry.setValue(value)); context.getSource().sendFeedback(Text.literal("[libjf-config-v1] Set " + subpath + "." + entry.getName() + " to " + 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 -> { tryRun(() -> entry.setValue(enumConstant)); context.getSource().sendFeedback(Text.literal("[libjf-config-v1] Set " + subpath + "." + entry.getName() + " to " + enumConstant), true); return Command.SINGLE_SUCCESS; })); } } cns.then(c_entry); } private 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()); else if (type.isFloat()) return FloatArgumentType.floatArg((float) info.getMinValue(), (float) info.getMaxValue()); else if (type.isDouble()) return DoubleArgumentType.doubleArg(info.getMinValue(), info.getMaxValue()); else if (type.isString()) return StringArgumentType.greedyString(); else if (type.isBool()) return BoolArgumentType.bool(); else return null; } private T tryRun(ThrowingSupplier supplier) throws CommandSyntaxException { return supplier.orThrow(eType::create).get(); } private void tryRun(ThrowingRunnable supplier) throws CommandSyntaxException { supplier.orThrow(eType::create).run(); } }