From 2504a67a397a60996fe3116a54ed7613f0ef8c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 3 Jun 2021 13:29:09 +0200 Subject: [PATCH] Separate config declaration from Forge config logic a bit. --- src/main/java/li/cil/oc2/common/Config.java | 188 ++------------- .../java/li/cil/oc2/common/ConfigManager.java | 226 ++++++++++++++++++ src/main/java/li/cil/oc2/common/Main.java | 3 +- 3 files changed, 251 insertions(+), 166 deletions(-) create mode 100644 src/main/java/li/cil/oc2/common/ConfigManager.java diff --git a/src/main/java/li/cil/oc2/common/Config.java b/src/main/java/li/cil/oc2/common/Config.java index 78ec7c85..84bcde3b 100644 --- a/src/main/java/li/cil/oc2/common/Config.java +++ b/src/main/java/li/cil/oc2/common/Config.java @@ -1,65 +1,40 @@ package li.cil.oc2.common; -import li.cil.oc2.api.API; +import li.cil.oc2.common.ConfigManager.Path; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ToolType; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.config.ModConfig; -import org.apache.commons.lang3.tuple.Pair; import java.util.UUID; -@Mod.EventBusSubscriber(modid = API.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public final class Config { - private static final CommonSettings COMMON_INSTANCE; - private static final ForgeConfigSpec COMMON_SPEC; + @Path("vm") public static long maxAllocatedMemory = 512 * Constants.MEGABYTE; + @Path("vm") public static int maxMemorySize = 8 * Constants.MEGABYTE; + @Path("vm") public static int maxHardDriveSize = 8 * Constants.MEGABYTE; + @Path("vm") public static int maxFlashMemorySize = 4 * Constants.KILOBYTE; + @Path("vm") public static int maxFloppySize = 512 * Constants.KILOBYTE; - /////////////////////////////////////////////////////////////////// + @Path("energy.blocks") public static double busCableEnergyPerTick = 0.1; + @Path("energy.blocks") public static double busInterfaceEnergyPerTick = 0.5; + @Path("energy.blocks") public static int computerEnergyPerTick = 10; + @Path("energy.blocks") public static int computerEnergyStorage = 2000; + @Path("energy.blocks") public static int chargerEnergyPerTick = 2500; + @Path("energy.blocks") public static int chargerEnergyStorage = 10000; - public static long maxAllocatedMemory = 512 * Constants.MEGABYTE; - public static int maxMemorySize = 8 * Constants.MEGABYTE; - public static int maxHardDriveSize = 8 * Constants.MEGABYTE; - public static int maxFlashMemorySize = 4 * Constants.KILOBYTE; - public static int maxFloppySize = 512 * Constants.KILOBYTE; + @Path("energy.entities") public static int robotEnergyPerTick = 5; + @Path("energy.entities") public static int robotEnergyStorage = 750000; - public static double busCableEnergyPerTick = 0.1; - public static double busInterfaceEnergyPerTick = 0.5; - public static int computerEnergyPerTick = 10; - public static int computerEnergyStorage = 2000; - public static int robotEnergyPerTick = 5; - public static int robotEnergyStorage = 750000; - public static int chargerEnergyPerTick = 2500; - public static int chargerEnergyStorage = 10000; + @Path("energy.items") public static double memoryEnergyPerMegabytePerTick = 0.5; + @Path("energy.items") public static double hardDriveEnergyPerMegabytePerTick = 1; + @Path("energy.items") public static int redstoneInterfaceCardEnergyPerTick = 1; + @Path("energy.items") public static int networkInterfaceEnergyPerTick = 1; + @Path("energy.items") public static int fileImportExportCardEnergyPerTick = 1; + @Path("energy.items") public static int blockOperationsModuleEnergyPerTick = 2; + @Path("energy.items") public static int inventoryOperationsModuleEnergyPerTick = 1; - public static double memoryEnergyPerMegabytePerTick = 0.5; - public static double hardDriveEnergyPerMegabytePerTick = 1; - public static int redstoneInterfaceCardEnergyPerTick = 1; - public static int networkInterfaceEnergyPerTick = 1; - public static int fileImportExportCardEnergyPerTick = 1; - public static int blockOperationsModuleEnergyPerTick = 2; - public static int inventoryOperationsModuleEnergyPerTick = 1; + @Path("gameplay") public static int blockOperationsModuleToolLevel = Items.DIAMOND_PICKAXE.getHarvestLevel(new ItemStack(Items.DIAMOND_PICKAXE), ToolType.PICKAXE, null, null); - public static int blockOperationsModuleToolLevel = Items.DIAMOND_PICKAXE.getHarvestLevel(new ItemStack(Items.DIAMOND_PICKAXE), ToolType.PICKAXE, null, null); - - public static UUID fakePlayerUUID = UUID.fromString("e39dd9a7-514f-4a2d-aa5e-b6030621416d"); - - /////////////////////////////////////////////////////////////////// - - static { - final Pair commonConfig = new ForgeConfigSpec.Builder().configure(CommonSettings::new); - COMMON_INSTANCE = commonConfig.getKey(); - COMMON_SPEC = commonConfig.getValue(); - } - - /////////////////////////////////////////////////////////////////// - - public static void initialize() { - ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, COMMON_SPEC); - } + @Path("admin") public static UUID fakePlayerUUID = UUID.fromString("e39dd9a7-514f-4a2d-aa5e-b6030621416d"); public static boolean computersUseEnergy() { return computerEnergyPerTick > 0 && computerEnergyStorage > 0; @@ -72,121 +47,4 @@ public final class Config { public static boolean chargerUseEnergy() { return chargerEnergyPerTick > 0 && chargerEnergyStorage > 0; } - - /////////////////////////////////////////////////////////////////// - - @SubscribeEvent - public static void handleModConfigEvent(final ModConfig.ModConfigEvent event) { - if (event.getConfig().getSpec() == COMMON_SPEC) { - maxAllocatedMemory = COMMON_INSTANCE.maxAllocatedMemory.get(); - maxMemorySize = COMMON_INSTANCE.maxMemorySize.get(); - maxHardDriveSize = COMMON_INSTANCE.maxHardDriveSize.get(); - maxFlashMemorySize = COMMON_INSTANCE.maxFlashMemorySize.get(); - - busCableEnergyPerTick = COMMON_INSTANCE.busCableEnergyPerTick.get(); - busInterfaceEnergyPerTick = COMMON_INSTANCE.busInterfaceEnergyPerTick.get(); - - computerEnergyPerTick = COMMON_INSTANCE.computerEnergyPerTick.get(); - computerEnergyStorage = COMMON_INSTANCE.computerEnergyStorage.get(); - robotEnergyPerTick = COMMON_INSTANCE.robotEnergyPerTick.get(); - robotEnergyStorage = COMMON_INSTANCE.robotEnergyStorage.get(); - chargerEnergyPerTick = COMMON_INSTANCE.chargerEnergyPerTick.get(); - chargerEnergyStorage = COMMON_INSTANCE.chargerEnergyStorage.get(); - - memoryEnergyPerMegabytePerTick = COMMON_INSTANCE.memoryEnergyPerMegabytePerTick.get(); - hardDriveEnergyPerMegabytePerTick = COMMON_INSTANCE.hardDriveEnergyPerMegabytePerTick.get(); - redstoneInterfaceCardEnergyPerTick = COMMON_INSTANCE.redstoneInterfaceCardEnergyPerTick.get(); - networkInterfaceEnergyPerTick = COMMON_INSTANCE.networkInterfaceEnergyPerTick.get(); - fileImportExportCardEnergyPerTick = COMMON_INSTANCE.fileImportExportCardEnergyPerTick.get(); - blockOperationsModuleEnergyPerTick = COMMON_INSTANCE.blockOperationsModuleEnergyPerTick.get(); - inventoryOperationsModuleEnergyPerTick = COMMON_INSTANCE.inventoryOperationsModuleEnergyPerTick.get(); - - - blockOperationsModuleToolLevel = COMMON_INSTANCE.blockOperationsModuleToolLevel.get(); - - fakePlayerUUID = UUID.fromString(COMMON_INSTANCE.fakePlayerUUID.get()); - } - } - - /////////////////////////////////////////////////////////////////// - - private static final class CommonSettings { - public final ForgeConfigSpec.LongValue maxAllocatedMemory; - public final ForgeConfigSpec.IntValue maxMemorySize; - public final ForgeConfigSpec.IntValue maxHardDriveSize; - public final ForgeConfigSpec.IntValue maxFlashMemorySize; - - public final ForgeConfigSpec.DoubleValue busCableEnergyPerTick; - public final ForgeConfigSpec.DoubleValue busInterfaceEnergyPerTick; - public final ForgeConfigSpec.IntValue computerEnergyPerTick; - public final ForgeConfigSpec.IntValue computerEnergyStorage; - public final ForgeConfigSpec.IntValue robotEnergyPerTick; - public final ForgeConfigSpec.IntValue robotEnergyStorage; - public final ForgeConfigSpec.IntValue chargerEnergyPerTick; - public final ForgeConfigSpec.IntValue chargerEnergyStorage; - - public final ForgeConfigSpec.DoubleValue memoryEnergyPerMegabytePerTick; - public final ForgeConfigSpec.DoubleValue hardDriveEnergyPerMegabytePerTick; - public final ForgeConfigSpec.IntValue redstoneInterfaceCardEnergyPerTick; - public final ForgeConfigSpec.IntValue networkInterfaceEnergyPerTick; - public final ForgeConfigSpec.IntValue fileImportExportCardEnergyPerTick; - public final ForgeConfigSpec.IntValue blockOperationsModuleEnergyPerTick; - public final ForgeConfigSpec.IntValue inventoryOperationsModuleEnergyPerTick; - - public final ForgeConfigSpec.IntValue blockOperationsModuleToolLevel; - - public final ForgeConfigSpec.ConfigValue fakePlayerUUID; - - public CommonSettings(final ForgeConfigSpec.Builder builder) { - builder.push("vm"); - { - maxAllocatedMemory = builder.defineInRange("maxAllocatedMemory", Config.maxAllocatedMemory, 0L, 64L * Constants.GIGABYTE); - maxMemorySize = builder.defineInRange("maxMemorySize", Config.maxMemorySize, 0, 256 * Constants.MEGABYTE); - maxHardDriveSize = builder.defineInRange("maxHardDriveSize", Config.maxHardDriveSize, 0, 512 * Constants.MEGABYTE); - maxFlashMemorySize = builder.defineInRange("maxFlashMemorySize", Config.maxFlashMemorySize, 0, 128 * Constants.MEGABYTE); - } - builder.pop(); - - builder.push("energy"); - { - builder.push("blocks"); - { - busCableEnergyPerTick = builder.defineInRange("busCableEnergyPerTick", Config.busCableEnergyPerTick, 0, Integer.MAX_VALUE); - busInterfaceEnergyPerTick = builder.defineInRange("busInterfaceEnergyPerTick", Config.busInterfaceEnergyPerTick, 0, Integer.MAX_VALUE); - computerEnergyPerTick = builder.defineInRange("computerEnergyPerTick", Config.computerEnergyPerTick, 0, Integer.MAX_VALUE); - computerEnergyStorage = builder.defineInRange("computerEnergyStorage", Config.computerEnergyStorage, 0, Integer.MAX_VALUE); - robotEnergyPerTick = builder.defineInRange("robotEnergyPerTick", Config.robotEnergyPerTick, 0, Integer.MAX_VALUE); - robotEnergyStorage = builder.defineInRange("robotEnergyStorage", Config.robotEnergyStorage, 0, Integer.MAX_VALUE); - chargerEnergyPerTick = builder.defineInRange("chargerEnergyPerTick", Config.chargerEnergyPerTick, 0, Integer.MAX_VALUE); - chargerEnergyStorage = builder.defineInRange("chargerEnergyStorage", Config.chargerEnergyStorage, 0, Integer.MAX_VALUE); - } - builder.pop(); - - builder.push("items"); - { - memoryEnergyPerMegabytePerTick = builder.defineInRange("memoryEnergyPerMegabytePerTick", Config.memoryEnergyPerMegabytePerTick, 0, Integer.MAX_VALUE); - hardDriveEnergyPerMegabytePerTick = builder.defineInRange("hardDriveEnergyPerMegabytePerTick", Config.hardDriveEnergyPerMegabytePerTick, 0, Integer.MAX_VALUE); - redstoneInterfaceCardEnergyPerTick = builder.defineInRange("redstoneInterfaceCardEnergyPerTick", Config.redstoneInterfaceCardEnergyPerTick, 0, Integer.MAX_VALUE); - networkInterfaceEnergyPerTick = builder.defineInRange("networkInterfaceEnergyPerTick", Config.networkInterfaceEnergyPerTick, 0, Integer.MAX_VALUE); - fileImportExportCardEnergyPerTick = builder.defineInRange("fileImportExportCardEnergyPerTick", Config.fileImportExportCardEnergyPerTick, 0, Integer.MAX_VALUE); - blockOperationsModuleEnergyPerTick = builder.defineInRange("blockOperationsModuleEnergyPerTick", Config.blockOperationsModuleEnergyPerTick, 0, Integer.MAX_VALUE); - inventoryOperationsModuleEnergyPerTick = builder.defineInRange("inventoryOperationsModuleEnergyPerTick", Config.inventoryOperationsModuleEnergyPerTick, 0, Integer.MAX_VALUE); - } - builder.pop(); - } - builder.pop(); - - builder.push("gameplay"); - { - blockOperationsModuleToolLevel = builder.defineInRange("modules.blockOperations.toolLevel", Config.blockOperationsModuleToolLevel, 0, Integer.MAX_VALUE); - } - builder.pop(); - - builder.push("admin"); - { - fakePlayerUUID = builder.define("fakePlayerUUID", Config.fakePlayerUUID.toString()); - } - builder.pop(); - } - } } diff --git a/src/main/java/li/cil/oc2/common/ConfigManager.java b/src/main/java/li/cil/oc2/common/ConfigManager.java new file mode 100644 index 00000000..2ed81b15 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/ConfigManager.java @@ -0,0 +1,226 @@ +package li.cil.oc2.common; + +import li.cil.oc2.api.API; +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.config.ModConfig; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; +import java.util.function.Supplier; + +@Mod.EventBusSubscriber(modid = API.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +public final class ConfigManager { + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface Type { + ModConfig.Type value() default ModConfig.Type.COMMON; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Path { + String value() default ""; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Min { + double value() default 0; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Max { + double value() default Double.POSITIVE_INFINITY; + } + + /////////////////////////////////////////////////////////////////// + + private static final Logger LOGGER = LogManager.getLogger(); + + /////////////////////////////////////////////////////////////////// + + private static final Map, ConfigFieldParser> PARSERS = new HashMap<>(); + private static final Map CONFIGS = new HashMap<>(); + + static { + PARSERS.put(int.class, ConfigManager::parseIntField); + PARSERS.put(long.class, ConfigManager::parseLongField); + PARSERS.put(double.class, ConfigManager::parseDoubleField); + PARSERS.put(String.class, ConfigManager::parseStringField); + PARSERS.put(UUID.class, ConfigManager::parseUUIDField); + } + + /////////////////////////////////////////////////////////////////// + + public static void add(final Supplier factory) { + final ArrayList> values = new ArrayList<>(); + final Pair config = new ForgeConfigSpec.Builder().configure(builder -> { + final T instance = factory.get(); + fillSpec(instance, builder, values); + return instance; + }); + CONFIGS.put(config.getValue(), new ConfigDefinition(config.getKey(), values)); + } + + public static void initialize() { + CONFIGS.forEach((spec, config) -> { + final Type typeAnnotation = config.instance.getClass().getAnnotation(Type.class); + final ModConfig.Type configType = typeAnnotation != null ? typeAnnotation.value() : ModConfig.Type.COMMON; + ModLoadingContext.get().registerConfig(configType, spec); + }); + } + + /////////////////////////////////////////////////////////////////// + + @SubscribeEvent + public static void handleModConfigEvent(final ModConfig.ModConfigEvent event) { + final ConfigDefinition config = CONFIGS.get(event.getConfig().getSpec()); + if (config != null) { + config.apply(); + } + } + + /////////////////////////////////////////////////////////////////// + + private static void fillSpec(final T instance, final ForgeConfigSpec.Builder builder, final ArrayList> values) { + for (final Field field : instance.getClass().getFields()) { + parseField(instance, builder, values, field); + } + } + + private static void parseField(final T instance, final ForgeConfigSpec.Builder builder, final ArrayList> values, final Field field) { + final ConfigFieldParser parser = PARSERS.get(field.getType()); + if (parser != null) { + final Path pathAnnotation = field.getAnnotation(Path.class); + final String path = getPath(pathAnnotation.value(), field); + + try { + values.add(parser.apply(instance, field, path, builder)); + } catch (final IllegalAccessException e) { + LOGGER.error("Failed accessing field [{}.{}], ignoring.", field.getDeclaringClass().getName(), field.getName()); + } + } + } + + private static ConfigFieldPair parseIntField(final Object instance, final Field field, final String path, final ForgeConfigSpec.Builder builder) throws IllegalAccessException { + final int defaultValue = field.getInt(instance); + final int minValue = (int) Math.max(getMin(field), Integer.MIN_VALUE); + final int maxValue = (int) Math.min(getMax(field), Integer.MAX_VALUE); + + final ForgeConfigSpec.IntValue configValue = builder.defineInRange(path, defaultValue, minValue, maxValue); + + return new ConfigFieldPair<>(field, configValue); + } + + private static ConfigFieldPair parseLongField(final Object instance, final Field field, final String path, final ForgeConfigSpec.Builder builder) throws IllegalAccessException { + final long defaultValue = field.getLong(instance); + final long minValue = (long) Math.max(getMin(field), Long.MIN_VALUE); + final long maxValue = (long) Math.min(getMax(field), Long.MAX_VALUE); + + final ForgeConfigSpec.LongValue configValue = builder.defineInRange(path, defaultValue, minValue, maxValue); + + return new ConfigFieldPair<>(field, configValue); + } + + private static ConfigFieldPair parseDoubleField(final Object instance, final Field field, final String path, final ForgeConfigSpec.Builder builder) throws IllegalAccessException { + final double defaultValue = field.getDouble(instance); + final double minValue = getMin(field); + final double maxValue = getMax(field); + + final ForgeConfigSpec.DoubleValue configValue = builder.defineInRange(path, defaultValue, minValue, maxValue); + + return new ConfigFieldPair<>(field, configValue); + } + + private static ConfigFieldPair parseStringField(final Object instance, final Field field, final String path, final ForgeConfigSpec.Builder builder) throws IllegalAccessException { + final String defaultValue = (String) field.get(instance); + + final ForgeConfigSpec.ConfigValue configValue = builder.define(path, defaultValue); + + return new ConfigFieldPair<>(field, configValue); + } + + private static ConfigFieldPair parseUUIDField(final Object instance, final Field field, final String path, final ForgeConfigSpec.Builder builder) throws IllegalAccessException { + final UUID defaultValue = (UUID) field.get(instance); + + final ForgeConfigSpec.ConfigValue configValue = builder.define(path, defaultValue.toString()); + + return new ConfigFieldPair<>(field, configValue, UUID::fromString); + } + + private static String getPath(@Nullable final String prefix, final Field field) { + return (prefix != null ? prefix + "." : "") + field.getName(); + } + + private static double getMin(final Field field) { + final Min minAnnotation = field.getAnnotation(Min.class); + return minAnnotation != null ? minAnnotation.value() : 0; + } + + private static double getMax(final Field field) { + final Max maxAnnotation = field.getAnnotation(Max.class); + return maxAnnotation != null ? maxAnnotation.value() : Double.POSITIVE_INFINITY; + } + + /////////////////////////////////////////////////////////////////// + + @FunctionalInterface + private interface ConfigFieldParser { + ConfigFieldPair apply(final Object instance, final Field field, final String path, final ForgeConfigSpec.Builder builder) throws IllegalAccessException; + } + + private static final class ConfigDefinition { + public final Object instance; + public final ArrayList> values; + + public ConfigDefinition(final Object instance, final ArrayList> values) { + this.instance = instance; + this.values = values; + } + + public void apply() { + for (final ConfigFieldPair pair : values) { + pair.apply(instance); + } + } + } + + private static final class ConfigFieldPair { + public final Field field; + public final ForgeConfigSpec.ConfigValue value; + private final Function converter; + + public ConfigFieldPair(final Field field, final ForgeConfigSpec.ConfigValue value, final Function converter) { + this.field = field; + this.value = value; + this.converter = converter; + } + + public ConfigFieldPair(final Field field, final ForgeConfigSpec.ConfigValue value) { + this(field, value, x -> x); + } + + public void apply(final Object instance) { + try { + field.set(instance, converter.apply(value.get())); + } catch (final IllegalAccessException ignored) { + } + } + } +} diff --git a/src/main/java/li/cil/oc2/common/Main.java b/src/main/java/li/cil/oc2/common/Main.java index 5fdbd354..711915f6 100644 --- a/src/main/java/li/cil/oc2/common/Main.java +++ b/src/main/java/li/cil/oc2/common/Main.java @@ -30,7 +30,8 @@ public final class Main { Sedna.initialize(); Serializers.initialize(); - Config.initialize(); + ConfigManager.add(Config::new); + ConfigManager.initialize(); ItemTags.initialize(); BlockTags.initialize();