Separate config declaration from Forge config logic a bit.

This commit is contained in:
Florian Nücke
2021-06-03 13:29:09 +02:00
parent a124d6f826
commit 2504a67a39
3 changed files with 251 additions and 166 deletions

View File

@@ -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<CommonSettings, ForgeConfigSpec> 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<String> 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();
}
}
}

View File

@@ -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<Class<?>, ConfigFieldParser> PARSERS = new HashMap<>();
private static final Map<ForgeConfigSpec, ConfigDefinition> 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 <T> void add(final Supplier<T> factory) {
final ArrayList<ConfigFieldPair<?>> values = new ArrayList<>();
final Pair<?, ForgeConfigSpec> 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 <T> void fillSpec(final T instance, final ForgeConfigSpec.Builder builder, final ArrayList<ConfigFieldPair<?>> values) {
for (final Field field : instance.getClass().getFields()) {
parseField(instance, builder, values, field);
}
}
private static <T> void parseField(final T instance, final ForgeConfigSpec.Builder builder, final ArrayList<ConfigFieldPair<?>> 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<String> 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<String> 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<ConfigFieldPair<?>> values;
public ConfigDefinition(final Object instance, final ArrayList<ConfigFieldPair<?>> values) {
this.instance = instance;
this.values = values;
}
public void apply() {
for (final ConfigFieldPair<?> pair : values) {
pair.apply(instance);
}
}
}
private static final class ConfigFieldPair<T> {
public final Field field;
public final ForgeConfigSpec.ConfigValue<T> value;
private final Function<T, Object> converter;
public ConfigFieldPair(final Field field, final ForgeConfigSpec.ConfigValue<T> value, final Function<T, Object> converter) {
this.field = field;
this.value = value;
this.converter = converter;
}
public ConfigFieldPair(final Field field, final ForgeConfigSpec.ConfigValue<T> value) {
this(field, value, x -> x);
}
public void apply(final Object instance) {
try {
field.set(instance, converter.apply(value.get()));
} catch (final IllegalAccessException ignored) {
}
}
}
}

View File

@@ -30,7 +30,8 @@ public final class Main {
Sedna.initialize();
Serializers.initialize();
Config.initialize();
ConfigManager.add(Config::new);
ConfigManager.initialize();
ItemTags.initialize();
BlockTags.initialize();