diff options
Diffstat (limited to 'src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigPlugin.java')
-rw-r--r-- | src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigPlugin.java | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigPlugin.java b/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigPlugin.java new file mode 100644 index 0000000..7f230de --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/compat/configured/IcebergConfigPlugin.java @@ -0,0 +1,199 @@ +package com.anthonyhilyard.iceberg.compat.configured; + +import com.anthonyhilyard.iceberg.config.IcebergConfigSpec; +import com.electronwill.nightconfig.core.AbstractConfig; +import com.electronwill.nightconfig.core.CommentedConfig; +import com.electronwill.nightconfig.core.UnmodifiableConfig; +import com.electronwill.nightconfig.core.file.CommentedFileConfig; +import com.google.common.collect.ImmutableList; +import com.mojang.datafixers.util.Pair; +import com.mrcrayfish.configured.Configured; +import com.mrcrayfish.configured.api.ConfigType; +import com.mrcrayfish.configured.api.IConfigEntry; +import com.mrcrayfish.configured.api.IConfigValue; +import com.mrcrayfish.configured.api.IModConfig; +import com.mrcrayfish.configured.impl.forge.ForgeListValue; +import com.mrcrayfish.configured.impl.forge.ForgeValue; +import com.mrcrayfish.configured.util.ConfigHelper; +import net.minecraft.Util; +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fml.event.config.ModConfigEvent; + +import java.nio.file.Path; +import java.util.EnumMap; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.commons.compress.utils.Lists; + +public class IcebergConfigPlugin implements IModConfig +{ + protected static final EnumMap<ModConfig.Type, ConfigType> TYPE_RESOLVER = Util.make(new EnumMap<>(ModConfig.Type.class), (map) -> { + map.put(ModConfig.Type.CLIENT, ConfigType.CLIENT); + map.put(ModConfig.Type.COMMON, ConfigType.UNIVERSAL); + map.put(ModConfig.Type.SERVER, ConfigType.WORLD_SYNC); + }); + + protected final ModConfig config; + protected final List<IcebergValueEntry> allConfigValues; + + public IcebergConfigPlugin(ModConfig config) + { + this.config = config; + this.allConfigValues = getAllConfigValues(config); + } + + @Override + public void update(IConfigEntry entry) + { + Set<IConfigValue<?>> changedValues = ConfigHelper.getChangedValues(entry); + if (!changedValues.isEmpty()) + { + CommentedConfig newConfig = CommentedConfig.copy(this.config.getConfigData()); + changedValues.forEach(value -> + { + if (value instanceof ForgeValue<?> forge) + { + if (forge instanceof ForgeListValue forgeList) + { + Function<List<?>, List<?>> converter = forgeList.getConverter(); + if (converter != null) + { + newConfig.set(forge.configValue.getPath(), converter.apply(forgeList.get())); + return; + } + } + newConfig.set(forge.configValue.getPath(), value.get()); + } + }); + this.config.getConfigData().putAll(newConfig); + } + + if (this.getType() == ConfigType.WORLD_SYNC) + { + if (!ConfigHelper.isPlayingGame()) + { + // Unload server configs since still in main menu + this.config.getHandler().unload(this.config.getFullPath().getParent(), this.config); + ConfigHelper.setForgeConfigData(this.config, null); + } + } + else if (!changedValues.isEmpty()) + { + Configured.LOGGER.info("Sending config reloading event for {}", this.config.getFileName()); + this.config.getSpec().afterReload(); + ConfigHelper.fireForgeConfigEvent(this.config, new ModConfigEvent.Reloading(this.config)); + } + } + + @Override + public IConfigEntry getRoot() + { + return new IcebergFolderEntry(((IcebergConfigSpec) this.config.getSpec()).getValues(), (IcebergConfigSpec) this.config.getSpec()); + } + + @Override + public ConfigType getType() + { + return TYPE_RESOLVER.get(this.config.getType()); + } + + @Override + public String getFileName() + { + return this.config.getFileName(); + } + + @Override + public String getModId() + { + return this.config.getModId(); + } + + @Override + public void loadWorldConfig(Path path, Consumer<IModConfig> result) + { + final CommentedFileConfig data = this.config.getHandler().reader(path).apply(this.config); + ConfigHelper.setForgeConfigData(this.config, data); + result.accept(this); + } + + @Override + public void stopEditing() + { + // Attempts to unload the server config if player simply just went back + if (this.config != null && this.getType() == ConfigType.WORLD) + { + if (!ConfigHelper.isPlayingGame()) + { + // Unload server configs since still in main menu + this.config.getHandler().unload(this.config.getFullPath().getParent(), this.config); + ConfigHelper.setForgeConfigData(this.config, null); + } + } + } + + @Override + public boolean isChanged() + { + // Block world configs since the path is dynamic + if (ConfigHelper.isWorldConfig(this) && this.config.getConfigData() == null) + { + return false; + } + + // Check if any config value doesn't equal it's default + return this.allConfigValues.stream().anyMatch(entry -> { + return !Objects.equals(entry.value.get(), entry.spec.getDefault()); + }); + } + + @Override + public void restoreDefaults() + { + // Block world configs since the path is dynamic + if (ConfigHelper.isWorldConfig(this) && this.config.getConfigData() == null) + { + return; + } + + // Creates a copy of the config data then pushes all at once to avoid multiple IO ops + CommentedConfig newConfig = CommentedConfig.copy(this.config.getConfigData()); + this.allConfigValues.forEach(entry -> newConfig.set(entry.value.getPath(), entry.spec.getDefault())); + this.config.getConfigData().putAll(newConfig); + + // Finally clear cache of all config values + this.allConfigValues.forEach(pair -> pair.value.clearCache()); + } + + private static List<IcebergValueEntry> getAllConfigValues(ModConfig config) + { + IcebergConfigSpec icebergConfigSpec = (IcebergConfigSpec) config.getSpec(); + List<Pair<ForgeConfigSpec.ConfigValue<?>, ForgeConfigSpec.ValueSpec>> values = Lists.newArrayList(); + gatherValuesFromIcebergConfig(icebergConfigSpec.getValues(), icebergConfigSpec, values); + return ImmutableList.copyOf(values).stream().map(pair -> new IcebergValueEntry(pair.getFirst(), pair.getSecond())).collect(Collectors.toList()); + } + + private static void gatherValuesFromIcebergConfig(UnmodifiableConfig config, IcebergConfigSpec spec, List<Pair<ForgeConfigSpec.ConfigValue<?>, ForgeConfigSpec.ValueSpec>> values) + { + config.valueMap().forEach((key, value) -> + { + if (value instanceof AbstractConfig) + { + gatherValuesFromIcebergConfig((UnmodifiableConfig) value, spec, values); + } + else if (value instanceof ForgeConfigSpec.ConfigValue<?> configValue) + { + ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(configValue.getPath()); + values.add(Pair.of(configValue, valueSpec)); + } + }); + } + + private record IcebergValueEntry(ForgeConfigSpec.ConfigValue<?> value, ForgeConfigSpec.ValueSpec spec) {} +} |