feat: config migrations #7
7 changed files with 221 additions and 97 deletions
src/main/java/land/chipmunk/chipmunkmod
|
@ -1,5 +1,7 @@
|
||||||
package land.chipmunk.chipmunkmod;
|
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.KaboomCheck;
|
||||||
import land.chipmunk.chipmunkmod.modules.SelfCare;
|
import land.chipmunk.chipmunkmod.modules.SelfCare;
|
||||||
import land.chipmunk.chipmunkmod.util.configurate.ConfigurateUtilities;
|
import land.chipmunk.chipmunkmod.util.configurate.ConfigurateUtilities;
|
||||||
|
@ -45,6 +47,7 @@ public class ChipmunkMod implements ModInitializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Configuration loadConfig() throws IOException {
|
public static Configuration loadConfig() throws IOException {
|
||||||
|
final ChipmunkModMigrations migrations = new ChipmunkModMigrations();
|
||||||
final ObjectMapper.Factory customFactory = ObjectMapper.factoryBuilder()
|
final ObjectMapper.Factory customFactory = ObjectMapper.factoryBuilder()
|
||||||
.defaultNamingScheme(NamingSchemes.CAMEL_CASE)
|
.defaultNamingScheme(NamingSchemes.CAMEL_CASE)
|
||||||
.build();
|
.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
|
// Configurate will create parent directories for us, so we don't need to do it
|
||||||
final BasicConfigurationNode node = loader.load();
|
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);
|
return defaults;
|
||||||
if (isBlank) {
|
}
|
||||||
node.set(Configuration.class, config);
|
|
||||||
|
if (migrations.migrate(node)) { // Migrated, write new config
|
||||||
loader.save(node);
|
loader.save(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return node.get(Configuration.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,90 +1,89 @@
|
||||||
package land.chipmunk.chipmunkmod;
|
package land.chipmunk.chipmunkmod.config;
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minecraft.util.math.BlockBox;
|
import net.minecraft.util.math.BlockBox;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||||
|
|
||||||
@ConfigSerializable
|
@ConfigSerializable
|
||||||
public class Configuration {
|
public class Configuration {
|
||||||
public CommandManager commands = new CommandManager();
|
public CommandManager commands = new CommandManager();
|
||||||
public CommandCore core = new CommandCore();
|
public CommandCore core = new CommandCore();
|
||||||
public Bots bots = new Bots();
|
public Bots bots = new Bots();
|
||||||
public CustomChat customChat = new CustomChat();
|
public CustomChat customChat = new CustomChat();
|
||||||
public boolean fullbright = false; // unused, but it is here for old configs
|
public String autoSkinUsername = "off";
|
||||||
public String autoSkinUsername = "off";
|
|
||||||
|
@ConfigSerializable
|
||||||
@ConfigSerializable
|
public static class CommandManager {
|
||||||
public static class CommandManager {
|
public String prefix = ".";
|
||||||
public String prefix = ".";
|
}
|
||||||
}
|
|
||||||
|
@ConfigSerializable
|
||||||
@ConfigSerializable
|
public static class CommandCore {
|
||||||
public static class CommandCore {
|
public BlockBox relativeArea = BlockBox.create(new BlockPos(0, 0, 0), new BlockPos(15, 0, 15));
|
||||||
public BlockBox relativeArea = BlockBox.create(new BlockPos(0, 0, 0), new BlockPos(15, 0, 15));
|
}
|
||||||
}
|
|
||||||
|
@ConfigSerializable
|
||||||
@ConfigSerializable
|
public static class Bots {
|
||||||
public static class Bots {
|
public BotInfo hbot = new BotInfo("#", null);
|
||||||
public BotInfo hbot = new BotInfo("#", null);
|
public BotInfo sbot = new BotInfo(":", null);
|
||||||
public BotInfo sbot = new BotInfo(":", null);
|
public BotInfo chipmunk = new BotInfo("'", null);
|
||||||
public BotInfo chipmunk = new BotInfo("'", null);
|
public ChomeNSBotInfo chomens = new ChomeNSBotInfo("*", null, null, null);
|
||||||
public ChomeNSBotInfo chomens = new ChomeNSBotInfo("*", null, null, null);
|
public BotInfo fnfboyfriend = new BotInfo("~", null);
|
||||||
public BotInfo fnfboyfriend = new BotInfo("~", null);
|
public BotInfo nbot = new BotInfo("?", null);
|
||||||
public BotInfo nbot = new BotInfo("?", null);
|
public BotInfo kittycorp = new BotInfo("^", null);
|
||||||
public BotInfo kittycorp = new BotInfo("^", null);
|
public TestBotInfo testbot = new TestBotInfo("-", null);
|
||||||
public TestBotInfo testbot = new TestBotInfo("-", null);
|
}
|
||||||
}
|
|
||||||
|
@ConfigSerializable
|
||||||
@ConfigSerializable
|
public static class ChomeNSBotInfo {
|
||||||
public static class ChomeNSBotInfo {
|
public String prefix;
|
||||||
public String prefix;
|
public @Nullable String key;
|
||||||
public @Nullable String key;
|
public @Nullable String authKey;
|
||||||
public @Nullable String authKey;
|
public @Nullable String formatKey;
|
||||||
public @Nullable String formatKey;
|
|
||||||
|
public ChomeNSBotInfo() {}
|
||||||
public ChomeNSBotInfo() {}
|
public ChomeNSBotInfo (String prefix, @Nullable String key, @Nullable String authKey, @Nullable String formatKey) {
|
||||||
public ChomeNSBotInfo (String prefix, @Nullable String key, @Nullable String authKey, @Nullable String formatKey) {
|
this.prefix = prefix;
|
||||||
this.prefix = prefix;
|
this.key = key;
|
||||||
this.key = key;
|
this.authKey = authKey;
|
||||||
this.authKey = authKey;
|
this.formatKey = formatKey;
|
||||||
this.formatKey = formatKey;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ConfigSerializable
|
||||||
@ConfigSerializable
|
public static class TestBotInfo {
|
||||||
public static class TestBotInfo {
|
public String prefix;
|
||||||
public String prefix;
|
public @Nullable String webhookUrl;
|
||||||
public @Nullable String webhookUrl;
|
|
||||||
|
public TestBotInfo() {}
|
||||||
public TestBotInfo() {}
|
public TestBotInfo (String prefix, @Nullable String webhookUrl) {
|
||||||
public TestBotInfo (String prefix, @Nullable String webhookUrl) {
|
this.prefix = prefix;
|
||||||
this.prefix = prefix;
|
this.webhookUrl = webhookUrl;
|
||||||
this.webhookUrl = webhookUrl;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ConfigSerializable
|
||||||
@ConfigSerializable
|
public static class BotInfo {
|
||||||
public static class BotInfo {
|
public String prefix;
|
||||||
public String prefix;
|
public @Nullable String key;
|
||||||
public @Nullable String key;
|
|
||||||
|
public BotInfo() {}
|
||||||
public BotInfo() {}
|
public BotInfo (String prefix, @Nullable String key) {
|
||||||
public BotInfo (String prefix, @Nullable String key) {
|
this.prefix = prefix;
|
||||||
this.prefix = prefix;
|
this.key = key;
|
||||||
this.key = key;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ConfigSerializable
|
||||||
@ConfigSerializable
|
public static class CustomChat {
|
||||||
public static class CustomChat {
|
public @NotNull Component format =
|
||||||
public @NotNull Component format =
|
Component.translatable("chat.type.text",
|
||||||
Component.translatable("chat.type.text",
|
Component.selector("UUID"),
|
||||||
Component.selector("UUID"),
|
Component.empty()
|
||||||
Component.empty()
|
.append(Component.text("MESSAGE"))
|
||||||
.append(Component.text("MESSAGE"))
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,7 @@ package land.chipmunk.chipmunkmod.util;
|
||||||
|
|
||||||
import com.mojang.brigadier.Command;
|
import com.mojang.brigadier.Command;
|
||||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||||
import land.chipmunk.chipmunkmod.Configuration;
|
import land.chipmunk.chipmunkmod.config.Configuration;
|
||||||
import land.chipmunk.chipmunkmod.commands.SayCommand;
|
|
||||||
import land.chipmunk.chipmunkmod.modules.Chat;
|
import land.chipmunk.chipmunkmod.modules.Chat;
|
||||||
import land.chipmunk.chipmunkmod.modules.CustomChat;
|
import land.chipmunk.chipmunkmod.modules.CustomChat;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue