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/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java index 7620c72a4c243cbeea245203ce03a97cbfa7d922..29796a404e210f7864f4b33b3367e02531bca2a0 100644 --- a/src/main/java/co/aikar/timings/TimingsExport.java +++ b/src/main/java/co/aikar/timings/TimingsExport.java @@ -240,7 +240,10 @@ public class TimingsExport extends Thread { parent.put("config", createObject( pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), - pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)) + // Gale start - Gale configuration - include in timings + pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), + pair("gale", mapAsJSON(Bukkit.spigot().getGaleConfig(), null)) + // Gale end - Gale configuration - include in timings )); new TimingsExport(listeners, parent, history).start(); @@ -281,7 +284,7 @@ public class TimingsExport extends Thread { return timingsCost; } - private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) { + public static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) { // Gale - Gale configuration JSONObject object = new JSONObject(); for (String key : config.getKeys(false)) { diff --git a/src/main/java/io/papermc/paper/configuration/Configurations.java b/src/main/java/io/papermc/paper/configuration/Configurations.java index 87e5f614ba988547a827486740db217e28585773..38d99d73a33911afa71d02a456bb4df62ce75166 100644 --- a/src/main/java/io/papermc/paper/configuration/Configurations.java +++ b/src/main/java/io/papermc/paper/configuration/Configurations.java @@ -7,8 +7,11 @@ import io.papermc.paper.configuration.constraint.Constraint; import io.papermc.paper.configuration.constraint.Constraints; import net.minecraft.core.RegistryAccess; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.GameRules; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; import org.checkerframework.checker.nullness.qual.Nullable; import org.jetbrains.annotations.MustBeInvokedByOverriders; import org.slf4j.Logger; @@ -96,7 +99,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); @@ -170,7 +173,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); } @@ -232,7 +235,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); } @@ -358,4 +361,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 YamlConfiguration createLegacyObject(final MinecraftServer server) { + YamlConfiguration global = YamlConfiguration.loadConfiguration(this.globalFolder.resolve(this.globalConfigFileName).toFile()); + ConfigurationSection worlds = global.createSection(legacyWorldsSectionKey); + worlds.set(legacyWorldDefaultsSectionKey, YamlConfiguration.loadConfiguration(this.globalFolder.resolve(this.defaultWorldConfigFileName).toFile())); + for (ServerLevel level : server.getAllLevels()) { + worlds.set(level.getWorld().getName(), 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 1029b6de6f36b08bf634b4056ef5701383f6f258..1dd9531ffa272b8248f78a9ec029edcd15339b5a 100644 --- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java @@ -323,7 +323,7 @@ public class PaperConfigurations extends Configurations globalConfig() { + // Gale start - Gale configuration + public static FieldDiscoverer galeWorldConfig(Configurations.ContextMap contextMap) { + final Map, Object> overrides = Map.of( + GaleWorldConfiguration.class, new GaleWorldConfiguration( + contextMap.require(PaperConfigurations.SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get(), + contextMap.require(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 696d075ca2883f3c37e35f983c4d020e5db89d16..1840332f79c5cfc2a913d80d9885939be92f87d6 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -3,9 +3,6 @@ package net.minecraft.server; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; -import co.aikar.timings.Timings; -import com.destroystokyo.paper.event.server.PaperServerListPingEvent; -import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -149,6 +146,9 @@ import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; import net.minecraft.world.level.storage.WorldData; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; +import org.galemc.gale.configuration.GaleConfigurations; import org.slf4j.Logger; // CraftBukkit start @@ -317,6 +317,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 +40,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 + GaleConfigurations galeConfigurations = 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 dd56c8e041116ef3602a9f89c998c8208ab89b51..86c615518e315dd4425d17df163e88a150a4ef7c 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -226,6 +226,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 f9abf63e12ea930275121b470e4e4906cff0fc12..e20b7a1ad141834a10c5f23f9b27cc41fa25ac0d 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -503,7 +503,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. // Holder holder = worlddimension.type(); // CraftBukkit - decompile error // Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error - super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), minecraftserver::getProfiler, 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(), minecraftserver::getProfiler, 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 507671476c3d2d92a2fdb05be24443af27d26dcf..32cd737206dd9f2bcfdacfe17dc0621ee34b589a 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -12,7 +12,6 @@ import java.util.function.Supplier; import javax.annotation.Nullable; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; -import net.minecraft.ReportedException; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; @@ -42,8 +41,6 @@ import net.minecraft.world.TickRateManager; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSources; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.boss.EnderDragonPart; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; @@ -101,6 +98,7 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.util.CraftSpawnCategory; import org.bukkit.entity.SpawnCategory; import org.bukkit.event.block.BlockPhysicsEvent; +import org.galemc.gale.configuration.GaleWorldConfiguration; // CraftBukkit end public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel, ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter, ca.spottedleaf.moonrise.patches.collisions.world.CollisionLevel { // Paper - rewrite chunk system // Paper - optimise collisions @@ -171,6 +169,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 GaleWorldConfiguration galeConfig; + public GaleWorldConfiguration galeConfig() { + return this.galeConfig; + } + // Gale end - Gale configuration public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray public final co.aikar.timings.WorldTimingsHandler timings; // Paper @@ -684,9 +688,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } // Paper end - optimise random ticking - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, 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, Supplier supplier, 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 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 c7df339aeb62ee627edaf1bb4c8474b61e357ba6..b1c1e600100ac31ecb20473b8ad2853676dff84a 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1072,6 +1072,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, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) @@ -2990,6 +2991,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; + + } + +} diff --git a/src/main/java/org/galemc/gale/configuration/timingsexport/GaleConfigurationTimingsExport.java b/src/main/java/org/galemc/gale/configuration/timingsexport/GaleConfigurationTimingsExport.java new file mode 100644 index 0000000000000000000000000000000000000000..579c2e69d8f6ce8398eb1297d1d1ead98c9068a5 --- /dev/null +++ b/src/main/java/org/galemc/gale/configuration/timingsexport/GaleConfigurationTimingsExport.java @@ -0,0 +1,19 @@ +// Gale - Gale configuration + +package org.galemc.gale.configuration.timingsexport; + +import co.aikar.timings.TimingsExport; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; +import org.json.simple.JSONObject; + +public final class GaleConfigurationTimingsExport { + + private GaleConfigurationTimingsExport() {} + + public static @NotNull JSONObject get() { + var json = TimingsExport.mapAsJSON(Bukkit.spigot().getGaleConfig(), null); + return json; + } + +}