feat: config migrations #7

Merged
ChomeNS merged 1 commit from amy/chomensmod:1.20.1 into 1.20.1 2025-01-03 00:44:09 -05:00
7 changed files with 221 additions and 97 deletions

View file

@ -1,5 +1,7 @@
package land.chipmunk.chipmunkmod;
import land.chipmunk.chipmunkmod.config.ChipmunkModMigrations;
import land.chipmunk.chipmunkmod.config.Configuration;
import land.chipmunk.chipmunkmod.modules.KaboomCheck;
import land.chipmunk.chipmunkmod.modules.SelfCare;
import land.chipmunk.chipmunkmod.util.configurate.ConfigurateUtilities;
@ -45,6 +47,7 @@ public class ChipmunkMod implements ModInitializer {
}
public static Configuration loadConfig() throws IOException {
final ChipmunkModMigrations migrations = new ChipmunkModMigrations();
final ObjectMapper.Factory customFactory = ObjectMapper.factoryBuilder()
.defaultNamingScheme(NamingSchemes.CAMEL_CASE)
.build();
@ -61,14 +64,19 @@ public class ChipmunkMod implements ModInitializer {
// Configurate will create parent directories for us, so we don't need to do it
final BasicConfigurationNode node = loader.load();
final boolean isBlank = node.empty();
if (node.empty()) { // Config empty, fill it with defaults
final Configuration defaults = new Configuration();
node.set(Configuration.class, defaults);
migrations.setLatest(node);
loader.save(node);
final Configuration config = node.get(Configuration.class);
if (isBlank) {
node.set(Configuration.class, config);
return defaults;
}
if (migrations.migrate(node)) { // Migrated, write new config
loader.save(node);
}
return config;
return node.get(Configuration.class);
}
}

View file

@ -0,0 +1,12 @@
package land.chipmunk.chipmunkmod.config;
import land.chipmunk.chipmunkmod.config.migration.AbstractMigrationManager;
import land.chipmunk.chipmunkmod.config.migrations.MigrationV0;
public final class ChipmunkModMigrations extends AbstractMigrationManager {
public ChipmunkModMigrations() {
super("version");
this.register(new MigrationV0()); // unversioned -> v0
}
}

View file

@ -1,90 +1,89 @@
package land.chipmunk.chipmunkmod;
import net.kyori.adventure.text.Component;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable
public class Configuration {
public CommandManager commands = new CommandManager();
public CommandCore core = new CommandCore();
public Bots bots = new Bots();
public CustomChat customChat = new CustomChat();
public boolean fullbright = false; // unused, but it is here for old configs
public String autoSkinUsername = "off";
@ConfigSerializable
public static class CommandManager {
public String prefix = ".";
}
@ConfigSerializable
public static class CommandCore {
public BlockBox relativeArea = BlockBox.create(new BlockPos(0, 0, 0), new BlockPos(15, 0, 15));
}
@ConfigSerializable
public static class Bots {
public BotInfo hbot = new BotInfo("#", null);
public BotInfo sbot = new BotInfo(":", null);
public BotInfo chipmunk = new BotInfo("'", null);
public ChomeNSBotInfo chomens = new ChomeNSBotInfo("*", null, null, null);
public BotInfo fnfboyfriend = new BotInfo("~", null);
public BotInfo nbot = new BotInfo("?", null);
public BotInfo kittycorp = new BotInfo("^", null);
public TestBotInfo testbot = new TestBotInfo("-", null);
}
@ConfigSerializable
public static class ChomeNSBotInfo {
public String prefix;
public @Nullable String key;
public @Nullable String authKey;
public @Nullable String formatKey;
public ChomeNSBotInfo() {}
public ChomeNSBotInfo (String prefix, @Nullable String key, @Nullable String authKey, @Nullable String formatKey) {
this.prefix = prefix;
this.key = key;
this.authKey = authKey;
this.formatKey = formatKey;
}
}
@ConfigSerializable
public static class TestBotInfo {
public String prefix;
public @Nullable String webhookUrl;
public TestBotInfo() {}
public TestBotInfo (String prefix, @Nullable String webhookUrl) {
this.prefix = prefix;
this.webhookUrl = webhookUrl;
}
}
@ConfigSerializable
public static class BotInfo {
public String prefix;
public @Nullable String key;
public BotInfo() {}
public BotInfo (String prefix, @Nullable String key) {
this.prefix = prefix;
this.key = key;
}
}
@ConfigSerializable
public static class CustomChat {
public @NotNull Component format =
Component.translatable("chat.type.text",
Component.selector("UUID"),
Component.empty()
.append(Component.text("MESSAGE"))
);
}
}
package land.chipmunk.chipmunkmod.config;
import net.kyori.adventure.text.Component;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable
public class Configuration {
public CommandManager commands = new CommandManager();
public CommandCore core = new CommandCore();
public Bots bots = new Bots();
public CustomChat customChat = new CustomChat();
public String autoSkinUsername = "off";
@ConfigSerializable
public static class CommandManager {
public String prefix = ".";
}
@ConfigSerializable
public static class CommandCore {
public BlockBox relativeArea = BlockBox.create(new BlockPos(0, 0, 0), new BlockPos(15, 0, 15));
}
@ConfigSerializable
public static class Bots {
public BotInfo hbot = new BotInfo("#", null);
public BotInfo sbot = new BotInfo(":", null);
public BotInfo chipmunk = new BotInfo("'", null);
public ChomeNSBotInfo chomens = new ChomeNSBotInfo("*", null, null, null);
public BotInfo fnfboyfriend = new BotInfo("~", null);
public BotInfo nbot = new BotInfo("?", null);
public BotInfo kittycorp = new BotInfo("^", null);
public TestBotInfo testbot = new TestBotInfo("-", null);
}
@ConfigSerializable
public static class ChomeNSBotInfo {
public String prefix;
public @Nullable String key;
public @Nullable String authKey;
public @Nullable String formatKey;
public ChomeNSBotInfo() {}
public ChomeNSBotInfo (String prefix, @Nullable String key, @Nullable String authKey, @Nullable String formatKey) {
this.prefix = prefix;
this.key = key;
this.authKey = authKey;
this.formatKey = formatKey;
}
}
@ConfigSerializable
public static class TestBotInfo {
public String prefix;
public @Nullable String webhookUrl;
public TestBotInfo() {}
public TestBotInfo (String prefix, @Nullable String webhookUrl) {
this.prefix = prefix;
this.webhookUrl = webhookUrl;
}
}
@ConfigSerializable
public static class BotInfo {
public String prefix;
public @Nullable String key;
public BotInfo() {}
public BotInfo (String prefix, @Nullable String key) {
this.prefix = prefix;
this.key = key;
}
}
@ConfigSerializable
public static class CustomChat {
public @NotNull Component format =
Component.translatable("chat.type.text",
Component.selector("UUID"),
Component.empty()
.append(Component.text("MESSAGE"))
);
}
}

View file

@ -0,0 +1,63 @@
package land.chipmunk.chipmunkmod.config.migration;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
// Makes it easier for forks to add their own config versioning structure
public abstract class AbstractMigrationManager {
private final List<ConfigMigration> migrations = new ArrayList<>();
private final Object[] versionKey;
public AbstractMigrationManager(final Object... versionKey) {
this.versionKey = versionKey;
}
protected void register(final ConfigMigration migration) {
this.migrations.add(migration);
}
protected void registerFrom(final int version, final Supplier<ConfigurationTransformation> supplier) {
this.migrations.add(ConfigMigration.from(version, supplier));
}
public ConfigurationTransformation.Versioned create() {
final ConfigurationTransformation.VersionedBuilder builder = ConfigurationTransformation.versionedBuilder()
.versionKey(versionKey);
this.migrations.forEach(migration -> builder.addVersion(migration.version(), migration.create()));
return builder.build();
}
public <N extends ConfigurationNode> void setLatest(final N config) throws ConfigurateException {
final ConfigurationTransformation.Versioned transforms = this.create();
config.node(transforms.versionKey()).set(Integer.class, transforms.latestVersion());
}
public <N extends ConfigurationNode> boolean migrate(final N config) throws ConfigurateException {
final ConfigurationTransformation.Versioned transforms = this.create();
final int version = transforms.version(config);
if (version > transforms.latestVersion()) {
ChipmunkMod.LOGGER.warn("Latest config version is {}, but yours is {}! Are you from the future?",
transforms.latestVersion(), version);
return false;
}
transforms.apply(config);
final int newVersion = transforms.version(config);
if (version != newVersion) {
ChipmunkMod.LOGGER.info("Migrated config from version {} to {}!", version, newVersion);
return true;
}
return false;
}
}

View file

@ -0,0 +1,22 @@
package land.chipmunk.chipmunkmod.config.migration;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import java.util.function.Supplier;
public interface ConfigMigration {
int version();
ConfigurationTransformation create();
static ConfigMigration from(final int version, final Supplier<ConfigurationTransformation> supplier) {
return new ConfigMigrationImpl(version, supplier);
}
record ConfigMigrationImpl(int version, Supplier<ConfigurationTransformation> supplier) implements ConfigMigration {
@Override
public ConfigurationTransformation create() {
return this.supplier.get();
}
}
}

View file

@ -0,0 +1,21 @@
package land.chipmunk.chipmunkmod.config.migrations;
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
import org.spongepowered.configurate.transformation.TransformAction;
import static org.spongepowered.configurate.NodePath.path;
public final class MigrationV0 implements ConfigMigration {
@Override
public int version() {
return 0;
}
@Override
public ConfigurationTransformation create() {
return ConfigurationTransformation.builder()
.addAction(path("fullbright"), TransformAction.remove())
.build();
}
}

View file

@ -2,8 +2,7 @@ package land.chipmunk.chipmunkmod.util;
import com.mojang.brigadier.Command;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.Configuration;
import land.chipmunk.chipmunkmod.commands.SayCommand;
import land.chipmunk.chipmunkmod.config.Configuration;
import land.chipmunk.chipmunkmod.modules.Chat;
import land.chipmunk.chipmunkmod.modules.CustomChat;
import net.minecraft.client.MinecraftClient;