Skip to content

Commit

Permalink
Convert legacy config to split configs on startup
Browse files Browse the repository at this point in the history
  • Loading branch information
mschae23 committed Nov 30, 2024
1 parent c0826f8 commit 564a08d
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;

Expand Down
139 changes: 107 additions & 32 deletions src/main/java/de/mschae23/grindenchantments/GrindEnchantmentsMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -66,18 +71,21 @@ 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
private static ClientConfig CLIENT_CONFIG = null;

@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);
Expand All @@ -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
Expand All @@ -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();
Expand Down Expand Up @@ -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 <C extends ModConfig<C>> ModConfig.Type<C, ? extends ModConfig<C>> getConfigType(ModConfig.Type<C, ? extends ModConfig<C>>[] versions, int version) {
public static <C extends ModConfig<C>> ModConfig.Type<C, ? extends ModConfig<C>> getConfigType(ModConfig.Type<C, ? extends ModConfig<C>>[] versions, int version) {
for (int i = versions.length - 1; i >= 0; i--) {
ModConfig.Type<C, ? extends ModConfig<C>> v = versions[i];

Expand All @@ -156,40 +153,118 @@ public static GrindEnchantmentsConfigV3 getLegacyConfig() {
return versions[versions.length - 1];
}

private static <C extends ModConfig<C>> Optional<C> readGenericConfig(Path configName, Codec<ModConfig<C>> codec,
DynamicOps<JsonElement> ops, String kind) {
private static <C extends ModConfig<C>> C initializeGenericConfig(Path configName, C latestDefault, Codec<ModConfig<C>> codec,
DynamicOps<JsonElement> 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<C> readConfig = ConfigIo.decodeConfig(input, codec, ops);
config = readConfig.latest();
ModConfig<C> 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<ClientConfig> readClientConfig() {
return readGenericConfig(Path.of("client.json"), ModConfig.<ClientConfig>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<ServerConfig> readServerConfig(RegistryWrapper.WrapperLookup wrapperLookup) {
return readGenericConfig(Path.of("server.json"), ModConfig.<ServerConfig>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<GrindEnchantmentsConfigV3> 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<GrindEnchantmentsConfigV3> readLegacyConfig() {
private static Optional<GrindEnchantmentsConfigV3> readLegacyConfig(RegistryWrapper.WrapperLookup wrapperLookup) {
final GrindEnchantmentsConfigV3 legacyLatestConfigDefault = GrindEnchantmentsConfigV3.DEFAULT;
final int legacyLatestConfigVersion = legacyLatestConfigDefault.version();
@SuppressWarnings({"unchecked", "deprecation"})
Expand All @@ -208,7 +283,7 @@ private static Optional<GrindEnchantmentsConfigV3> readLegacyConfig() {
try (InputStream input = Files.newInputStream(configPath)) {
log(Level.INFO, "Reading legacy config.");

ModConfig<GrindEnchantmentsConfigV3> readConfig = ConfigIo.decodeConfig(input, legacyConfigCodec, JsonOps.INSTANCE);
ModConfig<GrindEnchantmentsConfigV3> 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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ClientConfig> {
public static final MapCodec<ClientConfig> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Codec.BOOL.fieldOf("show_enchantment_cost").forGetter(ClientConfig::showLevelCost)
public record ClientConfig(boolean showLevelCost, boolean useDefaultIfUnsynced) implements ModConfig<ClientConfig> {
public static final MapCodec<ClientConfig> 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<ClientConfig, ClientConfig> TYPE = new ModConfig.Type<>(4, CODEC);
public static final ClientConfig DEFAULT = new ClientConfig(true);

public static final ModConfig.Type<ClientConfig, ClientConfig> TYPE = new ModConfig.Type<>(4, TYPE_CODEC);
public static final ClientConfig DEFAULT = new ClientConfig(true, true);
@SuppressWarnings("unchecked")
public static final ModConfig.Type<ClientConfig, ? extends ModConfig<ClientConfig>>[] VERSIONS = new ModConfig.Type[] { TYPE, };

public static final Codec<ModConfig<ClientConfig>> CODEC = ModConfig.createCodec(TYPE.version(), version ->
GrindEnchantmentsMod.getConfigType(VERSIONS, version));

@Override
public Type<ClientConfig, ?> type() {
return TYPE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,32 @@
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<ServerConfig> {
public static final MapCodec<ServerConfig> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
public static final MapCodec<ServerConfig> 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),
FilterConfig.CODEC.fieldOf("filter").forGetter(ServerConfig::filter),
DedicatedServerConfig.CODEC.orElse(DedicatedServerConfig.DEFAULT).fieldOf("dedicated_server_options").forGetter(ServerConfig::dedicatedServerConfig)
).apply(instance, instance.stable(ServerConfig::new)));

public static final ModConfig.Type<ServerConfig, ServerConfig> TYPE = new ModConfig.Type<>(4, CODEC);
public static final ModConfig.Type<ServerConfig, ServerConfig> 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<ServerConfig, ? extends ModConfig<ServerConfig>>[] VERSIONS = new ModConfig.Type[] { TYPE, };

public static final Codec<ModConfig<ServerConfig>> CODEC = ModConfig.createCodec(TYPE.version(), version ->
GrindEnchantmentsMod.getConfigType(VERSIONS, version));

@Override
public Type<ServerConfig, ?> type() {
return TYPE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<DedicatedServerConfigV3> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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<Identifier> items, FilterAction action) {
public static final Codec<ItemConfig> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codecs.listOrSingle(Identifier.CODEC).fieldOf("enchantments").forGetter(ItemConfig::items),
Expand Down
Loading

0 comments on commit 564a08d

Please sign in to comment.