From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martijn Muijsers Date: Wed, 23 Nov 2022 21:05:47 +0100 Subject: [PATCH] Gale configuration License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) Gale - https://galemc.org This patch is based on the following patch: "Paper config files" By: Jake Potrebic As part of: Paper (https://github.com/PaperMC/Paper) Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) diff --git a/src/main/java/io/papermc/paper/configuration/Configurations.java b/src/main/java/io/papermc/paper/configuration/Configurations.java index 8cf720f08514e8e4f62f4ad196f1277bd761c6b2..63afa5284028f3c423d19c2d5cb35b83c89050fd 100644 --- a/src/main/java/io/papermc/paper/configuration/Configurations.java +++ b/src/main/java/io/papermc/paper/configuration/Configurations.java @@ -94,7 +94,7 @@ public abstract class Configurations { }; } - static CheckedFunction reloader(Class type, T instance) { + public static CheckedFunction reloader(Class type, T instance) { // Gale - Gale configuration return node -> { ObjectMapper.Factory factory = (ObjectMapper.Factory) Objects.requireNonNull(node.options().serializers().get(type)); ObjectMapper.Mutable mutable = (ObjectMapper.Mutable) factory.get(type); @@ -168,7 +168,7 @@ public abstract class Configurations { final YamlConfigurationLoader loader = result.loader(); final ConfigurationNode node = loader.load(); if (result.isNewFile()) { // add version to new files - node.node(Configuration.VERSION_FIELD).raw(this.worldConfigVersion()); + node.node(Configuration.VERSION_FIELD).raw(getWorldConfigurationCurrentVersion()); // Gale - Gale configuration } else { this.verifyWorldConfigVersion(contextMap, node); } @@ -230,7 +230,7 @@ public abstract class Configurations { .build(); final ConfigurationNode worldNode = worldLoader.load(); if (newFile) { // set the version field if new file - worldNode.node(Configuration.VERSION_FIELD).set(this.worldConfigVersion()); + worldNode.node(Configuration.VERSION_FIELD).set(getWorldConfigurationCurrentVersion()); // Gale - Gale configuration } else { this.verifyWorldConfigVersion(contextMap, worldNode); } @@ -356,4 +356,25 @@ public abstract class Configurations { return "ContextKey{" + this.name + "}"; } } + + // Gale start - Gale configuration + + public static final String legacyWorldsSectionKey = "__________WORLDS__________"; + public static final String legacyWorldDefaultsSectionKey = "__defaults__"; + + @Deprecated + public org.bukkit.configuration.file.YamlConfiguration createLegacyObject(final net.minecraft.server.MinecraftServer server) { + org.bukkit.configuration.file.YamlConfiguration global = org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(this.globalFolder.resolve(this.globalConfigFileName).toFile()); + org.bukkit.configuration.ConfigurationSection worlds = global.createSection(legacyWorldsSectionKey); + worlds.set(legacyWorldDefaultsSectionKey, org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(this.globalFolder.resolve(this.defaultWorldConfigFileName).toFile())); + for (ServerLevel level : server.getAllLevels()) { + worlds.set(level.getWorld().getName(), org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(getWorldConfigFile(level).toFile())); + } + return global; + } + + public abstract int getWorldConfigurationCurrentVersion(); + + // Gale end - Gale configuration + } diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java index c5644d8d64f12073e39bc6ed79c8714f4560ff89..b993d3e2e9d987115129067e3a51060880453ee2 100644 --- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java @@ -326,7 +326,7 @@ public class PaperConfigurations extends Configurations globalConfig() { + // Gale start - Gale configuration + public static FieldDiscoverer galeWorldConfig(io.papermc.paper.configuration.Configurations.ContextMap contextMap) { + final Map, Object> overrides = Map.of( + org.galemc.gale.configuration.GaleWorldConfiguration.class, new org.galemc.gale.configuration.GaleWorldConfiguration( + contextMap.require(io.papermc.paper.configuration.PaperConfigurations.SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get(), + contextMap.require(io.papermc.paper.configuration.Configurations.WORLD_KEY) + ) + ); + return new InnerClassFieldDiscoverer(overrides); + } + // Gale end - Gale configuration + + public static FieldDiscoverer globalConfig() { // Gale - Gale configuration return new InnerClassFieldDiscoverer(Collections.emptyMap()); } } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index c26e3a239441376f2694782d4f07943538677c71..39e166379617630ca9cbad0f5dc4647d183a7570 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -327,6 +327,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop public public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, File userCacheFile, joptsimple.OptionSet optionSet) throws Exception { // Paper - add optionset to load paper config files; add userCacheFile parameter @@ -34,7 +39,10 @@ public record Services( final java.nio.file.Path legacyConfigPath = ((File) optionSet.valueOf("paper-settings")).toPath(); final java.nio.file.Path configDirPath = ((File) optionSet.valueOf("paper-settings-directory")).toPath(); io.papermc.paper.configuration.PaperConfigurations paperConfigurations = io.papermc.paper.configuration.PaperConfigurations.setup(legacyConfigPath, configDirPath, rootDirectory.toPath(), (File) optionSet.valueOf("spigot-settings")); - return new Services(minecraftSessionService, authenticationService.getServicesKeySet(), gameProfileRepository, gameProfileCache, paperConfigurations); + // Gale start - Gale configuration + org.galemc.gale.configuration.GaleConfigurations galeConfigurations = org.galemc.gale.configuration.GaleConfigurations.setup(configDirPath); + return new Services(minecraftSessionService, authenticationService.getServicesKeySet(), gameProfileRepository, gameProfileCache, paperConfigurations, galeConfigurations); + // Gale end - Gale configuration // Paper end - load paper config files from cli options } diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java index 17a158ff6ce6520b69a5a0032ba4c05449dd0cf8..9ce281e220089ea2a9218c25879f42aafa0a4011 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -223,6 +223,10 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess()); this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess()); // Paper end - initialize global and world-defaults configuration + // Gale start - Gale configuration + galeConfigurations.initializeGlobalConfiguration(this.registryAccess()); + galeConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess()); + // Gale end - Gale configuration this.server.spark.enableEarlyIfRequested(); // Paper - spark // Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save if (this.convertOldUsers()) { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index b4027f5cf90935a1fe3ab2c28b0bcbb55a7b541b..73bed8c899d146893e7e2f845b7bbf991d5d8a1f 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -597,7 +597,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Add env and gen to constructor, IWorldDataServer -> WorldDataServer public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { - super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig, minecraftserver.registryAccess(), iworlddataserver.getGameRules())), executor); // Paper - create paper world configs; Async-Anti-Xray: Pass executor + super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig, minecraftserver.registryAccess(), iworlddataserver.getGameRules())), spigotConfig -> minecraftserver.galeConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig, minecraftserver.registryAccess(), iworlddataserver.getGameRules())), executor); // Paper - create paper world configs; Async-Anti-Xray: Pass executor // Gale - Gale configuration this.pvpMode = minecraftserver.isPvpAllowed(); this.convertable = convertable_conversionsession; this.uuid = WorldUUID.getUUID(convertable_conversionsession.levelDirectory.path().toFile()); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 0de2b79481352b52438dde284262019b29949ad8..5ac5b21b5193cadeaa16250747be3b6685ca21ff 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -172,6 +172,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl return this.paperConfig; } // Paper end - add paper world config + // Gale start - Gale configuration + private final org.galemc.gale.configuration.GaleWorldConfiguration galeConfig; + public org.galemc.gale.configuration.GaleWorldConfiguration galeConfig() { + return this.galeConfig; + } + // Gale end - Gale configuration public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray public static BlockPos lastPhysicsProblem; // Spigot @@ -830,7 +836,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } // Paper end - optimise random ticking - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config & Anti-Xray + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.function.Function galeWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config & Anti-Xray // Gale - Gale configuration // Paper start - getblock optimisations - cache world height/sections final DimensionType dimType = holder.value(); this.minY = dimType.minY(); @@ -842,6 +848,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl // Paper end - getblock optimisations - cache world height/sections this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config + this.galeConfig = galeWorldConfigCreator.apply(this.spigotConfig); // Gale - Gale configuration this.generator = gen; this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index ac8af406180bc680d46e8edc3da0fc2e5211345a..269e3937b4ad1bdf04faa214245a2accbdc3a225 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1086,6 +1086,7 @@ public final class CraftServer implements Server { org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot this.console.paperConfigurations.reloadConfigs(this.console); + this.console.galeConfigurations.reloadConfigs(this.console); // Gale - Gale configuration for (ServerLevel world : this.console.getAllLevels()) { // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) @@ -3031,6 +3032,14 @@ public final class CraftServer implements Server { return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console); } + // Gale start - Gale configuration - API + @Override + public YamlConfiguration getGaleConfig() + { + return CraftServer.this.console.galeConfigurations.createLegacyObject(CraftServer.this.console); + } + // Gale end - Gale configuration - API + @Override public void restart() { org.spigotmc.RestartCommand.restart(); diff --git a/src/main/java/org/galemc/gale/configuration/GaleConfigurations.java b/src/main/java/org/galemc/gale/configuration/GaleConfigurations.java new file mode 100644 index 0000000000000000000000000000000000000000..de25d0b4001363e63873af8f0f2165e5449786df --- /dev/null +++ b/src/main/java/org/galemc/gale/configuration/GaleConfigurations.java @@ -0,0 +1,304 @@ +// Gale - Gale configuration + +package org.galemc.gale.configuration; + +import com.google.common.collect.Table; +import com.mojang.logging.LogUtils; +import io.leangen.geantyref.TypeToken; +import io.papermc.paper.configuration.Configuration; +import io.papermc.paper.configuration.ConfigurationPart; +import io.papermc.paper.configuration.Configurations; +import io.papermc.paper.configuration.GlobalConfiguration; +import io.papermc.paper.configuration.WorldConfiguration; +import io.papermc.paper.configuration.mapping.InnerClassFieldDiscoverer; +import io.papermc.paper.configuration.NestedSetting; +import io.papermc.paper.configuration.PaperConfigurations; +import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization; +import io.papermc.paper.configuration.serializer.ComponentSerializer; +import io.papermc.paper.configuration.serializer.EnumValueSerializer; +import io.papermc.paper.configuration.serializer.collections.FastutilMapSerializer; +import io.papermc.paper.configuration.serializer.PacketClassSerializer; +import io.papermc.paper.configuration.serializer.StringRepresentableSerializer; +import io.papermc.paper.configuration.serializer.collections.TableSerializer; +import io.papermc.paper.configuration.serializer.collections.MapSerializer; +import io.papermc.paper.configuration.serializer.registry.RegistryHolderSerializer; +import io.papermc.paper.configuration.serializer.registry.RegistryValueSerializer; +import io.papermc.paper.configuration.transformation.Transformations; +import io.papermc.paper.configuration.type.BooleanOrDefault; +import io.papermc.paper.configuration.type.number.DoubleOr; +import io.papermc.paper.configuration.type.Duration; +import io.papermc.paper.configuration.type.EngineMode; +import io.papermc.paper.configuration.type.number.IntOr; +import io.papermc.paper.configuration.type.fallback.FallbackValueSerializer; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Reference2LongMap; +import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationOptions; +import org.spongepowered.configurate.NodePath; +import org.spongepowered.configurate.objectmapping.ObjectMapper; +import org.spongepowered.configurate.transformation.ConfigurationTransformation; +import org.spongepowered.configurate.transformation.TransformAction; +import org.spongepowered.configurate.yaml.YamlConfigurationLoader; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +import static io.leangen.geantyref.GenericTypeReflector.erase; + +@SuppressWarnings("Convert2Diamond") +public class GaleConfigurations extends Configurations { + + private static final Logger LOGGER = LogUtils.getLogger(); + static final String GLOBAL_CONFIG_FILE_NAME = "gale-global.yml"; + static final String WORLD_DEFAULTS_CONFIG_FILE_NAME = "gale-world-defaults.yml"; + static final String WORLD_CONFIG_FILE_NAME = "gale-world.yml"; + public static final String CONFIG_DIR = "config"; + + private static final String GLOBAL_HEADER = String.format(""" + This is the global configuration file for Gale. + As you can see, there's a lot to configure. Some options may impact gameplay, so use + with caution, and make sure you know what each option does before configuring. + + If you need help with the configuration or have any questions related to Gale, + join us in our Discord, or check the GitHub Wiki pages. + + The world configuration options are inside + their respective world folder. The files are named %s + + Wiki: https://github.com/GaleMC/Gale/wiki + Discord: https://discord.gg/gwezNT8c24""", WORLD_CONFIG_FILE_NAME); + + private static final String WORLD_DEFAULTS_HEADER = """ + This is the world defaults configuration file for Gale. + As you can see, there's a lot to configure. Some options may impact gameplay, so use + with caution, and make sure you know what each option does before configuring. + + If you need help with the configuration or have any questions related to Gale, + join us in our Discord, or check the GitHub Wiki pages. + + Configuration options here apply to all worlds, unless you specify overrides inside + the world-specific config file inside each world folder. + + Wiki: https://github.com/GaleMC/Gale/wiki + Discord: https://discord.gg/gwezNT8c24"""; + + private static final Function WORLD_HEADER = map -> String.format(""" + This is a world configuration file for Gale. + This file may start empty but can be filled with settings to override ones in the %s/%s + + World: %s (%s)""", + CONFIG_DIR, + WORLD_DEFAULTS_CONFIG_FILE_NAME, + map.require(WORLD_NAME), + map.require(WORLD_KEY) + ); + + private static final String MOVED_NOTICE = """ + The global and world default configuration files have moved to %s + and the world-specific configuration file has been moved inside + the respective world folder. + + See https://github.com/GaleMC/Gale/wiki for more information. + """; + + public GaleConfigurations(final Path globalFolder) { + super(globalFolder, GaleGlobalConfiguration.class, GaleWorldConfiguration.class, GLOBAL_CONFIG_FILE_NAME, WORLD_DEFAULTS_CONFIG_FILE_NAME, WORLD_CONFIG_FILE_NAME); + } + + @Override + protected YamlConfigurationLoader.Builder createLoaderBuilder() { + return super.createLoaderBuilder() + .defaultOptions(GaleConfigurations::defaultOptions); + } + + private static ConfigurationOptions defaultOptions(ConfigurationOptions options) { + return options.serializers(builder -> builder + .register(MapSerializer.TYPE, new MapSerializer(false)) + .register(new EnumValueSerializer()) + .register(new ComponentSerializer()) + ); + } + + @Override + protected ObjectMapper.Factory.Builder createGlobalObjectMapperFactoryBuilder() { + return defaultGlobalFactoryBuilder(super.createGlobalObjectMapperFactoryBuilder()); + } + + private static ObjectMapper.Factory.Builder defaultGlobalFactoryBuilder(ObjectMapper.Factory.Builder builder) { + return builder.addDiscoverer(InnerClassFieldDiscoverer.globalConfig()); + } + + @Override + protected YamlConfigurationLoader.Builder createGlobalLoaderBuilder() { + return super.createGlobalLoaderBuilder() + .defaultOptions(GaleConfigurations::defaultGlobalOptions); + } + + private static ConfigurationOptions defaultGlobalOptions(ConfigurationOptions options) { + return options + .header(GLOBAL_HEADER) + .serializers(builder -> builder.register(new PacketClassSerializer())); + } + + @Override + public GaleGlobalConfiguration initializeGlobalConfiguration(final RegistryAccess registryAccess) throws ConfigurateException { + GaleGlobalConfiguration configuration = super.initializeGlobalConfiguration(registryAccess); + GaleGlobalConfiguration.set(configuration); + return configuration; + } + + @Override + protected ContextMap.Builder createDefaultContextMap(final RegistryAccess registryAccess) { + return super.createDefaultContextMap(registryAccess) + .put(PaperConfigurations.SPIGOT_WORLD_CONFIG_CONTEXT_KEY, PaperConfigurations.SPIGOT_WORLD_DEFAULTS); + } + + @Override + protected ObjectMapper.Factory.Builder createWorldObjectMapperFactoryBuilder(final ContextMap contextMap) { + return super.createWorldObjectMapperFactoryBuilder(contextMap) + .addNodeResolver(new RequiresSpigotInitialization.Factory(contextMap.require(PaperConfigurations.SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get())) + .addNodeResolver(new NestedSetting.Factory()) + .addDiscoverer(InnerClassFieldDiscoverer.galeWorldConfig(contextMap)); + } + + @Override + protected YamlConfigurationLoader.Builder createWorldConfigLoaderBuilder(final ContextMap contextMap) { + final RegistryAccess access = contextMap.require(REGISTRY_ACCESS); + return super.createWorldConfigLoaderBuilder(contextMap) + .defaultOptions(options -> options + .header(contextMap.require(WORLD_NAME).equals(WORLD_DEFAULTS) ? WORLD_DEFAULTS_HEADER : WORLD_HEADER.apply(contextMap)) + .serializers(serializers -> serializers + .register(new TypeToken>() {}, new FastutilMapSerializer.SomethingToPrimitive>(Reference2IntOpenHashMap::new, Integer.TYPE)) + .register(new TypeToken>() {}, new FastutilMapSerializer.SomethingToPrimitive>(Reference2LongOpenHashMap::new, Long.TYPE)) + .register(new TypeToken>() {}, new TableSerializer()) + .register(new StringRepresentableSerializer()) + .register(IntOr.Default.SERIALIZER) + .register(IntOr.Disabled.SERIALIZER) + .register(DoubleOr.Default.SERIALIZER) + .register(BooleanOrDefault.SERIALIZER) + .register(Duration.SERIALIZER) + .register(EngineMode.SERIALIZER) + .register(FallbackValueSerializer.create(contextMap.require(PaperConfigurations.SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get(), MinecraftServer::getServer)) + .register(new RegistryValueSerializer<>(new TypeToken>() {}, access, Registries.ENTITY_TYPE, true)) + .register(new RegistryValueSerializer<>(Item.class, access, Registries.ITEM, true)) + .register(new RegistryHolderSerializer<>(new TypeToken>() {}, access, Registries.CONFIGURED_FEATURE, false)) + .register(new RegistryHolderSerializer<>(Item.class, access, Registries.ITEM, true)) + ) + ); + } + + @Override + protected void applyWorldConfigTransformations(final ContextMap contextMap, final ConfigurationNode node, final @Nullable ConfigurationNode defaultsNode) throws ConfigurateException { + final ConfigurationNode version = node.node(Configuration.VERSION_FIELD); + final String world = contextMap.require(WORLD_NAME); + if (version.virtual()) { + LOGGER.warn("The Gale world config file for " + world + " didn't have a version set, assuming latest"); + version.raw(GaleWorldConfiguration.CURRENT_VERSION); + } + if (GaleRemovedConfigurations.REMOVED_WORLD_PATHS.length > 0) { + ConfigurationTransformation.Builder builder = ConfigurationTransformation.builder(); + for (NodePath path : GaleRemovedConfigurations.REMOVED_WORLD_PATHS) { + builder.addAction(path, TransformAction.remove()); + } + builder.build().apply(node); + } + // ADD FUTURE TRANSFORMS HERE + } + + @Override + protected void applyGlobalConfigTransformations(ConfigurationNode node) throws ConfigurateException { + if (GaleRemovedConfigurations.REMOVED_GLOBAL_PATHS.length > 0) { + ConfigurationTransformation.Builder builder = ConfigurationTransformation.builder(); + for (NodePath path : GaleRemovedConfigurations.REMOVED_GLOBAL_PATHS) { + builder.addAction(path, TransformAction.remove()); + } + builder.build().apply(node); + } + // ADD FUTURE TRANSFORMS HERE + } + + private static final List DEFAULT_AWARE_TRANSFORMATIONS = Collections.emptyList(); + + @Override + protected void applyDefaultsAwareWorldConfigTransformations(final ContextMap contextMap, final ConfigurationNode worldNode, final ConfigurationNode defaultsNode) throws ConfigurateException { + final ConfigurationTransformation.Builder builder = ConfigurationTransformation.builder(); + // ADD FUTURE TRANSFORMS HERE (these transforms run after the defaults have been merged into the node) + DEFAULT_AWARE_TRANSFORMATIONS.forEach(transform -> transform.apply(builder, contextMap, defaultsNode)); + + ConfigurationTransformation transformation; + try { + transformation = builder.build(); // build throws IAE if no actions were provided (bad zml) + } catch (IllegalArgumentException ignored) { + return; + } + transformation.apply(worldNode); + } + + @Override + public GaleWorldConfiguration createWorldConfig(final ContextMap contextMap) { + final String levelName = contextMap.require(WORLD_NAME); + try { + return super.createWorldConfig(contextMap); + } catch (IOException exception) { + throw new RuntimeException("Could not create Gale world config for " + levelName, exception); + } + } + + @Override + protected boolean isConfigType(final Type type) { + return ConfigurationPart.class.isAssignableFrom(erase(type)); + } + + public void reloadConfigs(MinecraftServer server) { + try { + this.initializeGlobalConfiguration(reloader(this.globalConfigClass, GaleGlobalConfiguration.get())); + this.initializeWorldDefaultsConfiguration(server.registryAccess()); + for (ServerLevel level : server.getAllLevels()) { + this.createWorldConfig(PaperConfigurations.createWorldContextMap(level), reloader(this.worldConfigClass, level.galeConfig())); + } + } catch (Exception ex) { + throw new RuntimeException("Could not reload Gale configuration files", ex); + } + } + + public static GaleConfigurations setup(final Path configDir) throws Exception { + try { + PaperConfigurations.createDirectoriesSymlinkAware(configDir); + return new GaleConfigurations(configDir); + } catch (final IOException ex) { + throw new RuntimeException("Could not setup GaleConfigurations", ex); + } + } + + @Override + protected int globalConfigVersion() { + return GaleGlobalConfiguration.CURRENT_VERSION; + } + + @Override + protected int worldConfigVersion() { + return getWorldConfigurationCurrentVersion(); + } + + @Override + public int getWorldConfigurationCurrentVersion() { + return GaleWorldConfiguration.CURRENT_VERSION; + } + +} diff --git a/src/main/java/org/galemc/gale/configuration/GaleGlobalConfiguration.java b/src/main/java/org/galemc/gale/configuration/GaleGlobalConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..8f8fd98f96cd390ba43033521982a13044df91cf --- /dev/null +++ b/src/main/java/org/galemc/gale/configuration/GaleGlobalConfiguration.java @@ -0,0 +1,30 @@ +// Gale - Gale configuration + +package org.galemc.gale.configuration; + +import io.papermc.paper.configuration.Configuration; +import io.papermc.paper.configuration.ConfigurationPart; +import org.spongepowered.configurate.objectmapping.meta.Setting; + +@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic"}) +public class GaleGlobalConfiguration extends ConfigurationPart { + static final int CURRENT_VERSION = 1; + private static GaleGlobalConfiguration instance; + public static GaleGlobalConfiguration get() { + return instance; + } + static void set(GaleGlobalConfiguration instance) { + GaleGlobalConfiguration.instance = instance; + } + + @Setting(Configuration.VERSION_FIELD) + public int version = CURRENT_VERSION; + + public SmallOptimizations smallOptimizations; + public class SmallOptimizations extends ConfigurationPart { + + public int dummyValue = 0; + + } + +} diff --git a/src/main/java/org/galemc/gale/configuration/GaleRemovedConfigurations.java b/src/main/java/org/galemc/gale/configuration/GaleRemovedConfigurations.java new file mode 100644 index 0000000000000000000000000000000000000000..9db322100dacbf2343fbb86e3e83d99febfa9d9d --- /dev/null +++ b/src/main/java/org/galemc/gale/configuration/GaleRemovedConfigurations.java @@ -0,0 +1,13 @@ +// Gale - Gale configuration + +package org.galemc.gale.configuration; + +import org.spongepowered.configurate.NodePath; + +interface GaleRemovedConfigurations { + + NodePath[] REMOVED_WORLD_PATHS = {}; + + NodePath[] REMOVED_GLOBAL_PATHS = {}; + +} diff --git a/src/main/java/org/galemc/gale/configuration/GaleWorldConfiguration.java b/src/main/java/org/galemc/gale/configuration/GaleWorldConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..b82bb95b524c95cdefb81abef906eded0717e9a1 --- /dev/null +++ b/src/main/java/org/galemc/gale/configuration/GaleWorldConfiguration.java @@ -0,0 +1,40 @@ +// Gale - Gale configuration + +package org.galemc.gale.configuration; + +import com.mojang.logging.LogUtils; +import io.papermc.paper.configuration.Configuration; +import io.papermc.paper.configuration.ConfigurationPart; +import io.papermc.paper.configuration.PaperConfigurations; +import net.minecraft.resources.ResourceLocation; +import org.slf4j.Logger; +import org.spigotmc.SpigotWorldConfig; +import org.spongepowered.configurate.objectmapping.meta.Setting; + +@SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic"}) +public class GaleWorldConfiguration extends ConfigurationPart { + private static final Logger LOGGER = LogUtils.getLogger(); + public static final int CURRENT_VERSION = 1; + + private transient final SpigotWorldConfig spigotConfig; + private transient final ResourceLocation worldKey; + public GaleWorldConfiguration(SpigotWorldConfig spigotConfig, ResourceLocation worldKey) { + this.spigotConfig = spigotConfig; + this.worldKey = worldKey; + } + + public boolean isDefault() { + return this.worldKey.equals(PaperConfigurations.WORLD_DEFAULTS_KEY); + } + + @Setting(Configuration.VERSION_FIELD) + public int version = CURRENT_VERSION; + + public SmallOptimizations smallOptimizations; + public class SmallOptimizations extends ConfigurationPart { + + public int dummyValue = 0; + + } + +}