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 06bff37e4c1fddd3be6343049a66787c63fb420c..2a4904b09b4b13e41c7aaa211c7eae6d48582b7a 100644 --- a/src/main/java/co/aikar/timings/TimingsExport.java +++ b/src/main/java/co/aikar/timings/TimingsExport.java @@ -241,7 +241,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(); @@ -282,7 +285,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/ConfigurationPart.java b/src/main/java/io/papermc/paper/configuration/ConfigurationPart.java index 7a4a7a654fe2516ed894a68f2657344df9d70f4c..82e6716c006492b9f24f148a918944b50231a158 100644 --- a/src/main/java/io/papermc/paper/configuration/ConfigurationPart.java +++ b/src/main/java/io/papermc/paper/configuration/ConfigurationPart.java @@ -1,6 +1,6 @@ package io.papermc.paper.configuration; -abstract class ConfigurationPart { +public abstract class ConfigurationPart { // Gale - Gale configuration public static abstract class Post extends ConfigurationPart { diff --git a/src/main/java/io/papermc/paper/configuration/Configurations.java b/src/main/java/io/papermc/paper/configuration/Configurations.java index c2dca89291361d60cbf160cab77749cb0130035a..cf6d50218769e3fecd12dbde70a03b5042feddf4 100644 --- a/src/main/java/io/papermc/paper/configuration/Configurations.java +++ b/src/main/java/io/papermc/paper/configuration/Configurations.java @@ -5,7 +5,10 @@ import io.leangen.geantyref.TypeToken; import io.papermc.paper.configuration.constraint.Constraint; import io.papermc.paper.configuration.constraint.Constraints; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; +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; @@ -88,7 +91,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); @@ -148,7 +151,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(WorldConfiguration.CURRENT_VERSION); + node.node(Configuration.VERSION_FIELD).raw(getWorldConfigurationCurrentVersion()); // Gale - Gale configuration } this.applyWorldConfigTransformations(contextMap, node); final W instance = node.require(this.worldConfigClass); @@ -207,7 +210,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(WorldConfiguration.CURRENT_VERSION); + worldNode.node(Configuration.VERSION_FIELD).set(getWorldConfigurationCurrentVersion()); // Gale - Gale configuration } this.applyWorldConfigTransformations(contextMap, worldNode); this.applyDefaultsAwareWorldConfigTransformations(contextMap, worldNode, defaultsNode); @@ -308,4 +311,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/InnerClassFieldDiscoverer.java b/src/main/java/io/papermc/paper/configuration/InnerClassFieldDiscoverer.java index a0aa1f1a7adf986d500a2135aa42e138aa3c4f08..6d19b985222d78750828fd2719c1fbf738e69a56 100644 --- a/src/main/java/io/papermc/paper/configuration/InnerClassFieldDiscoverer.java +++ b/src/main/java/io/papermc/paper/configuration/InnerClassFieldDiscoverer.java @@ -5,6 +5,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.configurate.objectmapping.FieldDiscoverer; import org.spongepowered.configurate.serialize.SerializationException; import org.spongepowered.configurate.util.CheckedSupplier; +import org.galemc.gale.configuration.GaleWorldConfiguration; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Constructor; @@ -17,7 +18,7 @@ import java.util.Map; import static io.leangen.geantyref.GenericTypeReflector.erase; -final class InnerClassFieldDiscoverer implements FieldDiscoverer> { +public final class InnerClassFieldDiscoverer implements FieldDiscoverer> { // Gale - Gale configuration private final Map, Object> instanceMap = new HashMap<>(); private final Map, Object> overrides; @@ -136,7 +137,19 @@ final class InnerClassFieldDiscoverer implements FieldDiscoverer 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/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java index 9fde9ccb5d069ddce8dd837ef1bc68b93ce66434..a82be9c7226348b6c8ed5edfa8dd8262b4f49f07 100644 --- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java @@ -127,13 +127,13 @@ public class PaperConfigurations extends Configurations SPIGOT_WORLD_DEFAULTS = Suppliers.memoize(() -> new SpigotWorldConfig(RandomStringUtils.randomAlphabetic(255)) { + public static final Supplier SPIGOT_WORLD_DEFAULTS = Suppliers.memoize(() -> new SpigotWorldConfig(RandomStringUtils.randomAlphabetic(255)) { // Gale - Gale configuration @Override // override to ensure "verbose" is false public void init() { SpigotConfig.readConfig(SpigotWorldConfig.class, this); } }); - static final ContextKey> SPIGOT_WORLD_CONFIG_CONTEXT_KEY = new ContextKey<>(new TypeToken>() {}, "spigot world config"); + public static final ContextKey> SPIGOT_WORLD_CONFIG_CONTEXT_KEY = new ContextKey<>(new TypeToken>() {}, "spigot world config"); // Gale - Gale configuration public PaperConfigurations(final Path globalFolder) { @@ -297,7 +297,7 @@ public class PaperConfigurations extends Configurations public public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, File userCacheFile, joptsimple.OptionSet optionSet) throws Exception { // Paper @@ -30,7 +36,10 @@ public record Services(MinecraftSessionService sessionService, SignatureValidato 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, signatureValidator, gameProfileRepository, gameProfileCache, paperConfigurations); + // Gale start - Gale configuration + GaleConfigurations galeConfigurations = GaleConfigurations.setup(configDirPath); + return new Services(minecraftSessionService, signatureValidator, gameProfileRepository, gameProfileCache, paperConfigurations, galeConfigurations); + // Gale end - Gale configuration // Paper end } } diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java index a7e133f3495e9132a5fdae2c24f225e7b026295a..b98fb8afdadbda47db5924299d90082edf3ca1b4 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -1,20 +1,15 @@ package net.minecraft.server.dedicated; -import com.google.common.collect.Lists; import com.mojang.authlib.GameProfile; import com.mojang.datafixers.DataFixer; import com.mojang.logging.LogUtils; -import java.io.BufferedReader; + import java.io.BufferedWriter; import java.io.IOException; -import java.io.InputStreamReader; import java.net.InetAddress; import java.net.Proxy; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Collections; -import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.function.BooleanSupplier; @@ -208,6 +203,10 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc. paperConfigurations.initializeGlobalConfiguration(); paperConfigurations.initializeWorldDefaultsConfiguration(); + // Gale start - Gale configuration + galeConfigurations.initializeGlobalConfiguration(); + galeConfigurations.initializeWorldDefaultsConfiguration(); + // Gale end - Gale configuration // Paper start - moved up to right after PlayerList creation but before file load/save if (this.convertOldUsers()) { this.getProfileCache().save(false); // Paper diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 5a5ff40df37db9cbd53c584ed26a3ce4888b29c0..512da79de8c9476c7289f4857c8bb966ff1a11c6 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -130,12 +130,10 @@ import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.dimension.BuiltinDimensionTypes; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.entity.EntityPersistentStorage; import net.minecraft.world.level.entity.EntityTickList; import net.minecraft.world.level.entity.EntityTypeTest; import net.minecraft.world.level.entity.LevelCallback; import net.minecraft.world.level.entity.LevelEntityGetter; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.gameevent.DynamicGameEventListener; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.GameEventDispatcher; @@ -527,7 +525,7 @@ public class ServerLevel extends Level implements WorldGenLevel { // 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)), executor); // Paper - 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)), spigotConfig -> minecraftserver.galeConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig)), executor); // Paper - 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 973ecd50f9cb6b86c353586e84d15dcb118ccb60..63122fb74a51547e23232a5409295369ee3aa353 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -1,10 +1,7 @@ package net.minecraft.world.level; -import co.aikar.timings.Timing; -import co.aikar.timings.Timings; import com.destroystokyo.paper.event.server.ServerExceptionEvent; import com.destroystokyo.paper.exception.ServerInternalException; -import com.google.common.base.MoreObjects; import com.google.common.collect.Lists; import com.mojang.serialization.Codec; import java.io.IOException; @@ -17,7 +14,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; @@ -44,8 +40,6 @@ import net.minecraft.world.DifficultyInstance; 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; @@ -91,17 +85,15 @@ import net.minecraft.network.protocol.game.ClientboundSetBorderSizePacket; import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDelayPacket; import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDistancePacket; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CapturedBlockState; import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.util.CraftSpawnCategory; -import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.SpawnCategory; import org.bukkit.event.block.BlockPhysicsEvent; -import org.bukkit.event.world.GenericGameEvent; +import org.galemc.gale.configuration.GaleWorldConfiguration; // CraftBukkit end public abstract class Level implements LevelAccessor, AutoCloseable { @@ -175,6 +167,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return this.paperConfig; } // Paper end + // 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 @@ -274,9 +272,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public abstract ResourceKey getTypeKey(); - 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 - Async-Anti-Xray - Pass executor + 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 - Async-Anti-Xray - Pass executor // 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 + 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 c5ead5947d0ede35060e25876df43aa488ab0121..670d66fb0bc64aab7473f92c25f69e91c1c0f226 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -956,6 +956,7 @@ public final class CraftServer implements Server { org.spigotmc.SpigotConfig.init((File) 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)) @@ -2744,6 +2745,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..9571aae593999d11b3908856b0295a7d6b588007 --- /dev/null +++ b/src/main/java/org/galemc/gale/configuration/GaleConfigurations.java @@ -0,0 +1,289 @@ +// 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.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.DoubleOrDefault; +import io.papermc.paper.configuration.type.Duration; +import io.papermc.paper.configuration.type.EngineMode; +import io.papermc.paper.configuration.type.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.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.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() throws ConfigurateException { + GaleGlobalConfiguration configuration = super.initializeGlobalConfiguration(); + GaleGlobalConfiguration.set(configuration); + return configuration; + } + + @Override + protected ContextMap.Builder createDefaultContextMap() { + return super.createDefaultContextMap() + .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) { + 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(DoubleOrDefault.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>() {}, Registries.ENTITY_TYPE, true)) + .register(new RegistryValueSerializer<>(Item.class, Registries.ITEM, true)) + .register(new RegistryHolderSerializer<>(new TypeToken>() {}, Registries.CONFIGURED_FEATURE, false)) + .register(new RegistryHolderSerializer<>(Item.class, Registries.ITEM, true)) + ) + ); + } + + @Override + protected void applyWorldConfigTransformations(final ContextMap contextMap, final ConfigurationNode node) 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(); + 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 + 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; + } + +}