From 564a08d9caad34dcbbd5987224ee5fbaa6ebc342 Mon Sep 17 00:00:00 2001 From: mschae23 <46165762+mschae23@users.noreply.github.com> Date: Sat, 30 Nov 2024 14:04:13 +0100 Subject: [PATCH] Convert legacy config to split configs on startup --- .../grindenchantments/GrindEnchantments.java | 4 +- .../GrindEnchantmentsMod.java | 139 ++++++++++++++---- .../config/ClientConfig.java | 16 +- .../config/ServerConfig.java | 10 +- .../legacy/v3/DedicatedServerConfigV3.java | 6 +- .../config/legacy/v3/FilterConfigV3.java | 6 + .../legacy/v3/GrindEnchantmentsConfigV3.java | 11 ++ .../legacy/v3/ResetRepairCostConfigV3.java | 5 + 8 files changed, 153 insertions(+), 44 deletions(-) diff --git a/src/main/java/de/mschae23/grindenchantments/GrindEnchantments.java b/src/main/java/de/mschae23/grindenchantments/GrindEnchantments.java index 87bf139..51a43da 100644 --- a/src/main/java/de/mschae23/grindenchantments/GrindEnchantments.java +++ b/src/main/java/de/mschae23/grindenchantments/GrindEnchantments.java @@ -31,8 +31,8 @@ import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import de.mschae23.grindenchantments.config.DedicatedServerConfig; import de.mschae23.grindenchantments.config.FilterConfig; -import de.mschae23.grindenchantments.config.legacy.v3.DedicatedServerConfigV3; import de.mschae23.grindenchantments.cost.CostFunction; public class GrindEnchantments { @@ -47,7 +47,7 @@ public static ItemEnchantmentsComponent getEnchantments(ItemStack stack, FilterC return filter.filter(EnchantmentHelper.getEnchantments(stack)); } - public static ItemStack addLevelCostComponent(ItemStack stack, IntSupplier cost, boolean canTakeItem, DedicatedServerConfigV3 config) { + public static ItemStack addLevelCostComponent(ItemStack stack, IntSupplier cost, boolean canTakeItem, DedicatedServerConfig config) { if (!config.alternativeCostDisplay()) return stack; diff --git a/src/main/java/de/mschae23/grindenchantments/GrindEnchantmentsMod.java b/src/main/java/de/mschae23/grindenchantments/GrindEnchantmentsMod.java index 4b72b80..bc2e3bd 100644 --- a/src/main/java/de/mschae23/grindenchantments/GrindEnchantmentsMod.java +++ b/src/main/java/de/mschae23/grindenchantments/GrindEnchantmentsMod.java @@ -19,12 +19,17 @@ package de.mschae23.grindenchantments; +import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.util.Optional; +import java.util.stream.Stream; import net.minecraft.registry.RegistryOps; import net.minecraft.registry.RegistryWrapper; import net.minecraft.util.Identifier; @@ -48,13 +53,13 @@ import de.mschae23.grindenchantments.config.legacy.v1.GrindEnchantmentsConfigV1; import de.mschae23.grindenchantments.config.legacy.v2.GrindEnchantmentsConfigV2; import de.mschae23.grindenchantments.config.legacy.v3.GrindEnchantmentsConfigV3; +import de.mschae23.grindenchantments.config.sync.ServerConfigS2CPayload; import de.mschae23.grindenchantments.cost.CostFunctionType; import de.mschae23.grindenchantments.event.ApplyLevelCostEvent; import de.mschae23.grindenchantments.event.GrindstoneEvents; import de.mschae23.grindenchantments.impl.DisenchantOperation; import de.mschae23.grindenchantments.impl.MoveOperation; import de.mschae23.grindenchantments.impl.ResetRepairCostOperation; -import de.mschae23.grindenchantments.config.sync.ServerConfigS2CPayload; import de.mschae23.grindenchantments.registry.GrindEnchantmentsRegistries; import io.github.fourmisain.taxfreelevels.TaxFreeLevels; import org.apache.logging.log4j.Level; @@ -66,8 +71,6 @@ public class GrindEnchantmentsMod implements ModInitializer { public static final String MODID = "grindenchantments"; public static final Logger LOGGER = LogManager.getLogger("Grind Enchantments"); - @Deprecated - private static GrindEnchantmentsConfigV3 LEGACY_CONFIG = GrindEnchantmentsConfigV3.DEFAULT; @Nullable private static ServerConfig SERVER_CONFIG = null; @Nullable @@ -75,9 +78,14 @@ public class GrindEnchantmentsMod implements ModInitializer { @Override public void onInitialize() { + GrindEnchantmentsRegistries.init(); + CostFunctionType.init(); + + convertLegacyConfig(); + // Singleplayer or on server ServerLifecycleEvents.SERVER_STARTING.register(server -> { - SERVER_CONFIG = readServerConfig(server.getRegistryManager()).orElse(ServerConfig.DEFAULT); + SERVER_CONFIG = initializeServerConfig(server.getRegistryManager()); SERVER_CONFIG.validateRegistryEntries(server.getRegistryManager()); }); ServerLifecycleEvents.SERVER_STOPPING.register(server -> SERVER_CONFIG = null); @@ -86,7 +94,7 @@ public void onInitialize() { PayloadTypeRegistry.configurationS2C().register(ServerConfigS2CPayload.ID, ServerConfigS2CPayload.CODEC); ClientLifecycleEvents.CLIENT_STARTED.register(client -> { - CLIENT_CONFIG = GrindEnchantmentsMod.readClientConfig().orElse(ClientConfig.DEFAULT); + CLIENT_CONFIG = GrindEnchantmentsMod.initializeClientConfig(); ClientConfigurationNetworking.registerGlobalReceiver(ServerConfigS2CPayload.ID, (payload, context) -> { //noinspection resource @@ -103,12 +111,6 @@ public void onInitialize() { } }); - //noinspection deprecation - LEGACY_CONFIG = readLegacyConfig().orElse(GrindEnchantmentsConfigV3.DEFAULT); - - GrindEnchantmentsRegistries.init(); - CostFunctionType.init(); - DisenchantOperation disenchant = new DisenchantOperation(); MoveOperation move = new MoveOperation(); ResetRepairCostOperation resetRepairCost = new ResetRepairCostOperation(); @@ -139,12 +141,7 @@ public static ClientConfig getClientConfig() { return CLIENT_CONFIG == null ? ClientConfig.DEFAULT : CLIENT_CONFIG; } - @Deprecated - public static GrindEnchantmentsConfigV3 getLegacyConfig() { - return LEGACY_CONFIG; - } - - private static > ModConfig.Type> getConfigType(ModConfig.Type>[] versions, int version) { + public static > ModConfig.Type> getConfigType(ModConfig.Type>[] versions, int version) { for (int i = versions.length - 1; i >= 0; i--) { ModConfig.Type> v = versions[i]; @@ -156,40 +153,118 @@ public static GrindEnchantmentsConfigV3 getLegacyConfig() { return versions[versions.length - 1]; } - private static > Optional readGenericConfig(Path configName, Codec> codec, - DynamicOps ops, String kind) { + private static > C initializeGenericConfig(Path configName, C latestDefault, Codec> codec, + DynamicOps ops, String kind) { + // modified version of ConfigIoImpl.initializeConfig from codec-config-api Path filePath = FabricLoader.getInstance().getConfigDir().resolve(MODID).resolve(configName); - @Nullable - C config = null; + C latestConfig = latestDefault; if (Files.exists(filePath) && Files.isRegularFile(filePath)) { try (InputStream input = Files.newInputStream(filePath)) { log(Level.INFO, "Reading " + kind + " config."); - ModConfig readConfig = ConfigIo.decodeConfig(input, codec, ops); - config = readConfig.latest(); + ModConfig config = ConfigIo.decodeConfig(input, codec, ops); + latestConfig = config.latest(); + + if (config.shouldUpdate() && config.version() < latestDefault.version()) { + // Default OpenOptions are CREATE, TRUNCATE_EXISTING, and WRITE + try (OutputStream output = Files.newOutputStream(filePath); + OutputStreamWriter writer = new OutputStreamWriter(new BufferedOutputStream(output))) { + log(Level.INFO, "Writing updated " + kind + " config."); + + ConfigIo.encodeConfig(writer, codec, config.latest(), ops); + } catch (IOException e) { + log(Level.ERROR, "IO exception while trying to write updated config: " + e.getLocalizedMessage()); + } catch (ConfigException e) { + log(Level.ERROR, e.getLocalizedMessage()); + } + } } catch (IOException e) { log(Level.ERROR, "IO exception while trying to read " + kind + " config: " + e.getLocalizedMessage()); } catch (ConfigException e) { log(Level.ERROR, e.getLocalizedMessage()); } + } else { + // Write default config if the file doesn't exist + try (OutputStream output = Files.newOutputStream(filePath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE); + OutputStreamWriter writer = new OutputStreamWriter(new BufferedOutputStream(output))) { + log(Level.INFO, "Writing default " + kind + " config."); + + ConfigIo.encodeConfig(writer, codec, latestDefault, ops); + } catch (IOException e) { + log(Level.ERROR, "IO exception while trying to write config: " + e.getLocalizedMessage()); + } catch (ConfigException e) { + log(Level.ERROR, e.getLocalizedMessage()); + } } - return Optional.ofNullable(config); + return latestConfig; + } + + public static ClientConfig initializeClientConfig() { + return initializeGenericConfig(Path.of("client.json"), ClientConfig.DEFAULT, ClientConfig.CODEC, + JsonOps.INSTANCE, "client"); } - public static Optional readClientConfig() { - return readGenericConfig(Path.of("client.json"), ModConfig.createCodec(ClientConfig.TYPE.version(), version -> - getConfigType(ClientConfig.VERSIONS, version)), JsonOps.INSTANCE, "client"); + private static ServerConfig initializeServerConfig(RegistryWrapper.WrapperLookup wrapperLookup) { + return initializeGenericConfig(Path.of("server.json"), ServerConfig.DEFAULT, ServerConfig.CODEC, + RegistryOps.of(JsonOps.INSTANCE, wrapperLookup), "server"); } - private static Optional readServerConfig(RegistryWrapper.WrapperLookup wrapperLookup) { - return readGenericConfig(Path.of("server.json"), ModConfig.createCodec(ServerConfig.TYPE.version(), version -> - getConfigType(ServerConfig.VERSIONS, version)), RegistryOps.of(JsonOps.INSTANCE, wrapperLookup), "server"); + @SuppressWarnings("deprecation") + private static void convertLegacyConfig() { + final Path newConfigDirPath = FabricLoader.getInstance().getConfigDir().resolve(MODID); + + if (!Files.isDirectory(newConfigDirPath)) { + RegistryWrapper.WrapperLookup wrapperLookup = RegistryWrapper.WrapperLookup.of(Stream.of(GrindEnchantmentsRegistries.COST_FUNCTION)); + Optional legacyConfigOpt = readLegacyConfig(wrapperLookup); + + if (legacyConfigOpt.isPresent()) { + GrindEnchantmentsConfigV3 legacyConfig = legacyConfigOpt.get(); + ServerConfig serverConfig = legacyConfig.toServerConfig(); + ClientConfig clientConfig = legacyConfig.toClientConfig(); + + try { + final Path serverConfigPath = newConfigDirPath.resolve("server.json"); + final Path clientConfigPath = newConfigDirPath.resolve("client.json"); + + Files.createDirectories(newConfigDirPath); + boolean success = true; + + try (OutputStream outputStream = Files.newOutputStream(serverConfigPath); + OutputStreamWriter writer = new OutputStreamWriter(new BufferedOutputStream(outputStream))) { + log(Level.INFO, "Writing converted server config."); + + ConfigIo.encodeConfig(writer, ServerConfig.CODEC, serverConfig, RegistryOps.of(JsonOps.INSTANCE, wrapperLookup)); + } catch (ConfigException e) { + log(Level.ERROR, e.getLocalizedMessage()); + success = false; + } + + try (OutputStream outputStream = Files.newOutputStream(clientConfigPath); + OutputStreamWriter writer = new OutputStreamWriter(new BufferedOutputStream(outputStream))) { + log(Level.INFO, "Writing converted client config."); + + ConfigIo.encodeConfig(writer, ClientConfig.CODEC, clientConfig, RegistryOps.of(JsonOps.INSTANCE, wrapperLookup)); + } catch (ConfigException e) { + log(Level.ERROR, e.getLocalizedMessage()); + success = false; + } + + if (success) { + Path configDir = FabricLoader.getInstance().getConfigDir(); + // Move to grindenchantments.json.old if conversion succeeds + Files.move(configDir.resolve(MODID + ".json"), configDir.resolve(MODID + ".json.old")); + } + } catch (IOException e) { + log(Level.ERROR, "IO exception while trying to convert legacy config: " + e.getLocalizedMessage()); + } + } + } } @SuppressWarnings("deprecation") - private static Optional readLegacyConfig() { + private static Optional readLegacyConfig(RegistryWrapper.WrapperLookup wrapperLookup) { final GrindEnchantmentsConfigV3 legacyLatestConfigDefault = GrindEnchantmentsConfigV3.DEFAULT; final int legacyLatestConfigVersion = legacyLatestConfigDefault.version(); @SuppressWarnings({"unchecked", "deprecation"}) @@ -208,7 +283,7 @@ private static Optional readLegacyConfig() { try (InputStream input = Files.newInputStream(configPath)) { log(Level.INFO, "Reading legacy config."); - ModConfig readConfig = ConfigIo.decodeConfig(input, legacyConfigCodec, JsonOps.INSTANCE); + ModConfig readConfig = ConfigIo.decodeConfig(input, legacyConfigCodec, RegistryOps.of(JsonOps.INSTANCE, wrapperLookup)); config = readConfig.latest(); } catch (IOException e) { log(Level.ERROR, "IO exception while trying to read config: " + e.getLocalizedMessage()); diff --git a/src/main/java/de/mschae23/grindenchantments/config/ClientConfig.java b/src/main/java/de/mschae23/grindenchantments/config/ClientConfig.java index 17d05b6..f3805d4 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/ClientConfig.java +++ b/src/main/java/de/mschae23/grindenchantments/config/ClientConfig.java @@ -23,18 +23,22 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import de.mschae23.config.api.ModConfig; +import de.mschae23.grindenchantments.GrindEnchantmentsMod; -public record ClientConfig(boolean showLevelCost) implements ModConfig { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( - Codec.BOOL.fieldOf("show_enchantment_cost").forGetter(ClientConfig::showLevelCost) +public record ClientConfig(boolean showLevelCost, boolean useDefaultIfUnsynced) implements ModConfig { + public static final MapCodec TYPE_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + Codec.BOOL.fieldOf("show_enchantment_cost").forGetter(ClientConfig::showLevelCost), + Codec.BOOL.fieldOf("use_default_server_config_if_unsynced").forGetter(ClientConfig::useDefaultIfUnsynced) ).apply(instance, instance.stable(ClientConfig::new))); - public static final ModConfig.Type TYPE = new ModConfig.Type<>(4, CODEC); - public static final ClientConfig DEFAULT = new ClientConfig(true); - + public static final ModConfig.Type TYPE = new ModConfig.Type<>(4, TYPE_CODEC); + public static final ClientConfig DEFAULT = new ClientConfig(true, true); @SuppressWarnings("unchecked") public static final ModConfig.Type>[] VERSIONS = new ModConfig.Type[] { TYPE, }; + public static final Codec> CODEC = ModConfig.createCodec(TYPE.version(), version -> + GrindEnchantmentsMod.getConfigType(VERSIONS, version)); + @Override public Type type() { return TYPE; diff --git a/src/main/java/de/mschae23/grindenchantments/config/ServerConfig.java b/src/main/java/de/mschae23/grindenchantments/config/ServerConfig.java index fb18a55..6d25f2c 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/ServerConfig.java +++ b/src/main/java/de/mschae23/grindenchantments/config/ServerConfig.java @@ -20,14 +20,16 @@ package de.mschae23.grindenchantments.config; import net.minecraft.registry.RegistryWrapper; +import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import de.mschae23.config.api.ModConfig; +import de.mschae23.grindenchantments.GrindEnchantmentsMod; public record ServerConfig(DisenchantConfig disenchant, MoveConfig move, ResetRepairCostConfig resetRepairCost, FilterConfig filter, DedicatedServerConfig dedicatedServerConfig) implements ModConfig { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + public static final MapCodec TYPE_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( DisenchantConfig.CODEC.fieldOf("disenchant_to_book").forGetter(ServerConfig::disenchant), MoveConfig.CODEC.fieldOf("move_enchantments").forGetter(ServerConfig::move), ResetRepairCostConfig.CODEC.fieldOf("reset_repair_cost").forGetter(ServerConfig::resetRepairCost), @@ -35,13 +37,15 @@ public record ServerConfig(DisenchantConfig disenchant, MoveConfig move, ResetRe DedicatedServerConfig.CODEC.orElse(DedicatedServerConfig.DEFAULT).fieldOf("dedicated_server_options").forGetter(ServerConfig::dedicatedServerConfig) ).apply(instance, instance.stable(ServerConfig::new))); - public static final ModConfig.Type TYPE = new ModConfig.Type<>(4, CODEC); + public static final ModConfig.Type TYPE = new ModConfig.Type<>(4, TYPE_CODEC); public static final ServerConfig DEFAULT = new ServerConfig(DisenchantConfig.DEFAULT, MoveConfig.DEFAULT, ResetRepairCostConfig.DEFAULT, FilterConfig.DEFAULT, DedicatedServerConfig.DEFAULT); - @SuppressWarnings("unchecked") public static final ModConfig.Type>[] VERSIONS = new ModConfig.Type[] { TYPE, }; + public static final Codec> CODEC = ModConfig.createCodec(TYPE.version(), version -> + GrindEnchantmentsMod.getConfigType(VERSIONS, version)); + @Override public Type type() { return TYPE; diff --git a/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/DedicatedServerConfigV3.java b/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/DedicatedServerConfigV3.java index 6345ee8..1c28208 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/DedicatedServerConfigV3.java +++ b/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/DedicatedServerConfigV3.java @@ -21,12 +21,16 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.grindenchantments.config.DedicatedServerConfig; @Deprecated public record DedicatedServerConfigV3(boolean alternativeCostDisplay) { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Codec.BOOL.fieldOf("alternative_cost_display_enabled").forGetter(DedicatedServerConfigV3::alternativeCostDisplay) ).apply(instance, instance.stable(DedicatedServerConfigV3::new))); - public static final DedicatedServerConfigV3 DEFAULT = new DedicatedServerConfigV3(false); + + public DedicatedServerConfig latest() { + return new DedicatedServerConfig(this.alternativeCostDisplay); + } } diff --git a/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/FilterConfigV3.java b/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/FilterConfigV3.java index 9efdfdf..ff72c3f 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/FilterConfigV3.java +++ b/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/FilterConfigV3.java @@ -25,6 +25,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import de.mschae23.grindenchantments.config.FilterAction; +import de.mschae23.grindenchantments.config.FilterConfig; @Deprecated public record FilterConfigV3(boolean enabled, ItemConfig item, EnchantmentConfig enchantment, FilterAction curses) { @@ -37,6 +38,11 @@ public record FilterConfigV3(boolean enabled, ItemConfig item, EnchantmentConfig public static final FilterConfigV3 DEFAULT = new FilterConfigV3(true, ItemConfig.DEFAULT, EnchantmentConfig.DEFAULT, FilterAction.IGNORE); + public FilterConfig latest() { + return new FilterConfig(this.enabled, new FilterConfig.ItemConfig(this.item.items, this.item.action), + new FilterConfig.EnchantmentConfig(this.enchantment.enchantments, this.enchantment.action), this.curses); + } + public record ItemConfig(List items, FilterAction action) { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Codecs.listOrSingle(Identifier.CODEC).fieldOf("enchantments").forGetter(ItemConfig::items), diff --git a/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/GrindEnchantmentsConfigV3.java b/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/GrindEnchantmentsConfigV3.java index 0bc90e5..ec4415d 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/GrindEnchantmentsConfigV3.java +++ b/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/GrindEnchantmentsConfigV3.java @@ -22,8 +22,10 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import de.mschae23.config.api.ModConfig; +import de.mschae23.grindenchantments.config.ClientConfig; import de.mschae23.grindenchantments.config.DisenchantConfig; import de.mschae23.grindenchantments.config.MoveConfig; +import de.mschae23.grindenchantments.config.ServerConfig; @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated @@ -58,4 +60,13 @@ public GrindEnchantmentsConfigV3 latest() { public boolean shouldUpdate() { return true; } + + public ServerConfig toServerConfig() { + return new ServerConfig(this.disenchant, this.move, this.resetRepairCost.latest(), this.filter.latest(), + this.dedicatedServerConfig.latest()); + } + + public ClientConfig toClientConfig() { + return new ClientConfig(this.clientConfig.showLevelCost(), true); + } } diff --git a/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/ResetRepairCostConfigV3.java b/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/ResetRepairCostConfigV3.java index 4d21c2a..29d718a 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/ResetRepairCostConfigV3.java +++ b/src/main/java/de/mschae23/grindenchantments/config/legacy/v3/ResetRepairCostConfigV3.java @@ -24,6 +24,7 @@ import net.minecraft.util.dynamic.Codecs; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.grindenchantments.config.ResetRepairCostConfig; import de.mschae23.grindenchantments.cost.AverageCountCostFunction; import de.mschae23.grindenchantments.cost.CostFunction; import de.mschae23.grindenchantments.cost.CountLevelsCostFunction; @@ -42,4 +43,8 @@ public record ResetRepairCostConfigV3(boolean enabled, List catalyst List.of(Identifier.ofVanilla("diamond")), true, // Intentionally no filter function new TransformCostFunction(new AverageCountCostFunction(new CountLevelsCostFunction(1.0, 4.0)), 1.5, 4.0)); + + public ResetRepairCostConfig latest() { + return new ResetRepairCostConfig(this.enabled, this.catalystItems, this.requiresEnchantment, this.costFunction); + } }