From c96ce10cdcf75cf642101b00cc9572304d276851 Mon Sep 17 00:00:00 2001 From: Keuin Date: Sat, 16 Jan 2021 15:34:15 +0800 Subject: Add runtime configuration editing command `/omvm set `. The set is temporary and will not be modified in disk. --- .../keuin/ohmyvanillamc/OhMyVanillaMinecraft.java | 219 ++++++++++++++------- 1 file changed, 151 insertions(+), 68 deletions(-) (limited to 'src/main/java/com/keuin/ohmyvanillamc/OhMyVanillaMinecraft.java') diff --git a/src/main/java/com/keuin/ohmyvanillamc/OhMyVanillaMinecraft.java b/src/main/java/com/keuin/ohmyvanillamc/OhMyVanillaMinecraft.java index 76936fa..e64708d 100644 --- a/src/main/java/com/keuin/ohmyvanillamc/OhMyVanillaMinecraft.java +++ b/src/main/java/com/keuin/ohmyvanillamc/OhMyVanillaMinecraft.java @@ -3,88 +3,171 @@ package com.keuin.ohmyvanillamc; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonIOException; +import com.keuin.ohmyvanillamc.config.ImmutableOmvmConfiguration; +import com.keuin.ohmyvanillamc.config.OmvmConfiguration; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.util.Formatting; import java.io.*; import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.logging.Logger; +import java.util.stream.Stream; + +import static com.keuin.ohmyvanillamc.ReflectionUtils.getFieldName; +import static com.keuin.ohmyvanillamc.ReflectionUtils.setPrivateField; public class OhMyVanillaMinecraft implements ModInitializer { - private static final Logger LOGGER = Logger.getLogger("OhMyVanillaMinecraft"); - - private static OmvmConfiguration configuration = null; - private static final OmvmConfiguration defaultConfiguration = new OmvmConfiguration(); - - public static OmvmConfiguration getConfiguration() { - return configuration != null ? configuration : defaultConfiguration; - } - - @Override - public void onInitialize() { - // This code runs as soon as Minecraft is in a mod-load-ready state. - // However, some things (like resources) may still be uninitialized. - // Proceed with mild caution. - - LOGGER.info("Loading configuration..."); - - // load configuration - - final String fileName = "omvm.json"; - final File file = new File(fileName); - if (!file.exists()) { - LOGGER.info("Configuration file does not exist! Use default configuration."); - try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { - final String jsonString = (new GsonBuilder().setPrettyPrinting().create()).toJson(defaultConfiguration); - try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream)) { - outputStreamWriter.write(jsonString); - } - } catch (FileNotFoundException e) { - LOGGER.severe("Cannot write default configuration to file `" + fileName + "`: " + e); - } catch (IOException e) { - LOGGER.severe("Failed to write default configuration to file `" + fileName + "`: " + e); - } - } else { - try (FileInputStream fileInputStream = new FileInputStream(file)) { - try (InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8)) { - try (BufferedReader reader = new BufferedReader(inputStreamReader)) { - configuration = (new Gson()).fromJson(reader, OmvmConfiguration.class); - } - } - } catch (IOException e) { - LOGGER.severe("Failed to read config file `" + fileName + "`: " + e); - } catch (JsonIOException e) { - LOGGER.severe("Failed to decode config json file `" + fileName + "`: " + e); - } - } - - if (configuration == null) { - configuration = defaultConfiguration; - } - - LOGGER.info("Configuration: \n==========\n" + configuration + "\n=========="); - - CommandRegistrationCallback.EVENT.register(new CommandRegistrationCallback() { - @Override - public void register(CommandDispatcher commandDispatcher, boolean b) { - commandDispatcher.register(CommandManager.literal("omvm").executes(new Command() { - @Override - public int run(CommandContext context) throws CommandSyntaxException { - String text = "OhMyVanillaMinecraft\n==========\n" + getConfiguration() + "\n=========="; - context.getSource().sendFeedback(new LiteralText(text), false); - return 1; // 1: success, -1: fail - } - })); - } - }); - - } + private static final Logger LOGGER = Logger.getLogger("OhMyVanillaMinecraft"); + + private static final OmvmConfiguration defaultConfiguration = + new ImmutableOmvmConfiguration(true, true, true, true, true, true); + private static OmvmConfiguration configuration = null; + + public static OmvmConfiguration getConfiguration() { + return configuration; + } + + @Override + public void onInitialize() { + // This code runs as soon as Minecraft is in a mod-load-ready state. + // However, some things (like resources) may still be uninitialized. + // Proceed with mild caution. + + LOGGER.info("Loading configuration..."); + + // load configuration + + final String fileName = "omvm.json"; + final File file = new File(fileName); + if (!file.exists()) { + LOGGER.info("Configuration file does not exist! Use default configuration."); + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + final String jsonString = (new GsonBuilder().setPrettyPrinting().create()).toJson(defaultConfiguration); + try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream)) { + outputStreamWriter.write(jsonString); + } + } catch (FileNotFoundException e) { + LOGGER.severe("Cannot write default configuration to file `" + fileName + "`: " + e); + } catch (IOException e) { + LOGGER.severe("Failed to write default configuration to file `" + fileName + "`: " + e); + } + } else { + try (FileInputStream fileInputStream = new FileInputStream(file)) { + try (InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8)) { + try (BufferedReader reader = new BufferedReader(inputStreamReader)) { + configuration = (new Gson()).fromJson(reader, OmvmConfiguration.class); + } + } + } catch (IOException e) { + LOGGER.severe("Failed to read config file `" + fileName + "`: " + e); + } catch (JsonIOException e) { + LOGGER.severe("Failed to decode config json file `" + fileName + "`: " + e); + } + } + + if (configuration == null) { + configuration = new OmvmConfiguration(defaultConfiguration); + } + + LOGGER.info("Configuration: \n==========\n" + configuration + "\n=========="); + + CommandRegistrationCallback.EVENT.register(new CommandRegistrationCallback() { + @Override + public void register(CommandDispatcher commandDispatcher, boolean b) { + commandDispatcher.register(CommandManager.literal("omvm").executes(new Command() { + @Override + public int run(CommandContext context) throws CommandSyntaxException { + String text = "OhMyVanillaMinecraft\n==========\n" + getConfiguration() + "\n=========="; + context.getSource().sendFeedback(new LiteralText(text), false); + return 1; // 1: success, -1: fail + } + })); + } + }); + + + String[] keys = getFieldName(configuration); + final Set keySet = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(keys))); + + CommandRegistrationCallback.EVENT.register(new CommandRegistrationCallback() { + @Override + public void register(CommandDispatcher commandDispatcher, boolean b) { + commandDispatcher.register(CommandManager.literal("omvm") + .then(CommandManager.literal("set") + .then(CommandManager.argument("key", StringArgumentType.word()) + .suggests(new SuggestionProvider() { + @Override + public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException { + String remaining = builder.getRemaining().toLowerCase(Locale.ROOT); + keySet.stream().filter(key -> key.toLowerCase().startsWith(remaining)).forEach(builder::suggest); + return builder.buildFuture(); + } + }) + .then(CommandManager.argument("value", StringArgumentType.word()).suggests(new SuggestionProvider() { + @Override + public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException { + String remaining = builder.getRemaining().toLowerCase(Locale.ROOT); + Stream.of("true", "false").filter(key -> key.toLowerCase().startsWith(remaining)).forEach(builder::suggest); + return builder.buildFuture(); + } + }) + .executes(new Command() { + @Override + public int run(CommandContext context) throws CommandSyntaxException { + try { + String key = context.getArgument("key", String.class); + String value = context.getArgument("value", String.class); + + if (!keySet.contains(key)) { + StringBuilder sb = new StringBuilder(); + sb.append("Invalid key. Available keys:"); + keySet.forEach(k -> sb.append("\n- ").append(k)); + context.getSource().sendFeedback(new LiteralText(sb.toString()) + .setStyle(Style.EMPTY.withColor(Formatting.RED)), false); + return -1; + } + + if (!Arrays.asList("true", "false").contains(value)) { + context.getSource().sendFeedback(new LiteralText("Value must be `true` or `false`.") + .setStyle(Style.EMPTY.withColor(Formatting.RED)), false); + return -1; + } + + setPrivateField(configuration, key, Boolean.valueOf(value)); + context.getSource().sendFeedback( + new LiteralText("`" + key + "` has been temporarily set to `" + value + "`."), true + ); + + return 1; // 1: success, -1: fail + } catch (NoSuchFieldException | IllegalAccessException e) { + context.getSource().sendFeedback(new LiteralText("There is a bug. Tell trueKeuin.") + .setStyle(Style.EMPTY.withColor(Formatting.RED)), false); + return -1; + } + } + }) + ) + ))); + } + }); + + } + + } -- cgit v1.2.3