package eu.midnightdust.lib.config; import com.mojang.brigadier.arguments.*; import com.mojang.brigadier.context.CommandContext; import eu.midnightdust.lib.util.PlatformFunctions; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; import java.lang.reflect.Field; import java.util.List; import java.util.Objects; import static eu.midnightdust.lib.config.MidnightConfig.Entry; public class AutoCommand { final static String VALUE = "value"; final Field field; final Class type; final String modid; final boolean isList; public AutoCommand(Field field, String modid) { this.field = field; this.modid = modid; this.type = MidnightConfig.getUnderlyingType(field); this.isList = field.getType() == List.class; var command = CommandManager.literal(field.getName()).executes(this::getValue); if (type.isEnum()) { for (Object enumValue : field.getType().getEnumConstants()) command = command.then(CommandManager.literal(enumValue.toString()) .executes(ctx -> this.setValue(ctx.getSource(), enumValue, ""))); } else if (isList) { for (String action : new String[]{"add", "remove"}) command = command.then(CommandManager.literal(action) .then(CommandManager.argument(VALUE, getArgType()).executes(ctx -> setValueFromArg(ctx, action)))); } else command = command.then(CommandManager.argument(VALUE, getArgType()).executes(ctx -> setValueFromArg(ctx, ""))); PlatformFunctions.registerCommand(CommandManager.literal("midnightconfig").requires(source -> source.hasPermissionLevel(2)).then(CommandManager.literal(modid).then(command))); } public ArgumentType getArgType() { Entry entry = field.getAnnotation(Entry.class); if (type == int.class) return IntegerArgumentType.integer((int) entry.min(), (int) entry.max()); else if (type == double.class) return DoubleArgumentType.doubleArg(entry.min(), entry.max()); else if (type == float.class) return FloatArgumentType.floatArg((float) entry.min(), (float) entry.max()); else if (type == boolean.class) return BoolArgumentType.bool(); return StringArgumentType.string(); } public int setValueFromArg(CommandContext context, String action) { if (type == int.class) return setValue(context.getSource(), IntegerArgumentType.getInteger(context, VALUE), action); else if (type == double.class) return setValue(context.getSource(), DoubleArgumentType.getDouble(context, VALUE), action); else if (type == float.class) return setValue(context.getSource(), FloatArgumentType.getFloat(context, VALUE), action); else if (type == boolean.class) return setValue(context.getSource(), BoolArgumentType.getBool(context, VALUE), action); return setValue(context.getSource(), StringArgumentType.getString(context, VALUE), action); } private int setValue(ServerCommandSource source, Object value, String action) { boolean add = Objects.equals(action, "add"); try { if (!isList) field.set(null, value); else { @SuppressWarnings("unchecked") var list = (List) field.get(null); if (add) list.add(value); else if (!list.contains(value)) throw new IllegalArgumentException("List does not contain this string!"); else list.remove(value); } MidnightConfig.write(modid); } catch (Exception e) { source.sendError(Text.literal(isList ? "Could not %s %s %s %s: %s".formatted(add ? "add" : "remove", value, add ? "to" : "from", field.getName(), e) : "Could not set %s to value %s: %s".formatted(field.getName(), value, e))); return 0; } source.sendFeedback(() -> Text.literal(isList ? "Successfully %s %s %s %s".formatted(add ? "added" : "removed", value, add ? "to" : "from", field.getName()) : "Successfully set %s to %s".formatted(field.getName(), value)), true); return 1; } private int getValue(CommandContext context) { context.getSource().sendFeedback(() -> { try { return Text.literal("The value of %s is %s".formatted(field.getName(), field.get(null))); } catch (IllegalAccessException e) {throw new RuntimeException(e);} }, true); return 0; } }