From 883f3348644fb9fba80ce81dce757482c71f92a2 Mon Sep 17 00:00:00 2001 From: AlphaKR93 Date: Wed, 19 Feb 2025 21:07:18 +0900 Subject: [PATCH] Fix NPE on startup --- .../papermc/paper/ServerBuildInfo.java.patch | 17 + .../main/java/org/bukkit/Server.java.patch | 44 + .../defaults/VersionCommand.java.patch | 110 ++ .../server/MinecraftServer.java.patch | 697 +++++++++++- .../net/minecraft/server/Services.java.patch | 62 ++ .../dedicated/DedicatedServer.java.patch | 59 +- .../server/level/ServerLevel.java.patch | 989 ++++++++++++++++++ .../minecraft/world/entity/Entity.java.patch | 11 + .../minecraft/world/level/Level.java.patch | 43 +- .../paper/PaperVersionFetcher.java.patch | 18 +- .../configuration/Configuration.java.patch | 20 + .../configuration/Configurations.java.patch | 385 +++++++ .../PaperConfigurations.java.patch | 415 ++++++++ .../InnerClassFieldDiscoverer.java.patch | 16 + .../bukkit/craftbukkit/CraftServer.java.patch | 24 + .../org/bukkit/craftbukkit/Main.java.patch | 46 +- plazma-server/src/main/resources/icon.png | Bin 0 -> 7439 bytes 17 files changed, 2948 insertions(+), 8 deletions(-) create mode 100644 plazma-api/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfo.java.patch create mode 100644 plazma-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch create mode 100644 plazma-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch create mode 100644 plazma-server/minecraft-patches/sources/net/minecraft/server/Services.java.patch create mode 100644 plazma-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch create mode 100644 plazma-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch create mode 100644 plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/Configuration.java.patch create mode 100644 plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/Configurations.java.patch create mode 100644 plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java.patch create mode 100644 plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java.patch create mode 100644 plazma-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch create mode 100644 plazma-server/src/main/resources/icon.png diff --git a/plazma-api/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfo.java.patch b/plazma-api/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfo.java.patch new file mode 100644 index 0000000..fc20a5e --- /dev/null +++ b/plazma-api/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfo.java.patch @@ -0,0 +1,17 @@ +--- a/src/main/java/io/papermc/paper/ServerBuildInfo.java ++++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java +@@ -25,6 +_,14 @@ + */ + Key BRAND_PURPUR_ID = Key.key("purpurmc", "purpur"); + // Purpur end ++ ++ // Plazma start ++ /** ++ * The brand id for Plazma. ++ */ ++ Key BRAND_PLAZMA_ID = Key.key("plazmamc", "plazma"); ++ // Plazma end ++ + /** + * Gets the {@code ServerBuildInfo}. + * diff --git a/plazma-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch b/plazma-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch new file mode 100644 index 0000000..4be992b --- /dev/null +++ b/plazma-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch @@ -0,0 +1,44 @@ +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2309,6 +_,11 @@ + // Spigot start + public class Spigot { + ++ /** ++ * @deprecated Use {@link #getSpigotConfig()} instead. ++ * @return The spigot configuration ++ */ ++ @Deprecated(since = "Plazma 1.21.4") + @NotNull + public org.bukkit.configuration.file.YamlConfiguration getConfig() { + throw new UnsupportedOperationException("Not supported yet."); +@@ -2334,17 +_,27 @@ + } + // Paper end + ++ // Plazma start + // Purpur start + @NotNull +- public org.bukkit.configuration.file.YamlConfiguration getPurpurConfig() { ++ public org.bukkit.configuration.file.YamlConfiguration getPurpurConfig() ++ { + throw new UnsupportedOperationException("Not supported yet."); + } + + @NotNull +- public java.util.Properties getServerProperties() { ++ public java.util.Properties getServerProperties() ++ { + throw new UnsupportedOperationException("Not supported yet."); + } + // Purpur end ++ ++ @NotNull ++ public org.bukkit.configuration.file.YamlConfiguration getPlazmaConfig() ++ { ++ throw new UnsupportedOperationException("Not supported yet."); ++ } ++ // Plazma end + + /** + * Sends the component to the player diff --git a/plazma-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch b/plazma-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch new file mode 100644 index 0000000..4916baf --- /dev/null +++ b/plazma-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch @@ -0,0 +1,110 @@ +--- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java ++++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java +@@ -64,7 +_,7 @@ + StringBuilder name = new StringBuilder(); + + for (String arg : args) { +- if (name.length() > 0) { ++ if (!name.isEmpty()) { // Plazma + name.append(' '); + } + +@@ -96,7 +_,7 @@ + } + + private void describeToSender(@NotNull Plugin plugin, @NotNull CommandSender sender) { +- PluginDescriptionFile desc = plugin.getDescription(); ++ io.papermc.paper.plugin.configuration.PluginMeta desc = plugin.getPluginMeta(); // Plazma - Use modern method + // Paper start - version command 2.0 + sender.sendMessage( + Component.text() +@@ -198,13 +_,7 @@ + sender.sendMessage(Component.text("Checking version, please wait...", NamedTextColor.WHITE, TextDecoration.ITALIC)); // Paper + if (!versionTaskStarted) { + versionTaskStarted = true; +- new Thread(new Runnable() { +- +- @Override +- public void run() { +- obtainVersion(); +- } +- }).start(); ++ new Thread(this::obtainVersion).start(); // Plazma + } + } finally { + versionLock.unlock(); +@@ -219,37 +_,6 @@ + return; + } + setVersionMessage(getVersionFetcher().getVersionMessage(version)); +- /* +- if (version == null) version = "Custom"; +- String[] parts = version.substring(0, version.indexOf(' ')).split("-"); +- if (parts.length == 4) { +- int cbVersions = getDistance("craftbukkit", parts[3]); +- int spigotVersions = getDistance("spigot", parts[2]); +- if (cbVersions == -1 || spigotVersions == -1) { +- setVersionMessage("Error obtaining version information"); +- } else { +- if (cbVersions == 0 && spigotVersions == 0) { +- setVersionMessage("You are running the latest version"); +- } else { +- setVersionMessage("You are " + (cbVersions + spigotVersions) + " version(s) behind"); +- } +- } +- +- } else if (parts.length == 3) { +- int cbVersions = getDistance("craftbukkit", parts[2]); +- if (cbVersions == -1) { +- setVersionMessage("Error obtaining version information"); +- } else { +- if (cbVersions == 0) { +- setVersionMessage("You are running the latest version"); +- } else { +- setVersionMessage("You are " + cbVersions + " version(s) behind"); +- } +- } +- } else { +- setVersionMessage("Unknown version, custom build?"); +- } +- */ + // Paper end + } + +@@ -259,7 +_,7 @@ + // Purpur start + int distance = getVersionFetcher().distance(); + final Component message = Component.join(net.kyori.adventure.text.JoinConfiguration.separator(Component.newline()), +- ChatColor.parseMM("Current Purpur Version: %s%s*", distance == 0 ? "" : distance > 0 ? "" : "", Bukkit.getVersion()), ++ net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize("Current Plazma Version: " + (distance == 0 ? "" : distance > 0 ? "" : "") + Bukkit.getVersion() + "*"), // Plazma + // Purpur end + msg + ); +@@ -279,27 +_,6 @@ + versionWaiters.clear(); + } finally { + versionLock.unlock(); +- } +- } +- +- private static int getDistance(@NotNull String repo, @NotNull String hash) { +- try { +- BufferedReader reader = Resources.asCharSource( +- new URL("https://hub.spigotmc.org/stash/rest/api/1.0/projects/SPIGOT/repos/" + repo + "/commits?since=" + URLEncoder.encode(hash, "UTF-8") + "&withCounts=true"), +- Charsets.UTF_8 +- ).openBufferedStream(); +- try { +- JsonObject obj = new Gson().fromJson(reader, JsonObject.class); +- return obj.get("totalCount").getAsInt(); +- } catch (JsonSyntaxException ex) { +- ex.printStackTrace(); +- return -1; +- } finally { +- reader.close(); +- } +- } catch (IOException e) { +- e.printStackTrace(); +- return -1; + } + } + } diff --git a/plazma-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch b/plazma-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch index faeae90..d1d1532 100644 --- a/plazma-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/plazma-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -1,6 +1,530 @@ --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1777,7 +_,7 @@ +@@ -18,6 +_,7 @@ + import it.unimi.dsi.fastutil.objects.ObjectArraySet; + import java.awt.image.BufferedImage; + import java.io.ByteArrayOutputStream; ++import java.io.File; + import java.io.IOException; + import java.io.Writer; + import java.lang.management.ManagementFactory; +@@ -174,24 +_,26 @@ + import org.slf4j.Logger; + + public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource, ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer { // Paper - rewrite chunk system ++ @Nullable // Plazma - Null safety + private static MinecraftServer SERVER; // Paper + public static final Logger LOGGER = LogUtils.getLogger(); + public static final net.kyori.adventure.text.logger.slf4j.ComponentLogger COMPONENT_LOGGER = net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(LOGGER.getName()); // Paper +- public static final String VANILLA_BRAND = "vanilla"; +- private static final float AVERAGE_TICK_TIME_SMOOTHING = 0.8F; +- private static final int TICK_STATS_SPAN = 100; ++ // public static final String VANILLA_BRAND = "vanilla"; ++ // private static final float AVERAGE_TICK_TIME_SMOOTHING = 0.8F; ++ // private static final int TICK_STATS_SPAN = 100; + private static final long OVERLOADED_THRESHOLD_NANOS = 30L * TimeUtil.NANOSECONDS_PER_SECOND / 20L; // CraftBukkit +- private static final int OVERLOADED_TICKS_THRESHOLD = 20; ++ // private static final int OVERLOADED_TICKS_THRESHOLD = 20; + private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeUtil.NANOSECONDS_PER_SECOND; +- private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100; ++ // private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100; + private static final long STATUS_EXPIRE_TIME_NANOS = 5L * TimeUtil.NANOSECONDS_PER_SECOND; +- private static final long PREPARE_LEVELS_DEFAULT_DELAY_NANOS = 10L * TimeUtil.NANOSECONDS_PER_MILLISECOND; +- private static final int MAX_STATUS_PLAYER_SAMPLE = 12; +- private static final int SPAWN_POSITION_SEARCH_RADIUS = 5; +- private static final int AUTOSAVE_INTERVAL = 6000; +- private static final int MIMINUM_AUTOSAVE_TICKS = 100; +- private static final int MAX_TICK_LATENCY = 3; +- public static final int ABSOLUTE_MAX_WORLD_SIZE = 29999984; ++ // private static final long PREPARE_LEVELS_DEFAULT_DELAY_NANOS = 10L * TimeUtil.NANOSECONDS_PER_MILLISECOND; ++ // private static final int MAX_STATUS_PLAYER_SAMPLE = 12; ++ // private static final int SPAWN_POSITION_SEARCH_RADIUS = 5; ++ // private static final int AUTOSAVE_INTERVAL = 6000; ++ // private static final int MIMINUM_AUTOSAVE_TICKS = 100; ++ // private static final int MAX_TICK_LATENCY = 3; ++ // public static final int ABSOLUTE_MAX_WORLD_SIZE = 29999984; ++ @Deprecated(forRemoval = true) // Plazma + public static final LevelSettings DEMO_SETTINGS = new LevelSettings( + "Demo World", GameType.SURVIVAL, false, Difficulty.NORMAL, false, new GameRules(FeatureFlags.DEFAULT_FLAGS), WorldDataConfiguration.DEFAULT + ); +@@ -206,6 +_,7 @@ + @Nullable + private MinecraftServer.TimeProfiler debugCommandProfiler; + private boolean debugCommandProfilerDelayStart; ++ @Nullable // Plazma - Null safety + private ServerConnectionListener connection; + public final ChunkProgressListenerFactory progressListenerFactory; + @Nullable +@@ -214,10 +_,12 @@ + private ServerStatus.Favicon statusIcon; + private final RandomSource random = RandomSource.create(); + public final DataFixer fixerUpper; ++ @Nullable // Plazma - Null safety + private String localIp; + private int port = -1; + private final LayeredRegistryAccess registries; + private Map, ServerLevel> levels = Maps.newLinkedHashMap(); ++ @Nullable // Plazma - Null safety + private PlayerList playerList; + private volatile boolean running = true; + private volatile boolean isRestarting = false; // Paper - flag to signify we're attempting to restart +@@ -229,6 +_,7 @@ + private boolean preventProxyConnections; + private boolean pvp; + private boolean allowFlight; ++ @Nullable // Plazma - Null safety + private net.kyori.adventure.text.Component motd; // Paper - Adventure + private int playerIdleTimeout; + private final long[] tickTimesNanos = new long[100]; +@@ -285,7 +_,7 @@ + public org.bukkit.command.ConsoleCommandSender console; + public static int currentTick; // Paper - improve tick loop + public static final long startTimeMillis = System.currentTimeMillis(); // Purpur - Add uptime command +- public java.util.Queue processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); ++ public java.util.Queue processQueue = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Plazma - Remove unnecessary type parameter + public int autosavePeriod; + // Paper - don't store the vanilla dispatcher + public boolean forceTicks; +@@ -299,8 +_,10 @@ + // Spigot end + public volatile boolean hasFullyShutdown; // Paper - Improved watchdog support + public volatile boolean abnormalExit; // Paper - Improved watchdog support ++ @Nullable // Plazma - Null safety + public volatile Thread shutdownThread; // Paper - Improved watchdog support + public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files ++ public final org.plazmamc.plazma.configurations.PlazmaConfigurations plazmaConfigurations; // Plazma - Configurable Plazma + public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked + private final Set pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping + public boolean lagging = false; // Purpur - Lagging threshold +@@ -312,18 +_,19 @@ + AtomicReference atomicReference = new AtomicReference<>(); + Thread thread = new ca.spottedleaf.moonrise.common.util.TickThread(() -> atomicReference.get().runServer(), "Server thread"); + thread.setUncaughtExceptionHandler((thread1, exception) -> LOGGER.error("Uncaught exception in server thread", exception)); +- thread.setPriority(Thread.NORM_PRIORITY+2); // Paper - Perf: Boost priority ++ thread.setPriority(Thread.NORM_PRIORITY + 2); // Paper - Perf: Boost priority // Plazma - Improve code quality + if (Runtime.getRuntime().availableProcessors() > 4) { + thread.setPriority(8); + } + +- S minecraftServer = (S)threadFunction.apply(thread); ++ S minecraftServer = threadFunction.apply(thread); // Plazma - Remove unnecessary type casting + atomicReference.set(minecraftServer); + thread.start(); + return minecraftServer; + } + + // Paper start - rewrite chunk system ++ @Nullable // Plazma - Null safety + private volatile Throwable chunkSystemCrash; + + @Override +@@ -344,12 +_,12 @@ + boolean executed = false; + for (final ServerLevel world : this.getAllLevels()) { + long currTime = System.nanoTime(); +- if (currTime - ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getLastMidTickFailure() <= TASK_EXECUTION_FAILURE_BACKOFF) { ++ if (currTime - world.moonrise$getLastMidTickFailure() <= TASK_EXECUTION_FAILURE_BACKOFF) { // Plazma - Remove unnecessary type casting + continue; + } + if (!world.getChunkSource().pollTask()) { + // we need to back off if this fails +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$setLastMidTickFailure(currTime); ++ world.moonrise$setLastMidTickFailure(currTime); // Plazma - Remove unnecessary type casting + } else { + executed = true; + } +@@ -384,8 +_,8 @@ + overuse = 10L * 1000L * 1000L; // 10ms + } + +- final double overuseCount = (double)overuse/(double)MAX_CHUNK_EXEC_TIME; +- final long extraSleep = (long)Math.round(overuseCount*CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME); ++ final double overuseCount = (double) overuse / (double) MAX_CHUNK_EXEC_TIME; // Plazma - Remove unnecessary type casting ++ final long extraSleep = Math.round(overuseCount*CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME); // Plazma - Remove unnecessary type casting + + this.lastMidTickExecute = currTime + extraSleep; + return; +@@ -412,68 +_,42 @@ + SERVER = this; // Paper - better singleton + this.registries = worldStem.registries(); + this.worldData = worldStem.worldData(); +- if (false && !this.registries.compositeAccess().lookupOrThrow(Registries.LEVEL_STEM).containsKey(LevelStem.OVERWORLD)) { // CraftBukkit - initialised later +- throw new IllegalStateException("Missing Overworld dimension data"); +- } else { +- this.proxy = proxy; +- this.packRepository = packRepository; +- this.resources = new MinecraftServer.ReloadableResources(worldStem.resourceManager(), worldStem.dataPackResources()); +- this.services = services; +- if (services.profileCache() != null) { +- services.profileCache().setExecutor(this); +- } +- +- // this.connection = new ServerConnectionListener(this); // Spigot +- this.tickRateManager = new ServerTickRateManager(this); +- this.progressListenerFactory = progressListenerFactory; +- this.storageSource = storageSource; +- this.playerDataStorage = storageSource.createPlayerStorage(); +- this.fixerUpper = fixerUpper; +- this.functionManager = new ServerFunctionManager(this, this.resources.managers.getFunctionLibrary()); +- HolderGetter holderGetter = this.registries +- .compositeAccess() +- .lookupOrThrow(Registries.BLOCK) +- .filterFeatures(this.worldData.enabledFeatures()); +- this.structureTemplateManager = new StructureTemplateManager(worldStem.resourceManager(), storageSource, fixerUpper, holderGetter); +- this.serverThread = serverThread; +- this.executor = Util.backgroundExecutor(); +- this.potionBrewing = PotionBrewing.bootstrap(this.worldData.enabledFeatures()); +- this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures()); +- this.fuelValues = FuelValues.vanillaBurnTimes(this.registries.compositeAccess(), this.worldData.enabledFeatures()); +- this.tickFrame = TracyClient.createDiscontinuousFrame("Server Tick"); ++ // Plazma start - Imporve code quality ++ this.proxy = proxy; ++ this.packRepository = packRepository; ++ this.resources = new MinecraftServer.ReloadableResources(worldStem.resourceManager(), worldStem.dataPackResources()); ++ this.services = services; ++ if (services.profileCache() != null) { ++ services.profileCache().setExecutor(this); + } ++ ++ // this.connection = new ServerConnectionListener(this); // Spigot ++ this.tickRateManager = new ServerTickRateManager(this); ++ this.progressListenerFactory = progressListenerFactory; ++ this.storageSource = storageSource; ++ this.playerDataStorage = storageSource.createPlayerStorage(); ++ this.fixerUpper = fixerUpper; ++ this.functionManager = new ServerFunctionManager(this, this.resources.managers.getFunctionLibrary()); ++ HolderGetter holderGetter = this.registries ++ .compositeAccess() ++ .lookupOrThrow(Registries.BLOCK) ++ .filterFeatures(this.worldData.enabledFeatures()); ++ this.structureTemplateManager = new StructureTemplateManager(worldStem.resourceManager(), storageSource, fixerUpper, holderGetter); ++ this.serverThread = serverThread; ++ this.executor = Util.backgroundExecutor(); ++ this.potionBrewing = PotionBrewing.bootstrap(this.worldData.enabledFeatures()); ++ this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures()); ++ this.fuelValues = FuelValues.vanillaBurnTimes(this.registries.compositeAccess(), this.worldData.enabledFeatures()); ++ this.tickFrame = TracyClient.createDiscontinuousFrame("Server Tick"); ++ // Plazma end - Improve code quality + // CraftBukkit start + this.options = options; + this.worldLoader = worldLoader; +- // Paper start - Handled by TerminalConsoleAppender +- // Try to see if we're actually running in a terminal, disable jline if not +- /* +- if (System.console() == null && System.getProperty("jline.terminal") == null) { +- System.setProperty("jline.terminal", "jline.UnsupportedTerminal"); +- Main.useJline = false; +- } +- +- try { +- this.reader = new ConsoleReader(System.in, System.out); +- this.reader.setExpandEvents(false); // Avoid parsing exceptions for uncommonly used event designators +- } catch (Throwable e) { +- try { +- // Try again with jline disabled for Windows users without C++ 2008 Redistributable +- System.setProperty("jline.terminal", "jline.UnsupportedTerminal"); +- System.setProperty("user.language", "en"); +- Main.useJline = false; +- this.reader = new ConsoleReader(System.in, System.out); +- this.reader.setExpandEvents(false); +- } catch (IOException ex) { +- MinecraftServer.LOGGER.warn((String) null, ex); +- } +- } +- */ +- // Paper end + io.papermc.paper.util.LogManagerShutdownThread.unhook(); // Paper - Improved watchdog support + Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this)); + // CraftBukkit end + this.paperConfigurations = services.paperConfigurations(); // Paper - add paper configuration files ++ this.plazmaConfigurations = services.plazmaConfigurations(); + } + + private void readScoreboard(DimensionDataStorage dataStorage) { +@@ -483,23 +_,11 @@ + protected abstract boolean initServer() throws IOException; + + protected void loadLevel(String levelId) { // CraftBukkit +- if (!JvmProfiler.INSTANCE.isRunning()) { +- } +- +- boolean flag = false; + ProfiledDuration profiledDuration = JvmProfiler.INSTANCE.onWorldLoadedStarted(); + this.loadWorld0(levelId); // CraftBukkit + if (profiledDuration != null) { + profiledDuration.finish(true); + } +- +- if (flag) { +- try { +- JvmProfiler.INSTANCE.stop(); +- } catch (Throwable var5) { +- LOGGER.warn("Failed to stop JFR profiling", var5); +- } +- } + } + + protected void forceDifficulty() { +@@ -776,7 +_,7 @@ + + try { + serverLevel.fillReportDetails(crashReport); +- } catch (Throwable var22) { ++ } catch (Throwable ignore) { // Plazma - Fix IDE warning + } + + throw new ReportedException(crashReport); +@@ -872,39 +_,30 @@ + int _int = serverLevel.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS); // CraftBukkit - per-world + int i = _int > 0 ? Mth.square(ChunkProgressListener.calculateDiameter(_int)) : 0; + ++ // CraftBukkit start + while (chunkSource.getTickingGenerated() < i) { +- // CraftBukkit start +- // this.nextTickTimeNanos = Util.getNanos() + PREPARE_LEVELS_DEFAULT_DELAY_NANOS; + this.executeModerately(); + } + +- // this.nextTickTimeNanos = Util.getNanos() + PREPARE_LEVELS_DEFAULT_DELAY_NANOS; + this.executeModerately(); + +- if (true) { +- ServerLevel serverLevel1 = serverLevel; +- // CraftBukkit end +- ForcedChunksSavedData forcedChunksSavedData = serverLevel1.getDataStorage().get(ForcedChunksSavedData.factory(), "chunks"); +- if (forcedChunksSavedData != null) { +- LongIterator longIterator = forcedChunksSavedData.getChunks().iterator(); ++ // Plazma start - Improve code quality ++ ForcedChunksSavedData forcedChunksSavedData = serverLevel.getDataStorage().get(ForcedChunksSavedData.factory(), "chunks"); ++ if (forcedChunksSavedData != null) { ++ LongIterator longIterator = forcedChunksSavedData.getChunks().iterator(); + +- while (longIterator.hasNext()) { +- long l = longIterator.nextLong(); +- ChunkPos chunkPos = new ChunkPos(l); +- serverLevel1.getChunkSource().updateChunkForced(chunkPos, true); +- } ++ while (longIterator.hasNext()) { ++ long l = longIterator.nextLong(); ++ ChunkPos chunkPos = new ChunkPos(l); ++ serverLevel.getChunkSource().updateChunkForced(chunkPos, true); + } + } ++ // Plazma end - Improve code quality + +- // CraftBukkit start +- // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS; + this.executeModerately(); +- // CraftBukkit end + listener.stop(); + // CraftBukkit start +- // this.updateMobSpawningFlags(); + serverLevel.setSpawnSettings(serverLevel.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && ((net.minecraft.server.dedicated.DedicatedServer) this).settings.getProperties().spawnMonsters); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean)) +- + this.forceTicks = false; + // CraftBukkit end + } +@@ -1014,6 +_,7 @@ + } + // Purpur end - UPnP Port Forwarding + // CraftBukkit start ++ // noinspection ConstantValue // Plazma - Null safety + if (this.server != null) { + this.server.spark.disable(); // Paper - spark + this.server.disablePlugins(); +@@ -1027,7 +_,7 @@ + LOGGER.info("Saving players"); + this.playerList.saveAll(); + this.playerList.removeAll(this.isRestarting); // Paper +- try { Thread.sleep(100); } catch (InterruptedException ex) {} // CraftBukkit - SPIGOT-625 - give server at least a chance to send packets ++ try { Thread.sleep(100); } catch (InterruptedException ignore) {} // CraftBukkit - SPIGOT-625 - give server at least a chance to send packets // Plazma - Fix IDE warning + } + + LOGGER.info("Saving worlds"); +@@ -1038,17 +_,6 @@ + } + } + +- while (false && this.levels.values().stream().anyMatch(level -> level.getChunkSource().chunkMap.hasWork())) { // Paper - rewrite chunk system +- this.nextTickTimeNanos = Util.getNanos() + TimeUtil.NANOSECONDS_PER_MILLISECOND; +- +- for (ServerLevel serverLevelx : this.getAllLevels()) { +- serverLevelx.getChunkSource().removeTicketsOnClosing(); +- serverLevelx.getChunkSource().tick(() -> true, false); +- } +- +- this.waitUntilNextTick(); +- } +- + this.saveAllChunks(false, true, false, true); // Paper - rewrite chunk system + + this.isSaving = false; +@@ -1069,14 +_,16 @@ + this.getProfileCache().save(false); // Paper - Perf: Async GameProfileCache saving + } + // Spigot end ++ + // Paper start - rewrite chunk system + LOGGER.info("Waiting for I/O tasks to complete..."); +- ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.flush((MinecraftServer)(Object)this); ++ ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.flush(this); // Plazma - Remove unnecessary type casting + LOGGER.info("All I/O tasks to complete"); +- if ((Object)this instanceof net.minecraft.server.dedicated.DedicatedServer) { ++ if (this instanceof net.minecraft.server.dedicated.DedicatedServer) { // Plazma - Remove unnecessary type casting + ca.spottedleaf.moonrise.common.util.MoonriseCommon.haltExecutors(); + } + // Paper end - rewrite chunk system ++ + // Paper start - Improved watchdog support - move final shutdown items here + Util.shutdownExecutors(); + try { +@@ -1089,7 +_,7 @@ + } + + public String getLocalIp() { +- return this.localIp; ++ return (this.localIp == null) ? "" : this.localIp; + } + + public void setLocalIp(String localIp) { +@@ -1123,9 +_,9 @@ + + // Paper start - Further improve server tick loop + private static final long SEC_IN_NANO = 1000000000; +- private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L; ++ //private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L; + private long lastTick = 0; +- private long catchupTime = 0; ++ //private long catchupTime = 0; + public final RollingAverage tps5s = new RollingAverage(5); // Purpur - Add 5 second tps average in /tps + public final RollingAverage tps1 = new RollingAverage(60); + public final RollingAverage tps5 = new RollingAverage(60 * 5); +@@ -1170,7 +_,7 @@ + return total.divide(dec(time), 30, java.math.RoundingMode.HALF_UP).doubleValue(); + } + } +- private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal(1E9).multiply(new java.math.BigDecimal(SAMPLE_INTERVAL)); ++ private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal("1E9").multiply(new java.math.BigDecimal(SAMPLE_INTERVAL)); // Plazma + // Paper end + + protected void runServer() { +@@ -1184,7 +_,6 @@ + this.status = this.buildServerStatus(); + + this.server.spark.enableBeforePlugins(); // Paper - spark +- // Spigot start + // Paper start + LOGGER.info("Running delayed init tasks"); + this.server.getScheduler().mainThreadHeartbeat(); // run all 1 tick delay tasks during init, +@@ -1202,6 +_,7 @@ + long tickSection = Util.getNanos(); + long currentTime; + // Paper end - further improve server tick loop ++ + // Paper start - Add onboarding message for initial server start + if (io.papermc.paper.configuration.GlobalConfiguration.isFirstStart) { + LOGGER.info("*************************************************************************************"); +@@ -1496,8 +_,8 @@ + + private Optional loadStatusIcon() { + Optional optional = Optional.of(this.getFile("server-icon.png")) +- .filter(path -> Files.isRegularFile(path)) +- .or(() -> this.storageSource.getIconFile().filter(path -> Files.isRegularFile(path))); ++ .filter(Files::isRegularFile) ++ .or(() -> this.storageSource.getIconFile().filter(Files::isRegularFile)); + return optional.flatMap(path -> { + try { + BufferedImage bufferedImage = ImageIO.read(path.toFile()); +@@ -1507,7 +_,7 @@ + ImageIO.write(bufferedImage, "PNG", byteArrayOutputStream); + return Optional.of(new ServerStatus.Favicon(byteArrayOutputStream.toByteArray())); + } catch (Exception var3) { +- LOGGER.error("Couldn't load server icon", (Throwable)var3); ++ LOGGER.error("Couldn't load server icon", var3); // Plazma - Remove unnecessary type casting + return Optional.empty(); + } + }); +@@ -1537,7 +_,7 @@ + int i = this.pauseWhileEmptySeconds() * 20; + this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping + if (i > 0) { +- if (this.playerList.getPlayerCount() == 0 && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping ++ if (this.getPlayerList().getPlayerCount() == 0 && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping // Plazma - Null safety + this.emptyTicks++; + } else { + this.emptyTicks = 0; +@@ -1590,7 +_,7 @@ + try { + this.isSaving = true; + if (playerSaveInterval > 0) { +- this.playerList.saveAll(playerSaveInterval); ++ this.getPlayerList().saveAll(playerSaveInterval); // Plazma - Null safety + } + for (final ServerLevel level : this.getAllLevels()) { + if (level.paperConfig().chunks.autoSaveInterval.value() > 0) { +@@ -1608,7 +_,7 @@ + this.server.spark.executeMainThreadTasks(); // Paper - spark + // Paper start - Server Tick Events + long endTime = System.nanoTime(); +- long remaining = (TICK_TIME - (endTime - lastTick)) - catchupTime; ++ long remaining = (TICK_TIME - (endTime - lastTick)); // Plazma - Remove unnecessary variable + new com.destroystokyo.paper.event.server.ServerTickEndEvent(this.tickCount, ((double)(endTime - lastTick) / 1000000D), remaining).callEvent(); + // Paper end - Server Tick Events + this.server.spark.tickEnd(((double)(endTime - lastTick) / 1000000D)); // Paper - spark +@@ -1671,7 +_,7 @@ + private ServerStatus buildServerStatus() { + ServerStatus.Players players = this.buildPlayerStatus(); + return new ServerStatus( +- io.papermc.paper.adventure.PaperAdventure.asVanilla(this.motd), // Paper - Adventure ++ io.papermc.paper.adventure.PaperAdventure.asVanilla(this.motd()), // Paper - Adventure // Plazma - Null safety + Optional.of(players), + Optional.of(ServerStatus.Version.current()), + Optional.ofNullable(this.statusIcon), +@@ -1680,7 +_,7 @@ + } + + private ServerStatus.Players buildPlayerStatus() { +- List players = this.playerList.getPlayers(); ++ List players = this.getPlayerList().getPlayers(); // Plazma - Null safety + int maxPlayers = this.getMaxPlayers(); + if (this.hidesOnlinePlayers()) { + return new ServerStatus.Players(maxPlayers, players.size(), List.of()); +@@ -1701,7 +_,7 @@ + + protected void tickChildren(BooleanSupplier hasTimeLeft) { + ProfilerFiller profilerFiller = Profiler.get(); +- this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing()); ++ this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing()); // Plazma - Null safety + this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit + // Paper start - Folia scheduler API + ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) org.bukkit.Bukkit.getGlobalRegionScheduler()).tick(); +@@ -1736,10 +_,9 @@ + long worldTime = level.getGameTime(); + final ClientboundSetTimePacket worldPacket = new ClientboundSetTimePacket(worldTime, dayTime, doDaylight); + for (Player entityhuman : level.players()) { +- if (!(entityhuman instanceof ServerPlayer) || (!level.isForceTime() && (tickCount + entityhuman.getId()) % 20 != 0)) { // Purpur - Configurable daylight cycle ++ if (!(entityhuman instanceof ServerPlayer entityplayer) || (!level.isForceTime() && (tickCount + entityhuman.getId()) % 20 != 0)) { // Purpur - Configurable daylight cycle // Plazma - Use modern method + continue; + } +- ServerPlayer entityplayer = (ServerPlayer) entityhuman; + long playerTime = entityplayer.getPlayerTime(); + boolean relativeTime = entityplayer.relativeTime; + ClientboundSetTimePacket packet = ((relativeTime || !doDaylight) && playerTime == dayTime) ? worldPacket : +@@ -1757,13 +_,6 @@ + net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers + serverLevel.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - Ridables + profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location()); +- /* Drop global time updates +- if (this.tickCount % 20 == 0) { +- profilerFiller.push("timeSync"); +- this.synchronizeTime(serverLevel); +- profilerFiller.pop(); +- } +- // CraftBukkit end */ + + profilerFiller.push("tick"); + +@@ -1777,14 +_,14 @@ profilerFiller.pop(); profilerFiller.pop(); @@ -9,3 +533,174 @@ } this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked + profilerFiller.popPush("connection"); + this.tickConnection(); + profilerFiller.popPush("players"); +- this.playerList.tick(); ++ this.getPlayerList().tick(); // Plazma - Null safety + if (SharedConstants.IS_RUNNING_IN_IDE && this.tickRateManager.runsNormally()) { + GameTestTicker.SINGLETON.tick(); + } +@@ -1797,7 +_,7 @@ + + profilerFiller.popPush("send chunks"); + +- for (ServerPlayer serverPlayer : this.playerList.getPlayers()) { ++ for (ServerPlayer serverPlayer : this.getPlayerList().getPlayers()) { // Plazma - Null safety + serverPlayer.connection.chunkSender.sendNextChunks(serverPlayer); + serverPlayer.connection.resumeFlushing(); + } +@@ -1810,7 +_,7 @@ + } + + private void synchronizeTime(ServerLevel level) { +- this.playerList ++ this.getPlayerList() // Plazma - Null safety + .broadcastAll( + new ClientboundSetTimePacket(level.getGameTime(), level.getDayTime(), level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)), + level.dimension() +@@ -1848,8 +_,9 @@ + return this.getServerDirectory().resolve(path); + } + ++ @Nullable // Plazma - Null safety + public final ServerLevel overworld() { +- return this.levels.get(Level.OVERWORLD); ++ return this.getLevel(Level.OVERWORLD); // Plazma + } + + @Nullable +@@ -1888,16 +_,16 @@ + + @Override + public int getPlayerCount() { +- return this.playerList.getPlayerCount(); ++ return this.getPlayerList().getPlayerCount(); + } + + @Override + public int getMaxPlayers() { +- return this.playerList.getMaxPlayers(); ++ return this.getPlayerList().getMaxPlayers(); + } + + public String[] getPlayerNames() { +- return this.playerList.getPlayerNamesArray(); ++ return this.getPlayerList().getPlayerNamesArray(); + } + + @DontObfuscate +@@ -1940,6 +_,7 @@ + LOGGER.info(io.papermc.paper.adventure.PaperAdventure.ANSI_SERIALIZER.serialize(io.papermc.paper.adventure.PaperAdventure.asAdventure(component))); // Paper - Log message with colors + } + ++ @Nullable // Plazma - Null safety + public KeyPair getKeyPair() { + return this.keyPair; + } +@@ -1977,7 +_,7 @@ + + // Paper start - per level difficulty + public void setDifficulty(ServerLevel level, Difficulty difficulty, boolean forceUpdate) { +- net.minecraft.world.level.storage.PrimaryLevelData worldData = (net.minecraft.world.level.storage.PrimaryLevelData) level.serverLevelData; ++ net.minecraft.world.level.storage.PrimaryLevelData worldData = level.serverLevelData; // Plazma - Remove unnecessary type casting + if (forceUpdate || !worldData.isDifficultyLocked()) { + worldData.setDifficulty(worldData.isHardcore() ? Difficulty.HARD : difficulty); + level.setSpawnSettings(worldData.getDifficulty() != Difficulty.PEACEFUL && ((net.minecraft.server.dedicated.DedicatedServer) this).settings.getProperties().spawnMonsters); +@@ -2068,7 +_,7 @@ + + @Override + public String getMotd() { +- return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.motd); // Paper - Adventure ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.motd()); // Paper - Adventure + } + + public void setMotd(String motd) { +@@ -2077,7 +_,7 @@ + } + + public net.kyori.adventure.text.Component motd() { +- return this.motd; ++ return Objects.requireNonNullElse(this.motd, net.kyori.adventure.text.Component.empty()); + } + + public void motd(net.kyori.adventure.text.Component motd) { +@@ -2090,7 +_,7 @@ + } + + public PlayerList getPlayerList() { +- return this.playerList; ++ return Objects.requireNonNull(this.playerList, "Server is not started yet"); + } + + public void setPlayerList(PlayerList list) { +@@ -2151,6 +_,7 @@ + this.playerIdleTimeout = idleTimeout; + } + ++ @Nullable + public MinecraftSessionService getSessionService() { + return this.services.sessionService(); + } +@@ -2160,13 +_,13 @@ + return this.services.profileKeySignatureValidator(); + } + ++ @Nullable + public GameProfileRepository getProfileRepository() { + return this.services.profileRepository(); + } + +- @Nullable + public GameProfileCache getProfileCache() { +- return this.services.profileCache(); ++ return Objects.requireNonNull(this.services.profileCache(), "Profile cache is null"); + } + + @Nullable +@@ -2236,7 +_,7 @@ + } + public CompletableFuture reloadResources(Collection selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause cause) { + // Paper end - Add ServerResourcesReloadedEvent +- CompletableFuture completableFuture = CompletableFuture.supplyAsync( ++ CompletableFuture completableFuture = CompletableFuture.supplyAsync( // Plazma - Remove unnecessary type parameter + () -> selectedIds.stream().map(this.packRepository::getPack).filter(Objects::nonNull).map(Pack::open).collect(ImmutableList.toImmutableList()), + this + ) +@@ -2277,7 +_,6 @@ + this.potionBrewing = this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes + if (Thread.currentThread() != this.serverThread) return; // Paper + // Paper start - we don't need to save everything, just advancements +- // this.getPlayerList().saveAll(); + for (final ServerPlayer player : this.getPlayerList().getPlayers()) { + player.getAdvancements().save(); + } +@@ -2478,7 +_,7 @@ + } + + public GameRules getGameRules() { +- return this.overworld().getGameRules(); ++ return Objects.requireNonNull(this.overworld()).getGameRules(); + } + + public CustomBossEvents getCustomBossEvents() { +@@ -2582,9 +_,8 @@ + private void dumpClasspath(Path path) throws IOException { + try (Writer bufferedWriter = Files.newBufferedWriter(path)) { + String property = System.getProperty("java.class.path"); +- String property1 = System.getProperty("path.separator"); + +- for (String string : Splitter.on(property1).split(property)) { ++ for (String string : Splitter.on(File.pathSeparator).split(property)) { + bufferedWriter.write(string); + bufferedWriter.write("\n"); + } +@@ -2636,7 +_,7 @@ + } + + public static MinecraftServer getServer() { +- return SERVER; // Paper ++ return Objects.requireNonNull(SERVER); // Paper + } + + @Deprecated diff --git a/plazma-server/minecraft-patches/sources/net/minecraft/server/Services.java.patch b/plazma-server/minecraft-patches/sources/net/minecraft/server/Services.java.patch new file mode 100644 index 0000000..947671c --- /dev/null +++ b/plazma-server/minecraft-patches/sources/net/minecraft/server/Services.java.patch @@ -0,0 +1,62 @@ +--- a/net/minecraft/server/Services.java ++++ b/net/minecraft/server/Services.java +@@ -6,26 +_,42 @@ + import com.mojang.authlib.yggdrasil.ServicesKeyType; + import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; + import java.io.File; +-import javax.annotation.Nullable; ++import org.jspecify.annotations.Nullable; // Plazma + import net.minecraft.server.players.GameProfileCache; + import net.minecraft.util.SignatureValidator; + + public record Services( +- MinecraftSessionService sessionService, ServicesKeySet servicesKeySet, GameProfileRepository profileRepository, GameProfileCache profileCache, @javax.annotation.Nullable io.papermc.paper.configuration.PaperConfigurations paperConfigurations // Paper - add paper configuration files ++ // Plazma start - Null safety ++ @Nullable MinecraftSessionService sessionService, ++ @org.jspecify.annotations.NonNull ServicesKeySet servicesKeySet, ++ @Nullable GameProfileRepository profileRepository, ++ @Nullable GameProfileCache profileCache, // Plazma - ++ io.papermc.paper.configuration.@Nullable PaperConfigurations paperConfigurations, // Paper - add paper configuration files ++ org.plazmamc.plazma.configurations.@Nullable PlazmaConfigurations plazmaConfigurations // Plazma - Configurable Plazma ++ // Plazma end - Null safety + ) { + public static final String USERID_CACHE_FILE = "usercache.json"; // Paper - private -> public + + // Paper start - add paper configuration files + public Services(MinecraftSessionService sessionService, ServicesKeySet servicesKeySet, GameProfileRepository profileRepository, GameProfileCache profileCache) { +- this(sessionService, servicesKeySet, profileRepository, profileCache, null); ++ this(sessionService, servicesKeySet, profileRepository, profileCache, null, null); // Plazma + } + ++ @org.jetbrains.annotations.Contract(pure = true) // Plazma + @Override +- public io.papermc.paper.configuration.PaperConfigurations paperConfigurations() { ++ public io.papermc.paper.configuration.@org.jspecify.annotations.NonNull PaperConfigurations paperConfigurations() { + return java.util.Objects.requireNonNull(this.paperConfigurations); + } + // Paper end - add paper configuration files + ++ // Plazma start - Configurable Plazma ++ @org.jetbrains.annotations.Contract(pure = true) ++ @Override ++ public org.plazmamc.plazma.configurations.@org.jspecify.annotations.NonNull PlazmaConfigurations plazmaConfigurations() { ++ return java.util.Objects.requireNonNull(this.plazmaConfigurations); ++ } ++ // Plazma end - Configurable Plazma ++ + public static Services create(YggdrasilAuthenticationService authenticationService, File profileRepository, File userCacheFile, joptsimple.OptionSet optionSet) throws Exception { // Paper - add optionset to load paper config files; add userCacheFile parameter + MinecraftSessionService minecraftSessionService = authenticationService.createMinecraftSessionService(); + GameProfileRepository gameProfileRepository = authenticationService.createProfileRepository(); +@@ -34,7 +_,11 @@ + 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, profileRepository.toPath(), (File) optionSet.valueOf("spigot-settings")); +- return new Services(minecraftSessionService, authenticationService.getServicesKeySet(), gameProfileRepository, gameProfileCache, paperConfigurations); ++ ++ // Plazma start - Configurable Plazma ++ final org.plazmamc.plazma.configurations.PlazmaConfigurations plazmaConfigurations = org.plazmamc.plazma.configurations.PlazmaConfigurations.create(optionSet); ++ return new Services(minecraftSessionService, authenticationService.getServicesKeySet(), gameProfileRepository, gameProfileCache, paperConfigurations, plazmaConfigurations); ++ // Plazma end - Configurable Plazma + // Paper end - load paper config files from cli options + } + diff --git a/plazma-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/plazma-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch index a03c05e..8837e3b 100644 --- a/plazma-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch +++ b/plazma-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -1,5 +1,16 @@ --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java +@@ -61,8 +_,8 @@ + + public class DedicatedServer extends MinecraftServer implements ServerInterface { + static final Logger LOGGER = LogUtils.getLogger(); +- private static final int CONVERSION_RETRY_DELAY_MS = 5000; +- private static final int CONVERSION_RETRIES = 2; ++ // private static final int CONVERSION_RETRY_DELAY_MS = 5000; ++ // private static final int CONVERSION_RETRIES = 2; + private final java.util.Queue serverCommandQueue = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Paper - Perf: use a proper queue + @Nullable + private QueryThreadGs4 queryThreadGs4; @@ -105,47 +_,12 @@ public void run() { // CraftBukkit start @@ -75,14 +86,33 @@ System.setOut(org.apache.logging.log4j.io.IoBuilder.forLogger(logger).setLevel(org.apache.logging.log4j.Level.INFO).buildPrintStream()); System.setErr(org.apache.logging.log4j.io.IoBuilder.forLogger(logger).setLevel(org.apache.logging.log4j.Level.WARN).buildPrintStream()); -@@ -208,6 +_,7 @@ +@@ -208,6 +_,8 @@ org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings")); org.spigotmc.SpigotConfig.registerCommands(); // Spigot end ++ + // noinspection ResultOfMethodCallIgnored // Plazma - For preloading io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc. // Purpur start - Configurable void damage height and damage try { +@@ -218,10 +_,17 @@ + } + org.purpurmc.purpur.PurpurConfig.registerCommands(); + // Purpur end - Configurable void damage height and damage ++ + // Paper start - initialize global and world-defaults configuration + this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess()); + this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess()); + // Paper end - initialize global and world-defaults configuration ++ ++ // Plazma start - Configurable Plazma ++ this.plazmaConfigurations.initializeGlobalConfiguration(this.registryAccess()); ++ this.plazmaConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess()); ++ // Plazma end - Configurable Plazma ++ + 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()) { @@ -234,15 +_,7 @@ io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark @@ -110,6 +140,33 @@ } // Purpur start - UPnP Port Forwarding if (org.purpurmc.purpur.PurpurConfig.useUPnP) { +@@ -316,7 +_,6 @@ + // Purpur end - UPnP Port Forwarding + + // CraftBukkit start +- // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // Spigot - moved up + this.server.loadPlugins(); + this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.STARTUP); + // CraftBukkit end +@@ -342,18 +_,9 @@ + LOGGER.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file."); + } + +- // CraftBukkit start +- /* +- if (this.convertOldUsers()) { +- this.getProfileCache().save(); +- } +- */ +- // CraftBukkit end +- + if (!OldUsersConverter.serverReadyAfterUserconversion(this)) { + return false; + } else { +- // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // CraftBukkit - moved up + this.debugSampleSubscriptionTracker = new DebugSampleSubscriptionTracker(this.getPlayerList()); + this.tickTimeLogger = new RemoteSampleLogger( + TpsDebugDimensions.values().length, this.debugSampleSubscriptionTracker, RemoteDebugSampleType.TICK_TIME @@ -380,14 +_,6 @@ this.rconThread = RconThread.create(this); } diff --git a/plazma-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/plazma-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch new file mode 100644 index 0000000..d3ff0f4 --- /dev/null +++ b/plazma-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -0,0 +1,989 @@ +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -34,7 +_,7 @@ + import java.util.stream.Collectors; + import java.util.stream.Stream; + import javax.annotation.Nonnull; +-import javax.annotation.Nullable; ++import org.jspecify.annotations.Nullable; // Plazma + import net.minecraft.CrashReport; + import net.minecraft.CrashReportCategory; + import net.minecraft.ReportType; +@@ -177,8 +_,8 @@ + private static final IntProvider THUNDER_DELAY = UniformInt.of(12000, 180000); + public static final IntProvider THUNDER_DURATION = UniformInt.of(3600, 15600); + private static final Logger LOGGER = LogUtils.getLogger(); +- private static final int EMPTY_TIME_NO_TICK = 300; +- private static final int MAX_SCHEDULED_TICKS_PER_TICK = 65536; ++ // private static final int EMPTY_TIME_NO_TICK = 300; ++ // private static final int MAX_SCHEDULED_TICKS_PER_TICK = 65536; + final List players = Lists.newArrayList(); + public final ServerChunkCache chunkSource; + private final MinecraftServer server; +@@ -332,7 +_,7 @@ + + @Override + public final void moonrise$midTickTasks() { +- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); ++ this.server.moonrise$executeMidTickTasks(); // Plazma - Remove unnecessary type casting + } + + @Override +@@ -546,7 +_,7 @@ + + @Override + public final void moonrise$removePlayerTickingRequest(final int chunkX, final int chunkZ) { +- ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)(Object)this, chunkX, chunkZ, "Cannot remove ticking request async"); ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, chunkX, chunkZ, "Cannot remove ticking request async"); // Plazma - Remove unnecessary type casting + + final long chunkKey = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ); + final int val = this.playerTickingRequests.addTo(chunkKey, -1); +@@ -560,7 +_,7 @@ + return; + } + +- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)(ServerLevel)(Object)this).moonrise$getChunkTaskScheduler() ++ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel) this).moonrise$getChunkTaskScheduler() // Plazma - Remove unnecessary type casting + .chunkHolderManager.getChunkHolder(chunkKey); + + if (chunkHolder == null || !chunkHolder.isTickingReady()) { +@@ -568,7 +_,7 @@ + } + + this.playerTickingChunks.remove( +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder() ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk) chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder() // Plazma - Remove unnecessary type casting + ); + } + // Paper end - chunk tick iteration +@@ -587,11 +_,28 @@ + boolean tickTime, + @Nullable RandomSequences randomSequences, + org.bukkit.World.Environment env, // CraftBukkit +- org.bukkit.generator.ChunkGenerator gen, // CraftBukkit +- org.bukkit.generator.BiomeProvider biomeProvider // CraftBukkit ++ org.bukkit.generator.@Nullable ChunkGenerator gen, // CraftBukkit ++ org.bukkit.generator.@Nullable BiomeProvider biomeProvider // CraftBukkit + ) { + // CraftBukkit start +- super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.location(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules())), dispatcher); // Paper - create paper world configs; Async-Anti-Xray: Pass executor ++ // Plazma start - Configurable Plazma ++ super( ++ serverLevelData, ++ dimension, ++ server.registryAccess(), ++ levelStem.type(), ++ false, ++ isDebug, ++ biomeZoomSeed, ++ server.getMaxChainedNeighborUpdates(), ++ gen, ++ biomeProvider, ++ env, ++ (spigotConfig) -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.location(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules())), ++ () -> server.plazmaConfigurations.createWorldConfig(io.papermc.paper.configuration.Configurations.ContextMap.builder().put(io.papermc.paper.configuration.Configurations.WORLD_DIRECTORY, levelStorageAccess.levelDirectory.path()).put(io.papermc.paper.configuration.Configurations.WORLD_NAME, serverLevelData.getLevelName()).put(io.papermc.paper.configuration.Configurations.WORLD_KEY, dimension.location()).build()), ++ dispatcher ++ ); // Paper - create paper world configs; Async-Anti-Xray: Pass executor ++ // Plazma end - Configurable Plazma + this.pvpMode = server.isPvpAllowed(); + this.levelStorageAccess = levelStorageAccess; + this.uuid = org.bukkit.craftbukkit.util.WorldUUID.getUUID(levelStorageAccess.levelDirectory.path().toFile()); +@@ -816,32 +_,33 @@ + } + + io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR +- this.entityTickList +- .forEach( +- entity -> { +- if (!entity.isRemoved()) { +- if (!tickRateManager.isEntityFrozen(entity)) { +- profilerFiller.push("checkDespawn"); +- entity.checkDespawn(); +- profilerFiller.pop(); +- if (true) { // Paper - rewrite chunk system +- Entity vehicle = entity.getVehicle(); +- if (vehicle != null) { +- if (!vehicle.isRemoved() && vehicle.hasPassenger(entity)) { +- return; +- } +- +- entity.stopRiding(); +- } +- +- profilerFiller.push("tick"); +- this.guardEntityTick(this::tickNonPassenger, entity); +- profilerFiller.pop(); +- } +- } ++ this.entityTickList.forEach(entity -> { ++ if (entity.isRemoved()) { ++ return; ++ } ++ ++ if (!tickRateManager.isEntityFrozen(entity)) { ++ profilerFiller.push("checkDespawn"); ++ entity.checkDespawn(); ++ profilerFiller.pop(); ++ // Plazma start - Improve code styling ++ // Paper start - Rewrite chunk system ++ Entity vehicle = entity.getVehicle(); ++ if (vehicle != null) { ++ if (!vehicle.isRemoved() && vehicle.hasPassenger(entity)) { ++ return; + } ++ ++ entity.stopRiding(); + } +- ); ++ ++ profilerFiller.push("tick"); ++ this.guardEntityTick(this::tickNonPassenger, entity); ++ profilerFiller.pop(); ++ // Paper end - Rewrite chunk system ++ // Plazma end - Improve code styling ++ } ++ }); + profilerFiller.pop(); + this.tickBlockEntities(); + } +@@ -860,23 +_,25 @@ + } + + protected void tickTime() { +- if (this.tickTime) { +- long l = this.levelData.getGameTime() + 1L; +- this.serverLevelData.setGameTime(l); +- Profiler.get().push("scheduledFunctions"); +- this.serverLevelData.getScheduledEvents().tick(this.server, l); +- Profiler.get().pop(); +- if (this.serverLevelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { +- // Purpur start - Configurable daylight cycle +- int incrementTicks = isDay() ? this.purpurConfig.daytimeTicks : this.purpurConfig.nighttimeTicks; +- if (incrementTicks != 12000) { +- this.preciseTime += 12000 / (double) incrementTicks; +- this.setDayTime(this.preciseTime); +- } else ++ // Plazma start - Improve code quality ++ if (!this.tickTime) return; ++ ++ long l = this.levelData.getGameTime() + 1L; ++ this.serverLevelData.setGameTime(l); ++ Profiler.get().push("scheduledFunctions"); ++ this.serverLevelData.getScheduledEvents().tick(this.server, l); ++ Profiler.get().pop(); ++ if (this.serverLevelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { ++ // Purpur start - Configurable daylight cycle ++ int incrementTicks = isDay() ? this.purpurConfig.daytimeTicks : this.purpurConfig.nighttimeTicks; ++ if (incrementTicks != 12000) { ++ this.preciseTime += 12000 / (double) incrementTicks; ++ this.setDayTime(this.preciseTime); ++ } else + // Purpur end - Configurable daylight cycle + this.setDayTime(this.levelData.getDayTime() + 1L); +- } + } ++ // Plazma end - Improve code quality + } + + public void setDayTime(long time) { +@@ -905,7 +_,7 @@ + + private void wakeUpAllPlayers() { + this.sleepStatus.removeAllSleepers(); +- this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList()).forEach(player -> player.stopSleepInBed(false, false)); ++ this.players.stream().filter(LivingEntity::isSleeping).toList().forEach(player -> player.stopSleepInBed(false, false)); // Plazma + } + + // Paper start - optimise random ticking +@@ -946,11 +_,11 @@ + // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! + final BlockPos pos = new BlockPos((location & 15) | offsetX, ((location >>> (4 + 4)) & 15) | offsetY, ((location >>> 4) & 15) | offsetZ); + +- state.randomTick((ServerLevel)(Object)this, pos, simpleRandom); ++ state.randomTick(this, pos, simpleRandom); // Plazma - Remove unnecessary type casting + if (doubleTickFluids) { + final FluidState fluidState = state.getFluidState(); + if (fluidState.isRandomlyTicking()) { +- fluidState.randomTick((ServerLevel)(Object)this, pos, simpleRandom); ++ fluidState.randomTick(this, pos, simpleRandom); // Plazma - Remove unnecessary type casting + } + } + } +@@ -1030,27 +_,29 @@ + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockPos1, Blocks.ICE.defaultBlockState(), null); // CraftBukkit + } + +- if (this.isRaining()) { +- int _int = this.getGameRules().getInt(GameRules.RULE_SNOW_ACCUMULATION_HEIGHT); +- if (_int > 0 && biome.shouldSnow(this, heightmapPos)) { +- BlockState blockState = this.getBlockState(heightmapPos); +- if (blockState.is(Blocks.SNOW)) { +- int layersValue = blockState.getValue(SnowLayerBlock.LAYERS); +- if (layersValue < Math.min(_int, 8)) { +- BlockState blockState1 = blockState.setValue(SnowLayerBlock.LAYERS, Integer.valueOf(layersValue + 1)); +- Block.pushEntitiesUp(blockState, blockState1, this, heightmapPos); +- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, heightmapPos, blockState1, null); // CraftBukkit +- } +- } else { +- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, heightmapPos, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit ++ if (!this.isRaining()) { ++ return; ++ } ++ ++ int _int = this.getGameRules().getInt(GameRules.RULE_SNOW_ACCUMULATION_HEIGHT); ++ if (_int > 0 && biome.shouldSnow(this, heightmapPos)) { ++ BlockState blockState = this.getBlockState(heightmapPos); ++ if (blockState.is(Blocks.SNOW)) { ++ int layersValue = blockState.getValue(SnowLayerBlock.LAYERS); ++ if (layersValue < Math.min(_int, 8)) { ++ BlockState blockState1 = blockState.setValue(SnowLayerBlock.LAYERS, layersValue + 1); // Plazma ++ Block.pushEntitiesUp(blockState, blockState1, this, heightmapPos); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, heightmapPos, blockState1, null); // CraftBukkit + } ++ } else { ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, heightmapPos, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit + } ++ } + +- Biome.Precipitation precipitationAt = biome.getPrecipitationAt(blockPos1, this.getSeaLevel()); +- if (precipitationAt != Biome.Precipitation.NONE) { +- BlockState blockState2 = this.getBlockState(blockPos1); +- blockState2.getBlock().handlePrecipitation(blockState2, this, blockPos1, precipitationAt); +- } ++ Biome.Precipitation precipitationAt = biome.getPrecipitationAt(blockPos1, this.getSeaLevel()); ++ if (precipitationAt != Biome.Precipitation.NONE) { ++ BlockState blockState2 = this.getBlockState(blockPos1); ++ blockState2.getBlock().handlePrecipitation(blockState2, this, blockPos1, precipitationAt); + } + } + +@@ -1074,24 +_,25 @@ + // Paper end - Add methods to find targets for lightning strikes + BlockPos heightmapPos = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos); + Optional optional = this.findLightningRod(heightmapPos); ++ // Plazma start - Improve code quality + if (optional.isPresent()) { + return optional.get(); +- } else { +- AABB aabb = AABB.encapsulatingFullBlocks(heightmapPos, heightmapPos.atY(this.getMaxY() + 1)).inflate(3.0); +- List entitiesOfClass = this.getEntitiesOfClass( +- LivingEntity.class, aabb, entity -> entity != null && entity.isAlive() && this.canSeeSky(entity.blockPosition()) && !entity.isSpectator() // Paper - Fix lightning being able to hit spectators (MC-262422) +- ); +- if (!entitiesOfClass.isEmpty()) { +- return entitiesOfClass.get(this.random.nextInt(entitiesOfClass.size())).blockPosition(); +- } else { +- if (returnNullWhenNoTarget) return null; // Paper - Add methods to find targets for lightning strikes +- if (heightmapPos.getY() == this.getMinY() - 1) { +- heightmapPos = heightmapPos.above(2); +- } +- +- return heightmapPos; +- } +- } ++ } ++ ++ AABB aabb = AABB.encapsulatingFullBlocks(heightmapPos, heightmapPos.atY(this.getMaxY() + 1)).inflate(3.0); ++ List entitiesOfClass = this.getEntitiesOfClass( ++ LivingEntity.class, aabb, entity -> entity != null && entity.isAlive() && this.canSeeSky(entity.blockPosition()) && !entity.isSpectator() // Paper - Fix lightning being able to hit spectators (MC-262422) ++ ); ++ if (!entitiesOfClass.isEmpty()) { ++ return entitiesOfClass.get(this.random.nextInt(entitiesOfClass.size())).blockPosition(); ++ } ++ if (returnNullWhenNoTarget) return null; // Paper - Add methods to find targets for lightning strikes ++ if (heightmapPos.getY() == this.getMinY() - 1) { ++ heightmapPos = heightmapPos.above(2); ++ } ++ ++ return heightmapPos; ++ // Plazma end - Improve code quality + } + + public boolean isHandlingTick() { +@@ -1103,39 +_,45 @@ + } + + private void announceSleepStatus() { +- if (this.canSleepThroughNights()) { +- if (!this.getServer().isSingleplayer() || this.getServer().isPublished()) { +- int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); +- Component component; +- if (this.sleepStatus.areEnoughSleeping(_int)) { +- // Purpur start - Customizable sleeping actionbar messages +- if (org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.isBlank()) { +- return; +- } +- if (!org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.equalsIgnoreCase("default")) { +- component = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepSkippingNight)); +- } else +- // Purpur end - Customizable sleeping actionbar messages +- component = Component.translatable("sleep.skipping_night"); +- } else { +- // Purpur start - Customizable sleeping actionbar messages +- if (org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.isBlank()) { +- return; +- } +- if (!org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.equalsIgnoreCase("default")) { +- component = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent, +- net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("count", Integer.toString(this.sleepStatus.amountSleeping())), +- net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("total", Integer.toString(this.sleepStatus.sleepersNeeded(_int))))); +- } else +- // Purpur end - Customizable sleeping actionbar messages +- component = Component.translatable("sleep.players_sleeping", this.sleepStatus.amountSleeping(), this.sleepStatus.sleepersNeeded(_int)); +- } +- +- for (ServerPlayer serverPlayer : this.players) { +- serverPlayer.displayClientMessage(component, true); +- } +- } +- } ++ // Plazma start - Improve code quality ++ if (!this.canSleepThroughNights()) { ++ return; ++ } ++ ++ if (this.getServer().isSingleplayer() && !this.getServer().isPublished()) { ++ return; ++ } ++ ++ int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); ++ Component component; ++ if (this.sleepStatus.areEnoughSleeping(_int)) { ++ // Purpur start - Customizable sleeping actionbar messages ++ if (org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.isBlank()) { ++ return; ++ } ++ if (!org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.equalsIgnoreCase("default")) { ++ component = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepSkippingNight)); ++ } else ++ // Purpur end - Customizable sleeping actionbar messages ++ component = Component.translatable("sleep.skipping_night"); ++ } else { ++ // Purpur start - Customizable sleeping actionbar messages ++ if (org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.isBlank()) { ++ return; ++ } ++ if (!org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.equalsIgnoreCase("default")) { ++ component = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent, ++ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("count", Integer.toString(this.sleepStatus.amountSleeping())), ++ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("total", Integer.toString(this.sleepStatus.sleepersNeeded(_int))))); ++ } else ++ // Purpur end - Customizable sleeping actionbar messages ++ component = Component.translatable("sleep.players_sleeping", this.sleepStatus.amountSleeping(), this.sleepStatus.sleepersNeeded(_int)); ++ } ++ ++ for (ServerPlayer serverPlayer : this.players) { ++ serverPlayer.displayClientMessage(component, true); ++ } ++ // Plazma end - Improve code quality + } + + public void updateSleepingPlayerList() { +@@ -1211,30 +_,6 @@ + this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F); + } + +- /* CraftBukkit start +- if (this.oRainLevel != this.rainLevel) { +- this.server +- .getPlayerList() +- .broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, this.rainLevel), this.dimension()); +- } +- +- if (this.oThunderLevel != this.thunderLevel) { +- this.server +- .getPlayerList() +- .broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, this.thunderLevel), this.dimension()); +- } +- +- if (isRaining != this.isRaining()) { +- if (isRaining) { +- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.STOP_RAINING, 0.0F)); +- } else { +- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, 0.0F)); +- } +- +- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, this.rainLevel)); +- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, this.thunderLevel)); +- } +- */ + for (ServerPlayer player : this.players) { + if (player.level() == this) { + player.tickWeather(); +@@ -1291,7 +_,7 @@ + } + // Paper start - rewrite chunk system + if ((++this.tickedBlocksOrFluids & 7L) != 0L) { +- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); ++ this.server.moonrise$executeMidTickTasks(); // Plazma - Remove unnecessary type casting + } + // Paper end - rewrite chunk system + +@@ -1304,7 +_,7 @@ + } + // Paper start - rewrite chunk system + if ((++this.tickedBlocksOrFluids & 7L) != 0L) { +- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); ++ this.server.moonrise$executeMidTickTasks(); // Plazma - Remove unnecessary type casting + } + // Paper end - rewrite chunk system + +@@ -1316,9 +_,7 @@ + + public static List getCurrentlyTickingEntities() { + Entity ticking = currentlyTickingEntity.get(); +- List ret = java.util.Arrays.asList(ticking == null ? new Entity[0] : new Entity[] { ticking }); +- +- return ret; ++ return java.util.Arrays.asList(ticking == null ? new Entity[0] : new Entity[] { ticking }); // Plazma + } + // Paper end - log detailed entity tick information + +@@ -1329,23 +_,27 @@ + if (currentlyTickingEntity.get() == null) { + currentlyTickingEntity.lazySet(entity); + } ++ // Plazma start - Improve code quality + // Paper end - log detailed entity tick information +- entity.setOldPosAndRot(); +- ProfilerFiller profilerFiller = Profiler.get(); +- entity.tickCount++; +- entity.totalEntityAge++; // Paper - age-like counter for all entities +- profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()); +- profilerFiller.incrementCounter("tickNonPassenger"); +- final boolean isActive = io.papermc.paper.entity.activation.ActivationRange.checkIfActive(entity); // Paper - EAR 2 +- if (isActive) { // Paper - EAR 2 +- entity.tick(); +- entity.postTick(); // CraftBukkit +- } else {entity.inactiveTick();} // Paper - EAR 2 +- profilerFiller.pop(); ++ entity.setOldPosAndRot(); ++ ProfilerFiller profilerFiller = Profiler.get(); ++ entity.tickCount++; ++ entity.totalEntityAge++; // Paper - age-like counter for all entities ++ profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()); ++ profilerFiller.incrementCounter("tickNonPassenger"); ++ final boolean isActive = io.papermc.paper.entity.activation.ActivationRange.checkIfActive(entity); // Paper - EAR 2 ++ if (isActive) { // Paper - EAR 2 ++ entity.tick(); ++ entity.postTick(); // CraftBukkit ++ } else { ++ entity.inactiveTick(); // Paper - EAR 2 ++ } ++ profilerFiller.pop(); + +- for (Entity entity1 : entity.getPassengers()) { +- this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 +- } ++ for (Entity entity1 : entity.getPassengers()) { ++ this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 ++ } ++ // Plazma end - Improve code quality + // Paper start - log detailed entity tick information + } finally { + if (currentlyTickingEntity.get() == entity) { +@@ -1358,29 +_,33 @@ + private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2 + if (passengerEntity.isRemoved() || passengerEntity.getVehicle() != ridingEntity) { + passengerEntity.stopRiding(); +- } else if (passengerEntity instanceof Player || this.entityTickList.contains(passengerEntity)) { +- passengerEntity.setOldPosAndRot(); +- passengerEntity.tickCount++; +- passengerEntity.totalEntityAge++; // Paper - age-like counter for all entities +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(passengerEntity.getType()).toString()); +- profilerFiller.incrementCounter("tickPassenger"); +- // Paper start - EAR 2 +- if (isActive) { ++ // Plazma start - Improve code quality ++ } else if (!(passengerEntity instanceof Player) && !this.entityTickList.contains(passengerEntity)) { ++ return; ++ } ++ ++ passengerEntity.setOldPosAndRot(); ++ passengerEntity.tickCount++; ++ passengerEntity.totalEntityAge++; // Paper - age-like counter for all entities ++ ProfilerFiller profilerFiller = Profiler.get(); ++ profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(passengerEntity.getType()).toString()); ++ profilerFiller.incrementCounter("tickPassenger"); ++ // Paper start - EAR 2 ++ if (isActive) { + passengerEntity.rideTick(); + passengerEntity.postTick(); // CraftBukkit +- } else { +- passengerEntity.setDeltaMovement(Vec3.ZERO); +- passengerEntity.inactiveTick(); +- // copied from inside of if (isPassenger()) of passengerTick, but that ifPassenger is unnecessary +- ridingEntity.positionRider(passengerEntity); +- } +- // Paper end - EAR 2 +- profilerFiller.pop(); ++ } else { ++ passengerEntity.setDeltaMovement(Vec3.ZERO); ++ passengerEntity.inactiveTick(); ++ // copied from inside of if (isPassenger()) of passengerTick, but that ifPassenger is unnecessary ++ ridingEntity.positionRider(passengerEntity); ++ } ++ // Paper end - EAR 2 ++ profilerFiller.pop(); + +- for (Entity entity : passengerEntity.getPassengers()) { +- this.tickPassenger(passengerEntity, entity, isActive); // Paper - EAR 2 +- } ++ for (Entity entity : passengerEntity.getPassengers()) { ++ this.tickPassenger(passengerEntity, entity, isActive); // Paper - EAR 2 ++ // Plazma end - Improve code quality + } + } + +@@ -1546,7 +_,7 @@ + this.addDuringTeleport(entity, null); + } + +- public void addDuringTeleport(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { ++ public void addDuringTeleport(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason reason) { + // CraftBukkit end + if (entity instanceof ServerPlayer serverPlayer) { + this.addPlayer(serverPlayer); +@@ -1575,7 +_,7 @@ + } + + // CraftBukkit start +- private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { ++ private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason spawnReason) { // Plazma - Null safety + org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot + entity.generation = false; // Paper - Don't fire sync event during generation; Reset flag if it was added during a ServerLevel generation process + // Paper start - extra debug info +@@ -1588,22 +_,26 @@ + if (entity.isRemoved()) { + // LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityType.getKey(entity.getType())); // CraftBukkit - remove warning + return false; +- } else { +- if (entity instanceof net.minecraft.world.entity.item.ItemEntity itemEntity && itemEntity.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added +- // Paper start - capture all item additions to the world +- if (captureDrops != null && entity instanceof net.minecraft.world.entity.item.ItemEntity) { +- captureDrops.add((net.minecraft.world.entity.item.ItemEntity) entity); +- return true; +- } +- // Paper end - capture all item additions to the world +- // SPIGOT-6415: Don't call spawn event when reason is null. For example when an entity teleports to a new world. +- if (spawnReason != null && !org.bukkit.craftbukkit.event.CraftEventFactory.doEntityAddEventCalling(this, entity, spawnReason)) { +- return false; +- } +- // CraftBukkit end +- +- return this.moonrise$getEntityLookup().addNewEntity(entity); // Paper - rewrite chunk system +- } ++ } ++ ++ // Plazma start - Improve code quality ++ if (entity instanceof net.minecraft.world.entity.item.ItemEntity itemEntity && itemEntity.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added ++ ++ // Paper start - capture all item additions to the world ++ if (captureDrops != null && entity instanceof net.minecraft.world.entity.item.ItemEntity) { ++ captureDrops.add((net.minecraft.world.entity.item.ItemEntity) entity); ++ return true; ++ } ++ // Paper end - capture all item additions to the world ++ ++ // SPIGOT-6415: Don't call spawn event when reason is null. For example when an entity teleports to a new world. ++ if (spawnReason != null && !org.bukkit.craftbukkit.event.CraftEventFactory.doEntityAddEventCalling(this, entity, spawnReason)) { ++ return false; ++ } ++ // CraftBukkit end ++ ++ return this.moonrise$getEntityLookup().addNewEntity(entity); // Paper - rewrite chunk system ++ // Plazma end - Improve code quality + } + + public boolean tryAddFreshEntityWithPassengers(Entity entity) { +@@ -1624,15 +_,17 @@ + public void unload(LevelChunk chunk) { + // Spigot start + for (net.minecraft.world.level.block.entity.BlockEntity blockEntity : chunk.getBlockEntities().values()) { +- if (blockEntity instanceof net.minecraft.world.Container) { +- // Paper start - this area looks like it can load chunks, change the behavior +- // chests for example can apply physics to the world +- // so instead we just change the active container and call the event +- for (org.bukkit.entity.HumanEntity human : Lists.newArrayList(((net.minecraft.world.Container) blockEntity).getViewers())) { +- ((org.bukkit.craftbukkit.entity.CraftHumanEntity) human).getHandle().closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason +- } +- // Paper end - this area looks like it can load chunks, change the behavior ++ // Plazma start - Improve code quality ++ if (!(blockEntity instanceof net.minecraft.world.Container container)) continue; ++ ++ // Paper start - this area looks like it can load chunks, change the behavior ++ // chests for example can apply physics to the world ++ // so instead we just change the active container and call the event ++ for (org.bukkit.entity.HumanEntity human : Lists.newArrayList(container.getViewers())) { ++ ((org.bukkit.craftbukkit.entity.CraftHumanEntity) human).getHandle().closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason + } ++ // Paper end - this area looks like it can load chunks, change the behavior ++ // Plazma end - Improve code quality + } + // Spigot end + chunk.clearAllBlockEntities(); +@@ -1678,19 +_,25 @@ + } + // Paper end - Add BlockBreakProgressUpdateEvent + for (ServerPlayer serverPlayer : this.server.getPlayerList().getPlayers()) { +- if (serverPlayer != null && serverPlayer.level() == this && serverPlayer.getId() != breakerId) { +- double d = pos.getX() - serverPlayer.getX(); +- double d1 = pos.getY() - serverPlayer.getY(); +- double d2 = pos.getZ() - serverPlayer.getZ(); +- // CraftBukkit start +- if (breakerPlayer != null && !serverPlayer.getBukkitEntity().canSee(breakerPlayer.getBukkitEntity())) { +- continue; +- } +- // CraftBukkit end +- if (d * d + d1 * d1 + d2 * d2 < 1024.0) { +- serverPlayer.connection.send(new ClientboundBlockDestructionPacket(breakerId, pos, progress)); +- } +- } ++ // Plazma start - Improve code quality ++ if (serverPlayer == null || serverPlayer.level() != this || serverPlayer.getId() == breakerId) { ++ continue; ++ } ++ ++ double d = pos.getX() - serverPlayer.getX(); ++ double d1 = pos.getY() - serverPlayer.getY(); ++ double d2 = pos.getZ() - serverPlayer.getZ(); ++ ++ // CraftBukkit start ++ if (breakerPlayer != null && !serverPlayer.getBukkitEntity().canSee(breakerPlayer.getBukkitEntity())) { ++ continue; ++ } ++ // CraftBukkit end ++ ++ if (d * d + d1 * d1 + d2 * d2 < 1024.0) { ++ serverPlayer.connection.send(new ClientboundBlockDestructionPacket(breakerId, pos, progress)); ++ } ++ // Plazma end - Improve code quality + } + } + +@@ -1722,26 +_,29 @@ + + @Override + public void globalLevelEvent(int id, BlockPos pos, int data) { +- if (this.getGameRules().getBoolean(GameRules.RULE_GLOBAL_SOUND_EVENTS)) { +- this.server.getPlayerList().getPlayers().forEach(player -> { +- Vec3 vec31; +- if (player.level() == this) { +- Vec3 vec3 = Vec3.atCenterOf(pos); +- if (player.distanceToSqr(vec3) < Mth.square(32)) { +- vec31 = vec3; +- } else { +- Vec3 vec32 = vec3.subtract(player.position()).normalize(); +- vec31 = player.position().add(vec32.scale(32.0)); +- } +- } else { +- vec31 = player.position(); +- } +- +- player.connection.send(new ClientboundLevelEventPacket(id, BlockPos.containing(vec31), data, true)); +- }); +- } else { ++ // Plazma start - Improve code quality ++ if (!this.getGameRules().getBoolean(GameRules.RULE_GLOBAL_SOUND_EVENTS)) { + this.levelEvent(null, id, pos, data); ++ return; + } ++ ++ this.server.getPlayerList().getPlayers().forEach(player -> { ++ Vec3 vec31; ++ if (player.level() == this) { ++ Vec3 vec3 = Vec3.atCenterOf(pos); ++ if (player.distanceToSqr(vec3) < Mth.square(32)) { ++ vec31 = vec3; ++ } else { ++ Vec3 vec32 = vec3.subtract(player.position()).normalize(); ++ vec31 = player.position().add(vec32.scale(32.0)); ++ } ++ } else { ++ vec31 = player.position(); ++ } ++ ++ player.connection.send(new ClientboundLevelEventPacket(id, BlockPos.containing(vec31), data, true)); ++ }); ++ // Plazma end - Improve code quality + } + + @Override +@@ -1768,19 +_,21 @@ + @Override + public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) { + if (this.isUpdatingNavigations) { +- String string = "recursive call to sendBlockUpdated"; ++ //String string = "recursive call to sendBlockUpdated"; + Util.logAndPauseIfInIde("recursive call to sendBlockUpdated", new IllegalStateException("recursive call to sendBlockUpdated")); + } + + this.getChunkSource().blockChanged(pos); + this.pathTypesByPosCache.invalidate(pos); +- if (this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates ++ if (!this.paperConfig().misc.updatePathfindingOnBlockUpdate) return; // Paper - option to disable pathfinding updates // Plazma - Improve code quality ++ + VoxelShape collisionShape = oldState.getCollisionShape(this, pos); + VoxelShape collisionShape1 = newState.getCollisionShape(this, pos); +- if (Shapes.joinIsNotEmpty(collisionShape, collisionShape1, BooleanOp.NOT_SAME)) { +- List list = new ObjectArrayList<>(); ++ // Plazma start - Improve code quality ++ if (!Shapes.joinIsNotEmpty(collisionShape, collisionShape1, BooleanOp.NOT_SAME)) return; ++ List list = new ObjectArrayList<>(); + +- try { // Paper - catch CME see below why ++ try { // Paper - catch CME see below why + for (Mob mob : this.navigatingMobs) { + PathNavigation navigation = mob.getNavigation(); + if (navigation.shouldRecomputePath(pos)) { +@@ -1788,26 +_,24 @@ + } + } + // Paper start - catch CME see below why +- } catch (final java.util.ConcurrentModificationException concurrentModificationException) { +- // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register +- // In this case we just run the update again across all the iterators as the chunk will then be loaded +- // As this is a relative edge case it is much faster than copying navigators (on either read or write) +- this.sendBlockUpdated(pos, oldState, newState, flags); +- return; +- } +- // Paper end - catch CME see below why +- +- try { +- this.isUpdatingNavigations = true; +- +- for (PathNavigation pathNavigation : list) { +- pathNavigation.recomputePath(); +- } +- } finally { +- this.isUpdatingNavigations = false; +- } +- } +- } // Paper - option to disable pathfinding updates ++ } catch (final java.util.ConcurrentModificationException concurrentModificationException) { ++ // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register ++ // In this case we just run the update again across all the iterators as the chunk will then be loaded ++ // As this is a relative edge case it is much faster than copying navigators (on either read or write) ++ this.sendBlockUpdated(pos, oldState, newState, flags); ++ return; ++ } ++ // Paper end - catch CME see below why ++ ++ try { ++ this.isUpdatingNavigations = true; ++ ++ for (PathNavigation pathNavigation : list) { ++ pathNavigation.recomputePath(); ++ } ++ } finally { ++ this.isUpdatingNavigations = false; ++ } + } + + @Override +@@ -1900,7 +_,7 @@ + ParticleOptions smallExplosionParticles, + ParticleOptions largeExplosionParticles, + Holder explosionSound, +- @Nullable java.util.function.Consumer configurator ++ java.util.function.@Nullable Consumer configurator // Plazma - Null safety + ) { + // CraftBukkit end + Explosion.BlockInteraction blockInteraction = switch (explosionInteraction) { +@@ -1948,23 +_,26 @@ + + while (!this.blockEvents.isEmpty()) { + BlockEventData blockEventData = this.blockEvents.removeFirst(); +- if (this.shouldTickBlocksAt(blockEventData.pos())) { +- if (this.doBlockEvent(blockEventData)) { +- this.server +- .getPlayerList() +- .broadcast( +- null, +- blockEventData.pos().getX(), +- blockEventData.pos().getY(), +- blockEventData.pos().getZ(), +- 64.0, +- this.dimension(), +- new ClientboundBlockEventPacket(blockEventData.pos(), blockEventData.block(), blockEventData.paramA(), blockEventData.paramB()) +- ); +- } +- } else { ++ // Plazma start - Improve code quality ++ if (!this.shouldTickBlocksAt(blockEventData.pos())) { + this.blockEventsToReschedule.add(blockEventData); +- } ++ return; ++ } ++ ++ if (!this.doBlockEvent(blockEventData)) { ++ return; ++ } ++ ++ this.server.getPlayerList().broadcast( ++ null, ++ blockEventData.pos().getX(), ++ blockEventData.pos().getY(), ++ blockEventData.pos().getZ(), ++ 64.0, ++ this.dimension(), ++ new ClientboundBlockEventPacket(blockEventData.pos(), blockEventData.block(), blockEventData.paramA(), blockEventData.paramB()) ++ ); ++ // Plazma end - Improve code quality + } + + this.blockEvents.addAll(this.blockEventsToReschedule); +@@ -2058,8 +_,7 @@ + ); + int i = 0; + +- for (int i1 = 0; i1 < receivers.size(); i1++) { // Paper - particle API +- ServerPlayer serverPlayer = receivers.get(i1); // Paper - particle API ++ for (ServerPlayer serverPlayer : receivers) { // Paper - particle API // Plazma + if (sender != null && !serverPlayer.getBukkitEntity().canSee(sender.getBukkitEntity())) continue; // CraftBukkit + if (this.sendParticles(serverPlayer, overrideLimiter, posX, posY, posZ, clientboundLevelParticlesPacket)) { + i++; +@@ -2090,17 +_,19 @@ + } + + private boolean sendParticles(ServerPlayer player, boolean longDistance, double posX, double posY, double posZ, Packet packet) { ++ // Plazma start - Improve code quality + if (player.level() != this) { + return false; +- } else { +- BlockPos blockPos = player.blockPosition(); +- if (blockPos.closerToCenterThan(new Vec3(posX, posY, posZ), longDistance ? 512.0 : 32.0)) { +- player.connection.send(packet); +- return true; +- } else { +- return false; +- } +- } ++ } ++ ++ BlockPos blockPos = player.blockPosition(); ++ if (blockPos.closerToCenterThan(new Vec3(posX, posY, posZ), longDistance ? 512.0 : 32.0)) { ++ player.connection.send(packet); ++ return true; ++ } ++ ++ return false; ++ // Plazma end - Improve code quality + } + + @Nullable +@@ -2128,19 +_,21 @@ + + @Nullable + public BlockPos findNearestMapStructure(TagKey structureTag, BlockPos pos, int radius, boolean skipExistingChunks) { ++ // Plazma start - Improve code quality + if (!this.serverLevelData.worldGenOptions().generateStructures()) { // CraftBukkit + return null; +- } else { +- Optional> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag); +- if (optional.isEmpty()) { +- return null; +- } else { +- Pair> pair = this.getChunkSource() +- .getGenerator() +- .findNearestMapStructure(this, optional.get(), pos, radius, skipExistingChunks); +- return pair != null ? pair.getFirst() : null; +- } +- } ++ } ++ ++ Optional> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag); ++ if (optional.isEmpty()) { ++ return null; ++ } ++ ++ Pair> pair = this.getChunkSource() ++ .getGenerator() ++ .findNearestMapStructure(this, optional.get(), pos, radius, skipExistingChunks); ++ return pair != null ? pair.getFirst() : null; ++ // Plazma end - Improve code quality + } + + @Nullable +@@ -2247,7 +_,7 @@ + + public LongSet getForcedChunks() { + ForcedChunksSavedData forcedChunksSavedData = this.getDataStorage().get(ForcedChunksSavedData.factory(), "chunks"); +- return (LongSet)(forcedChunksSavedData != null ? LongSets.unmodifiable(forcedChunksSavedData.getChunks()) : LongSets.EMPTY_SET); ++ return (forcedChunksSavedData != null ? LongSets.unmodifiable(forcedChunksSavedData.getChunks()) : LongSets.EMPTY_SET); // Plazma - Remove unnecessary type casting + } + + public boolean setChunkForced(int chunkX, int chunkZ, boolean add) { +@@ -2363,27 +_,11 @@ + bufferedWriter1.write(crashReport.getFriendlyReport(ReportType.TEST)); + } + +- Path path1 = path.resolve("chunks.csv"); +- +- try (Writer bufferedWriter2 = Files.newBufferedWriter(path1)) { +- //chunkMap.dumpChunks(bufferedWriter2); // Paper - rewrite chunk system +- } +- +- Path path2 = path.resolve("entity_chunks.csv"); +- +- try (Writer bufferedWriter3 = Files.newBufferedWriter(path2)) { +- //this.entityManager.dumpSections(bufferedWriter3); // Paper - rewrite chunk system +- } +- +- Path path3 = path.resolve("entities.csv"); +- +- try (Writer bufferedWriter4 = Files.newBufferedWriter(path3)) { ++ try (Writer bufferedWriter4 = Files.newBufferedWriter(path.resolve("entities.csv"))) { + dumpEntities(bufferedWriter4, this.getEntities().getAll()); + } + +- Path path4 = path.resolve("block_entities.csv"); +- +- try (Writer bufferedWriter5 = Files.newBufferedWriter(path4)) { ++ try (Writer bufferedWriter5 = Files.newBufferedWriter(path.resolve("block_entities.csv"))) { + this.dumpBlockEntityTickers(bufferedWriter5); + } + } +@@ -2688,20 +_,12 @@ + @Override + public void onTrackingStart(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot +- // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true + if (entity instanceof ServerPlayer serverPlayer) { + ServerLevel.this.players.add(serverPlayer); + ServerLevel.this.updateSleepingPlayerList(); + } + + if (entity instanceof Mob mob) { +- if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning +- String string = "onTrackingStart called during navigation iteration"; +- Util.logAndPauseIfInIde( +- "onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration") +- ); +- } +- + ServerLevel.this.navigatingMobs.add(mob); + } + +@@ -2746,6 +_,7 @@ + } + } + // Spigot end ++ + // Spigot start + if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message + // Paper start - Fix merchant inventory not closing on entity removal +@@ -2765,13 +_,6 @@ + } + + if (entity instanceof Mob mob) { +- if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning +- String string = "onTrackingStart called during navigation iteration"; +- Util.logAndPauseIfInIde( +- "onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration") +- ); +- } +- + ServerLevel.this.navigatingMobs.remove(mob); + } + diff --git a/plazma-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch b/plazma-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch new file mode 100644 index 0000000..b6d9eaf --- /dev/null +++ b/plazma-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/Entity.java ++++ b/net/minecraft/world/entity/Entity.java +@@ -172,7 +_,7 @@ + // Paper - replace random + } + // Paper end - Share random for entities to make them more random +- public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason ++ public @Nullable org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason // Plazma - Null safety + + public boolean collisionLoadChunks = false; // Paper + private @Nullable org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity; diff --git a/plazma-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch b/plazma-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch index 838ce6b..8bbc8fc 100644 --- a/plazma-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch +++ b/plazma-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch @@ -23,6 +23,14 @@ protected float oRainLevel; public float rainLevel; protected float oThunderLevel; +@@ -144,6 +_,7 @@ + // CraftBukkit start Added the following + private final CraftWorld world; + public boolean pvpMode; ++ @Nullable // Plazma - Null safety + public org.bukkit.generator.ChunkGenerator generator; + + public boolean preventPoiUpdated = false; // CraftBukkit - SPIGOT-5710 @@ -152,6 +_,7 @@ public boolean isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent public Map capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper @@ -31,8 +39,17 @@ public List captureDrops; public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); // Paper start -@@ -171,11 +_,13 @@ +@@ -169,13 +_,22 @@ + } + // Paper end - add paper world config ++ // Plazma start - Configurable Plazma ++ private final org.plazmamc.plazma.configurations.WorldConfiguration plazmaConfig; ++ public org.plazmamc.plazma.configurations.WorldConfiguration plazmaConfig() { ++ return this.plazmaConfig; ++ } ++ // Plazma end - Configurable Plazma ++ public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur - Purpur config files + @Nullable // Plazma - Null safety @@ -119,6 +136,30 @@ } @Override +@@ -879,11 +_,11 @@ + boolean isDebug, + long biomeZoomSeed, + int maxChainedNeighborUpdates, +- org.bukkit.generator.ChunkGenerator gen, // CraftBukkit +- org.bukkit.generator.BiomeProvider biomeProvider, // CraftBukkit ++ org.bukkit.generator.@org.jspecify.annotations.Nullable ChunkGenerator gen, // CraftBukkit ++ org.bukkit.generator.@org.jspecify.annotations.Nullable BiomeProvider biomeProvider, // CraftBukkit + org.bukkit.World.Environment env, // CraftBukkit +- java.util.function.Function paperWorldConfigCreator, // Paper - create paper world config ++ java.util.function.Function paperWorldConfigCreator, // Paper - create paper world config ++ java.util.function.Supplier plazmaWorldConfigSupplier, // Plazma - Plazma config files + java.util.concurrent.Executor executor // Paper - Anti-Xray + ) { + // Paper start - getblock optimisations - cache world height/sections +@@ -897,6 +_,7 @@ + // Paper end - getblock optimisations - cache world height/sections + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot + this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config ++ this.plazmaConfig = plazmaWorldConfigSupplier.get(); // Plazma - Plazma config files + this.purpurConfig = new org.purpurmc.purpur.PurpurWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), env); // Purpur - Purpur config files + this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur - Add adjustable breeding cooldown to config + this.generator = gen; @@ -990,7 +_,7 @@ return true; } diff --git a/plazma-server/paper-patches/files/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java.patch b/plazma-server/paper-patches/files/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java.patch index c9166df..3ba3700 100644 --- a/plazma-server/paper-patches/files/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java.patch +++ b/plazma-server/paper-patches/files/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java.patch @@ -1,5 +1,16 @@ --- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +@@ -22,8 +_,8 @@ + import net.kyori.adventure.text.event.ClickEvent; + import net.kyori.adventure.text.format.NamedTextColor; + import net.kyori.adventure.text.format.TextDecoration; +-import org.checkerframework.checker.nullness.qual.NonNull; +-import org.checkerframework.checker.nullness.qual.Nullable; ++import org.jspecify.annotations.NonNull; // Plazma - Null safety ++import org.jspecify.annotations.Nullable; // Plazma - Null safety + import org.checkerframework.framework.qual.DefaultQualifier; + import org.slf4j.Logger; + @@ -36,7 +_,7 @@ private static final int DISTANCE_ERROR = -1; private static final int DISTANCE_UNKNOWN = -2; @@ -9,15 +20,18 @@ private static int distance = DISTANCE_UNKNOWN; public int distance() { return distance; } // Purpur end - Rebrand -@@ -52,7 +_,7 @@ +@@ -52,9 +_,9 @@ if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) { updateMessage = text("You are running a development version without access to version information", color(0xFF5300)); } else { - updateMessage = getUpdateStatusMessage("PurpurMC/Purpur", build); // Purpur - Rebrand + updateMessage = getUpdateStatusMessage("PlazmaMC/Plazma", build); // Purpur - Rebrand // Plazma - Configurable Plazma } - final @Nullable Component history = this.getHistory(); +- final @Nullable Component history = this.getHistory(); ++ final Component history = this.getHistory(); + return history != null ? Component.textOfChildren(updateMessage, Component.newline(), history) : updateMessage; + } @@ -87,23 +_,23 @@ } diff --git a/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/Configuration.java.patch b/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/Configuration.java.patch new file mode 100644 index 0000000..592aedb --- /dev/null +++ b/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/Configuration.java.patch @@ -0,0 +1,20 @@ +--- a/src/main/java/io/papermc/paper/configuration/Configuration.java ++++ b/src/main/java/io/papermc/paper/configuration/Configuration.java +@@ -1,11 +_,15 @@ + package io.papermc.paper.configuration; + ++@Deprecated(forRemoval = true) + public final class Configuration { ++ ++ @Deprecated(forRemoval = true) + public static final String VERSION_FIELD = "_version"; +- @Deprecated ++ ++ @Deprecated(forRemoval = true) + public static final String LEGACY_CONFIG_VERSION_FIELD = "config-version"; + +- @Deprecated ++ @Deprecated(forRemoval = true) + public static final int FINAL_LEGACY_VERSION = 27; + + private Configuration() { diff --git a/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/Configurations.java.patch b/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/Configurations.java.patch new file mode 100644 index 0000000..9cdb5a6 --- /dev/null +++ b/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/Configurations.java.patch @@ -0,0 +1,385 @@ +--- a/src/main/java/io/papermc/paper/configuration/Configurations.java ++++ b/src/main/java/io/papermc/paper/configuration/Configurations.java +@@ -31,33 +_,65 @@ + import org.spongepowered.configurate.util.CheckedFunction; + import org.spongepowered.configurate.yaml.YamlConfigurationLoader; + +-public abstract class Configurations { ++public abstract class Configurations { // Plazma ++ ++ public static final String CONFIG_DIR = "config"; + + private static final Logger LOGGER = LogUtils.getClassLogger(); + public static final String WORLD_DEFAULTS = "__world_defaults__"; + public static final ResourceLocation WORLD_DEFAULTS_KEY = ResourceLocation.fromNamespaceAndPath("configurations", WORLD_DEFAULTS); + protected final Path globalFolder; ++ + protected final Class globalConfigClass; +- protected final Class worldConfigClass; + protected final String globalConfigFileName; ++ protected final String globalConfigHeader; ++ protected final int globalConfigVersion; ++ ++ protected final Class worldConfigClass; + protected final String defaultWorldConfigFileName; ++ protected final String defaultWorldConfigHeader; + protected final String worldConfigFileName; ++ protected final java.util.function.Function worldConfigHeader; ++ protected final int worldConfigVersion; + +- public Configurations( ++ protected Configurations( // Plazma + final Path globalFolder, +- final Class globalConfigType, +- final Class worldConfigClass, ++ final Class globalConfigClass, + final String globalConfigFileName, ++ final String globalConfigHeader, ++ final int globalConfigVersion, ++ final Class worldConfigClass, + final String defaultWorldConfigFileName, +- final String worldConfigFileName ++ final String defaultWorldConfigHeader, ++ final String worldConfigFileName, ++ final java.util.function.Function worldConfigHeader, ++ final int worldConfigVersion + ) { ++ try { ++ if (!Files.isDirectory(globalFolder)) { ++ Files.createDirectories(globalFolder); ++ } ++ } catch (final IOException ex) { ++ throw new RuntimeException("Could not setup configurations", ex); ++ } ++ + this.globalFolder = globalFolder; +- this.globalConfigClass = globalConfigType; +- this.worldConfigClass = worldConfigClass; ++ ++ this.globalConfigClass = globalConfigClass; + this.globalConfigFileName = globalConfigFileName; ++ this.globalConfigHeader = globalConfigHeader; ++ this.globalConfigVersion = globalConfigVersion; ++ ++ this.worldConfigClass = worldConfigClass; + this.defaultWorldConfigFileName = defaultWorldConfigFileName; ++ this.defaultWorldConfigHeader = defaultWorldConfigHeader; + this.worldConfigFileName = worldConfigFileName; ++ this.worldConfigHeader = worldConfigHeader; ++ this.worldConfigVersion = worldConfigVersion; + } ++ ++ protected abstract G globalConfigInstance(); ++ protected abstract W worldConfigInstance(final ServerLevel level); + + protected ObjectMapper.Factory.Builder createObjectMapper() { + return ObjectMapper.factoryBuilder() +@@ -66,56 +_,34 @@ + } + + protected YamlConfigurationLoader.Builder createLoaderBuilder() { +- return ConfigurationLoaders.naturallySorted(); +- } +- +- protected abstract boolean isConfigType(final Type type); +- +- protected abstract int globalConfigVersion(); +- +- protected abstract int worldConfigVersion(); ++ return ConfigurationLoaders.naturallySorted().defaultOptions(this::defaultOptions); ++ } ++ ++ protected abstract ConfigurationOptions defaultOptions(final ConfigurationOptions options); ++ ++ protected boolean isConfigType(final Type type) { ++ return ConfigurationPart.class.isAssignableFrom(io.leangen.geantyref.GenericTypeReflector.erase(type)); ++ } + + protected ObjectMapper.Factory.Builder createGlobalObjectMapperFactoryBuilder() { +- return this.createObjectMapper(); ++ return this.createObjectMapper().addDiscoverer(io.papermc.paper.configuration.mapping.InnerClassFieldDiscoverer.globalConfig()); + } + + @MustBeInvokedByOverriders +- protected YamlConfigurationLoader.Builder createGlobalLoaderBuilder(RegistryAccess registryAccess) { +- return this.createLoaderBuilder(); +- } +- +- static CheckedFunction creator(final Class type, final boolean refreshNode) { +- return node -> { +- final T instance = node.require(type); +- if (refreshNode) { +- node.set(type, instance); +- } +- return instance; +- }; +- } +- +- static CheckedFunction reloader(Class type, T instance) { +- return node -> { +- ObjectMapper.Factory factory = (ObjectMapper.Factory) Objects.requireNonNull(node.options().serializers().get(type)); +- ObjectMapper.Mutable mutable = (ObjectMapper.Mutable) factory.get(type); +- mutable.load(instance, node); +- return instance; +- }; +- } +- +- public G initializeGlobalConfiguration(final RegistryAccess registryAccess) throws ConfigurateException { +- return this.initializeGlobalConfiguration(registryAccess, creator(this.globalConfigClass, true)); +- } +- +- private void trySaveFileNode(YamlConfigurationLoader loader, ConfigurationNode node, String filename) throws ConfigurateException { +- try { +- loader.save(node); +- } catch (ConfigurateException ex) { +- if (ex.getCause() instanceof AccessDeniedException) { +- LOGGER.warn("Could not save {}: Paper could not persist the full set of configuration settings in the configuration file. Any setting missing from the configuration file will be set with its default value in memory. Admins should make sure to review the configuration documentation at https://docs.papermc.io/paper/configuration for more details.", filename, ex); +- } else throw ex; +- } +- } ++ protected YamlConfigurationLoader.Builder createGlobalLoaderBuilder(final RegistryAccess registryAccess) { ++ return this.createLoaderBuilder().defaultOptions((options) -> ++ defaultGlobalOptions(options.header(this.globalConfigHeader), registryAccess) ++ ); ++ } ++ ++ protected abstract ConfigurationOptions defaultGlobalOptions(final ConfigurationOptions options, final RegistryAccess registryAccess); ++ ++ public void initializeGlobalConfiguration(final RegistryAccess registryAccess) throws ConfigurateException { ++ final G instance = this.initializeGlobalConfiguration(registryAccess, creator(this.globalConfigClass, true)); ++ this.setGlobalConfigInstance(instance); ++ } ++ ++ protected abstract void setGlobalConfigInstance(final G instance); + + protected G initializeGlobalConfiguration(final RegistryAccess registryAccess, final CheckedFunction creator) throws ConfigurateException { + final Path configFile = this.globalFolder.resolve(this.globalConfigFileName); +@@ -126,7 +_,7 @@ + final ConfigurationNode node; + if (Files.notExists(configFile)) { + node = CommentedConfigurationNode.root(loader.defaultOptions()); +- node.node(Configuration.VERSION_FIELD).raw(this.globalConfigVersion()); ++ node.node(Configuration.VERSION_FIELD).raw(this.globalConfigVersion); + GlobalConfiguration.isFirstStart = true; + } else { + node = loader.load(); +@@ -142,9 +_,9 @@ + final ConfigurationNode version = globalNode.node(Configuration.VERSION_FIELD); + if (version.virtual()) { + LOGGER.warn("The global config file didn't have a version set, assuming latest"); +- version.raw(this.globalConfigVersion()); +- } else if (version.getInt() > this.globalConfigVersion()) { +- LOGGER.error("Loading a newer configuration than is supported ({} > {})! You may have to backup & delete your global config file to start the server.", version.getInt(), this.globalConfigVersion()); ++ version.raw(this.globalConfigVersion); ++ } else if (version.getInt() > this.globalConfigVersion) { ++ LOGGER.error("Loading a newer configuration than is supported ({} > {})! You may have to backup & delete your global config file to start the server.", version.getInt(), this.globalConfigVersion); + } + } + +@@ -159,6 +_,36 @@ + .put(REGISTRY_ACCESS, registryAccess); + } + ++ protected ObjectMapper.Factory.Builder createWorldObjectMapperFactoryBuilder(final ContextMap contextMap) { ++ return this.createObjectMapper() ++ .addDiscoverer(io.papermc.paper.configuration.mapping.InnerClassFieldDiscoverer.worldConfig(this.worldConfigClass, createWorldConfigInstance(contextMap))); ++ } ++ ++ protected abstract W createWorldConfigInstance(final ContextMap contextMap); ++ ++ @MustBeInvokedByOverriders ++ protected YamlConfigurationLoader.Builder createWorldConfigLoaderBuilder(final ContextMap contextMap) { ++ return this.createLoaderBuilder().defaultOptions((options) -> ++ defaultWorldOptions(options.header(contextMap.require(WORLD_NAME).equals(WORLD_DEFAULTS) ? this.defaultWorldConfigHeader : this.worldConfigHeader.apply(contextMap)), contextMap) ++ ); ++ } ++ ++ protected abstract ConfigurationOptions defaultWorldOptions(final ConfigurationOptions options, final ContextMap contextMap); ++ ++ private DefaultWorldLoader createDefaultWorldLoader(final boolean requireFile, final ContextMap contextMap, final Path configFile) { ++ boolean willCreate = Files.notExists(configFile); ++ if (requireFile && willCreate) { ++ throw new IllegalStateException("World defaults configuration file '" + configFile + "' doesn't exist"); ++ } ++ return new DefaultWorldLoader( ++ this.createWorldConfigLoaderBuilder(contextMap) ++ .defaultOptions(this.applyObjectMapperFactory(this.createWorldObjectMapperFactoryBuilder(contextMap).build())) ++ .path(configFile) ++ .build(), ++ willCreate ++ ); ++ } ++ + public void initializeWorldDefaultsConfiguration(final RegistryAccess registryAccess) throws ConfigurateException { + final ContextMap contextMap = this.createDefaultContextMap(registryAccess) + .put(FIRST_DEFAULT) +@@ -168,7 +_,7 @@ + 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(this.worldConfigVersion); + } else { + this.verifyWorldConfigVersion(contextMap, node); + } +@@ -178,38 +_,17 @@ + this.trySaveFileNode(loader, node, configFile.toString()); + } + +- private DefaultWorldLoader createDefaultWorldLoader(final boolean requireFile, final ContextMap contextMap, final Path configFile) { +- boolean willCreate = Files.notExists(configFile); +- if (requireFile && willCreate) { +- throw new IllegalStateException("World defaults configuration file '" + configFile + "' doesn't exist"); +- } +- return new DefaultWorldLoader( +- this.createWorldConfigLoaderBuilder(contextMap) +- .defaultOptions(this.applyObjectMapperFactory(this.createWorldObjectMapperFactoryBuilder(contextMap).build())) +- .path(configFile) +- .build(), +- willCreate +- ); +- } +- +- private record DefaultWorldLoader(YamlConfigurationLoader loader, boolean isNewFile) { +- } +- +- protected ObjectMapper.Factory.Builder createWorldObjectMapperFactoryBuilder(final ContextMap contextMap) { +- return this.createObjectMapper(); +- } +- +- @MustBeInvokedByOverriders +- protected YamlConfigurationLoader.Builder createWorldConfigLoaderBuilder(final ContextMap contextMap) { +- return this.createLoaderBuilder(); +- } +- + // Make sure to run version transforms on the default world config first via #setupWorldDefaultsConfig +- public W createWorldConfig(final ContextMap contextMap) throws IOException { +- return this.createWorldConfig(contextMap, creator(this.worldConfigClass, false)); ++ public W createWorldConfig(final ContextMap contextMap) { ++ final String levelName = contextMap.require(WORLD_NAME); ++ try { ++ return this.createWorldConfig(contextMap, creator(this.worldConfigClass, false)); ++ } catch (IOException exception) { ++ throw new RuntimeException("Could not create world config for " + levelName, exception); ++ } + } + +- protected W createWorldConfig(final ContextMap contextMap, final CheckedFunction creator) throws IOException { ++ private W createWorldConfig(final ContextMap contextMap, final CheckedFunction creator) throws IOException { + Preconditions.checkArgument(!contextMap.isDefaultWorldContext(), "cannot create world map with default world context"); + final Path defaultsConfigFile = this.globalFolder.resolve(this.defaultWorldConfigFileName); + final YamlConfigurationLoader defaultsLoader = this.createDefaultWorldLoader(true, this.createDefaultContextMap(contextMap.require(REGISTRY_ACCESS)).build(), defaultsConfigFile).loader(); +@@ -219,7 +_,9 @@ + final Path dir = contextMap.require(WORLD_DIRECTORY); + final Path worldConfigFile = dir.resolve(this.worldConfigFileName); + if (Files.notExists(worldConfigFile)) { +- PaperConfigurations.createDirectoriesSymlinkAware(dir); ++ if (!Files.isDirectory(dir)) { ++ Files.createDirectories(dir); ++ } + Files.createFile(worldConfigFile); // create empty file as template + newFile = true; + } +@@ -230,7 +_,7 @@ + .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(this.worldConfigVersion); + } else { + this.verifyWorldConfigVersion(contextMap, worldNode); + } +@@ -248,17 +_,17 @@ + if (worldName.equals(WORLD_DEFAULTS)) { + LOGGER.warn("The world defaults config file didn't have a version set, assuming latest"); + } else { +- LOGGER.warn("The world config file for " + worldName + " didn't have a version set, assuming latest"); ++ LOGGER.warn("The world config file for {} didn't have a version set, assuming latest", worldName); + } +- version.raw(this.worldConfigVersion()); +- } else if (version.getInt() > this.worldConfigVersion()) { ++ version.raw(this.worldConfigVersion); ++ } else if (version.getInt() > this.worldConfigVersion) { + String msg = "Loading a newer configuration than is supported ({} > {})! "; + if (worldName.equals(WORLD_DEFAULTS)) { + msg += "You may have to backup & delete the world defaults config file to start the server."; + } else { + msg += "You may have to backup & delete the " + worldName + " config file to start the server."; + } +- LOGGER.error(msg, version.getInt(), this.worldConfigVersion()); ++ LOGGER.error(msg, version.getInt(), this.worldConfigVersion); + } + } + +@@ -278,6 +_,63 @@ + return level.levelStorageAccess.levelDirectory.path().resolve(this.worldConfigFileName); + } + ++ protected abstract ContextMap createWorldContextMap(final ServerLevel level); ++ ++ public void reloadConfigs(final net.minecraft.server.MinecraftServer server) { ++ try { ++ this.initializeGlobalConfiguration(server.registryAccess(), reloader(this.globalConfigClass, this.globalConfigInstance())); ++ this.initializeWorldDefaultsConfiguration(server.registryAccess()); ++ for (ServerLevel level : server.getAllLevels()) { ++ this.createWorldConfig(createWorldContextMap(level), reloader(this.worldConfigClass, this.worldConfigInstance(level))); ++ } ++ } catch (Exception ex) { ++ throw new RuntimeException("Could not reload paper configuration files", ex); ++ } ++ } ++ ++ @Deprecated ++ public final org.bukkit.configuration.file.YamlConfiguration createLegacyObject(final net.minecraft.server.MinecraftServer server) { ++ final org.bukkit.configuration.file.YamlConfiguration global = org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(this.globalFolder.resolve(this.globalConfigFileName).toFile()); ++ final org.bukkit.configuration.ConfigurationSection worlds = global.createSection("__________WORLDS__________"); ++ worlds.set("__defaults__", 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; ++ } ++ ++ private void trySaveFileNode(YamlConfigurationLoader loader, ConfigurationNode node, String filename) throws ConfigurateException { ++ try { ++ loader.save(node); ++ } catch (ConfigurateException ex) { ++ if (ex.getCause() instanceof AccessDeniedException) { ++ LOGGER.warn("Could not save {}: {} could not persist the full set of configuration settings in the configuration file. Any setting missing from the configuration file will be set with its default value in memory. Admins should make sure to review the configuration documentation at https://docs.papermc.io/paper/configuration for more details.", io.papermc.paper.ServerBuildInfo.buildInfo().brandName(), filename, ex); ++ } else throw ex; ++ } ++ } ++ ++ private static CheckedFunction creator(final Class type, final boolean refreshNode) { ++ return node -> { ++ final T instance = node.require(type); ++ if (refreshNode) { ++ node.set(type, instance); ++ } ++ return instance; ++ }; ++ } ++ ++ private static CheckedFunction reloader(Class type, T instance) { ++ return node -> { ++ ObjectMapper.Factory factory = (ObjectMapper.Factory) Objects.requireNonNull(node.options().serializers().get(type)); ++ ObjectMapper.Mutable mutable = (ObjectMapper.Mutable) factory.get(type); ++ mutable.load(instance, node); ++ return instance; ++ }; ++ } ++ ++ private record DefaultWorldLoader(YamlConfigurationLoader loader, boolean isNewFile) { ++ } ++ + public static class ContextMap { + private static final Object VOID = new Object(); + +@@ -344,6 +_,7 @@ + public static final ContextKey FIRST_DEFAULT = new ContextKey<>(Void.class, "first default"); + public static final ContextKey REGISTRY_ACCESS = new ContextKey<>(RegistryAccess.class, "registry access"); + public static final ContextKey GAME_RULES = new ContextKey<>(GameRules.class, "game rules"); ++ public static final String VERSION_FIELD = "_version"; + + public record ContextKey(TypeToken type, String name) { + diff --git a/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java.patch b/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java.patch new file mode 100644 index 0000000..629ae22 --- /dev/null +++ b/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java.patch @@ -0,0 +1,415 @@ +--- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java ++++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +@@ -83,62 +_,6 @@ + @SuppressWarnings("Convert2Diamond") + public class PaperConfigurations extends Configurations { + +- private static final Logger LOGGER = LogUtils.getClassLogger(); +- static final String GLOBAL_CONFIG_FILE_NAME = "paper-global.yml"; +- static final String WORLD_DEFAULTS_CONFIG_FILE_NAME = "paper-world-defaults.yml"; +- static final String WORLD_CONFIG_FILE_NAME = "paper-world.yml"; +- public static final String CONFIG_DIR = "config"; +- private static final String BACKUP_DIR ="legacy-backup"; +- +- private static final String GLOBAL_HEADER = String.format(""" +- This is the global configuration file for Paper. +- 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 Paper, +- join us in our Discord or check the docs page. +- +- The world configuration options have been moved inside +- their respective world folder. The files are named %s +- +- Docs: https://docs.papermc.io/ +- Discord: https://discord.gg/papermc +- Website: https://papermc.io/""", WORLD_CONFIG_FILE_NAME); +- +- private static final String WORLD_DEFAULTS_HEADER = """ +- This is the world defaults configuration file for Paper. +- 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 Paper, +- join us in our Discord or check the docs page. +- +- Configuration options here apply to all worlds, unless you specify overrides inside +- the world-specific config file inside each world folder. +- +- Docs: https://docs.papermc.io/ +- Discord: https://discord.gg/papermc +- Website: https://papermc.io/"""; +- +- private static final Function WORLD_HEADER = map -> String.format(""" +- This is a world configuration file for Paper. +- This file may start empty but can be filled with settings to override ones in the %s/%s +- +- World: %s (%s)""", +- PaperConfigurations.CONFIG_DIR, +- PaperConfigurations.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://docs.papermc.io/paper/configuration for more information. +- """; +- + @VisibleForTesting + public static final Supplier SPIGOT_WORLD_DEFAULTS = Suppliers.memoize(() -> new SpigotWorldConfig(RandomStringUtils.randomAlphabetic(255)) { + @Override // override to ensure "verbose" is false +@@ -148,28 +_,71 @@ + }); + public static final ContextKey> SPIGOT_WORLD_CONFIG_CONTEXT_KEY = new ContextKey<>(new TypeToken>() {}, "spigot world config"); + +- +- public PaperConfigurations(final Path globalFolder) { +- super(globalFolder, GlobalConfiguration.class, WorldConfiguration.class, GLOBAL_CONFIG_FILE_NAME, WORLD_DEFAULTS_CONFIG_FILE_NAME, WORLD_CONFIG_FILE_NAME); +- } +- +- @Override +- protected int globalConfigVersion() { +- return GlobalConfiguration.CURRENT_VERSION; +- } +- +- @Override +- protected int worldConfigVersion() { +- return WorldConfiguration.CURRENT_VERSION; +- } +- +- @Override +- protected YamlConfigurationLoader.Builder createLoaderBuilder() { +- return super.createLoaderBuilder() +- .defaultOptions(PaperConfigurations::defaultOptions); +- } +- +- private static ConfigurationOptions defaultOptions(ConfigurationOptions options) { ++ private PaperConfigurations(final Path globalFolder) { // Plazma ++ super( ++ globalFolder, ++ ++ GlobalConfiguration.class, ++ "paper-global.yml", ++ """ ++ This is the global configuration file for Paper. ++ 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 Paper, ++ join us in our Discord or check the docs page. ++ ++ The world configuration options have been moved inside ++ their respective world folder. The files are named paper-world.yml. ++ ++ Docs: https://docs.papermc.io/ ++ Discord: https://discord.gg/papermc ++ Website: https://papermc.io/""", ++ GlobalConfiguration.CURRENT_VERSION, ++ ++ WorldConfiguration.class, ++ "paper-world-defaults.yml", ++ """ ++ This is the world defaults configuration file for Paper. ++ 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 Paper, ++ join us in our Discord or check the docs page. ++ ++ Configuration options here apply to all worlds, unless you specify overrides inside ++ the world-specific config file inside each world folder. ++ ++ Docs: https://docs.papermc.io/ ++ Discord: https://discord.gg/papermc ++ Website: https://papermc.io/""", ++ "paper-world.yml", ++ (map) -> String.format(""" ++ This is a world configuration file for Paper. ++ This file may start empty but can be filled with settings to override ones in the %s/%s ++ ++ World: %s (%s)""", ++ CONFIG_DIR, ++ "paper-world-defaults.yml", ++ map.require(WORLD_NAME), ++ map.require(WORLD_KEY) ++ ), ++ WorldConfiguration.CURRENT_VERSION ++ ); ++ } ++ ++ @Override ++ protected GlobalConfiguration globalConfigInstance() { ++ return GlobalConfiguration.get(); ++ } ++ ++ @Override ++ protected WorldConfiguration worldConfigInstance(final ServerLevel level) { ++ return level.paperConfig(); ++ } ++ ++ @Override ++ protected ConfigurationOptions defaultOptions(ConfigurationOptions options) { + return options.serializers(builder -> builder + .register(MapSerializer.TYPE, new MapSerializer(false)) + .register(new EnumValueSerializer()) +@@ -187,23 +_,8 @@ + } + + @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(RegistryAccess registryAccess) { +- return super.createGlobalLoaderBuilder(registryAccess) +- .defaultOptions((options) -> defaultGlobalOptions(registryAccess, options)); +- } +- +- private static ConfigurationOptions defaultGlobalOptions(RegistryAccess registryAccess, ConfigurationOptions options) { ++ protected ConfigurationOptions defaultGlobalOptions(final ConfigurationOptions options, final RegistryAccess registryAccess) { + return options +- .header(GLOBAL_HEADER) + .serializers(builder -> builder + .register(new PacketClassSerializer()) + .register(new RegistryValueSerializer<>(new TypeToken>() {}, registryAccess, Registries.DATA_COMPONENT_TYPE, false)) +@@ -211,10 +_,8 @@ + } + + @Override +- public GlobalConfiguration initializeGlobalConfiguration(final RegistryAccess registryAccess) throws ConfigurateException { +- GlobalConfiguration configuration = super.initializeGlobalConfiguration(registryAccess); ++ protected void setGlobalConfigInstance(final GlobalConfiguration configuration) { + GlobalConfiguration.set(configuration); +- return configuration; + } + + @Override +@@ -227,11 +_,11 @@ + protected ObjectMapper.Factory.Builder createWorldObjectMapperFactoryBuilder(final ContextMap contextMap) { + return super.createWorldObjectMapperFactoryBuilder(contextMap) + .addNodeResolver(new RequiresSpigotInitialization.Factory(contextMap.require(SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get())) +- .addNodeResolver(new NestedSetting.Factory()) +- .addDiscoverer(InnerClassFieldDiscoverer.worldConfig(createWorldConfigInstance(contextMap))); ++ .addNodeResolver(new NestedSetting.Factory()); + } + +- private static WorldConfiguration createWorldConfigInstance(ContextMap contextMap) { ++ @Override ++ protected WorldConfiguration createWorldConfigInstance(final ContextMap contextMap) { + return new WorldConfiguration( + contextMap.require(PaperConfigurations.SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get(), + contextMap.require(Configurations.WORLD_KEY) +@@ -239,26 +_,22 @@ + } + + @Override +- protected YamlConfigurationLoader.Builder createWorldConfigLoaderBuilder(final ContextMap contextMap) { ++ protected ConfigurationOptions defaultWorldOptions(final ConfigurationOptions options, 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 FastutilMapSerializer.SomethingToSomething>(Reference2ObjectOpenHashMap::new)) +- .register(new TypeToken>() {}, new TableSerializer()) +- .register(DespawnRange.class, DespawnRange.SERIALIZER) +- .register(StringRepresentableSerializer::isValidFor, new StringRepresentableSerializer()) +- .register(EngineMode.SERIALIZER) +- .register(FallbackValueSerializer.create(contextMap.require(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 RegistryValueSerializer<>(Block.class, access, Registries.BLOCK, true)) +- .register(new RegistryHolderSerializer<>(new TypeToken>() {}, access, Registries.CONFIGURED_FEATURE, false)) +- ) +- ); ++ return options.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 FastutilMapSerializer.SomethingToSomething>(Reference2ObjectOpenHashMap::new)) ++ .register(new TypeToken>() {}, new TableSerializer()) ++ .register(DespawnRange.class, DespawnRange.SERIALIZER) ++ .register(StringRepresentableSerializer::isValidFor, new StringRepresentableSerializer()) ++ .register(EngineMode.SERIALIZER) ++ .register(FallbackValueSerializer.create(contextMap.require(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 RegistryValueSerializer<>(Block.class, access, Registries.BLOCK, true)) ++ .register(new RegistryHolderSerializer<>(new TypeToken>() {}, access, Registries.CONFIGURED_FEATURE, false)) ++ ); + } + + @Override +@@ -305,33 +_,7 @@ + } + + @Override +- public WorldConfiguration 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 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(server.registryAccess(), reloader(this.globalConfigClass, GlobalConfiguration.get())); +- this.initializeWorldDefaultsConfiguration(server.registryAccess()); +- for (ServerLevel level : server.getAllLevels()) { +- this.createWorldConfig(createWorldContextMap(level), reloader(this.worldConfigClass, level.paperConfig())); +- } +- } catch (Exception ex) { +- throw new RuntimeException("Could not reload paper configuration files", ex); +- } +- } +- +- private static ContextMap createWorldContextMap(ServerLevel level) { ++ protected ContextMap createWorldContextMap(final ServerLevel level) { + return createWorldContextMap(level.levelStorageAccess.levelDirectory.path(), level.serverLevelData.getLevelName(), level.dimension().location(), level.spigotConfig, level.registryAccess(), level.getGameRules()); + } + +@@ -347,102 +_,10 @@ + } + + public static PaperConfigurations setup(final Path legacyConfig, final Path configDir, final Path worldFolder, final File spigotConfig) throws Exception { +- final Path legacy = Files.isSymbolicLink(legacyConfig) ? Files.readSymbolicLink(legacyConfig) : legacyConfig; +- if (needsConverting(legacyConfig)) { +- final String legacyFileName = legacyConfig.getFileName().toString(); +- try { +- if (Files.exists(configDir) && !Files.isDirectory(configDir)) { +- throw new RuntimeException("Paper needs to create a '" + configDir.toAbsolutePath() + "' folder. You already have a non-directory named '" + configDir.toAbsolutePath() + "'. Please remove it and restart the server."); +- } +- final Path backupDir = configDir.resolve(BACKUP_DIR); +- if (Files.exists(backupDir) && !Files.isDirectory(backupDir)) { +- throw new RuntimeException("Paper needs to create a '" + BACKUP_DIR + "' directory in the '" + configDir.toAbsolutePath() + "' folder. You already have a non-directory named '" + BACKUP_DIR + "'. Please remove it and restart the server."); +- } +- createDirectoriesSymlinkAware(backupDir); +- final String backupFileName = legacyFileName + ".old"; +- final Path legacyConfigBackup = backupDir.resolve(backupFileName); +- if (Files.exists(legacyConfigBackup) && !Files.isRegularFile(legacyConfigBackup)) { +- throw new RuntimeException("Paper needs to create a '" + backupFileName + "' file in the '" + backupDir.toAbsolutePath() + "' folder. You already have a non-file named '" + backupFileName + "'. Please remove it and restart the server."); +- } +- Files.move(legacyConfig.toRealPath(), legacyConfigBackup, StandardCopyOption.REPLACE_EXISTING); // make backup +- if (Files.isSymbolicLink(legacyConfig)) { +- Files.delete(legacyConfig); +- } +- final Path replacementFile = legacy.resolveSibling(legacyFileName + "-README.txt"); +- if (Files.notExists(replacementFile)) { +- Files.createFile(replacementFile); +- Files.writeString(replacementFile, String.format(MOVED_NOTICE, configDir.toAbsolutePath())); +- } +- convert(legacyConfigBackup, configDir, worldFolder, spigotConfig); +- } catch (final IOException ex) { +- throw new RuntimeException("Could not convert '" + legacyFileName + "' to the new configuration format", ex); +- } +- } +- try { +- createDirectoriesSymlinkAware(configDir); +- return new PaperConfigurations(configDir); +- } catch (final IOException ex) { +- throw new RuntimeException("Could not setup PaperConfigurations", ex); +- } +- } +- +- private static void convert(final Path legacyConfig, final Path configDir, final Path worldFolder, final File spigotConfig) throws Exception { +- createDirectoriesSymlinkAware(configDir); +- +- final YamlConfigurationLoader legacyLoader = ConfigurationLoaders.naturallySortedWithoutHeader(legacyConfig); +- final YamlConfigurationLoader globalLoader = ConfigurationLoaders.naturallySortedWithoutHeader(configDir.resolve(GLOBAL_CONFIG_FILE_NAME)); +- final YamlConfigurationLoader worldDefaultsLoader = ConfigurationLoaders.naturallySortedWithoutHeader(configDir.resolve(WORLD_DEFAULTS_CONFIG_FILE_NAME)); +- +- final ConfigurationNode legacy = legacyLoader.load(); +- checkState(!legacy.virtual(), "can't be virtual"); +- final int version = legacy.node(Configuration.LEGACY_CONFIG_VERSION_FIELD).getInt(); +- +- final ConfigurationNode legacyWorldSettings = legacy.node("world-settings").copy(); +- checkState(!legacyWorldSettings.virtual(), "can't be virtual"); +- legacy.removeChild("world-settings"); +- +- // Apply legacy transformations before settings flatten +- final YamlConfiguration spigotConfiguration = loadLegacyConfigFile(spigotConfig); // needs to change spigot config values in this transformation +- LegacyPaperConfig.transformation(spigotConfiguration).apply(legacy); +- spigotConfiguration.save(spigotConfig); +- legacy.mergeFrom(legacy.node("settings")); // flatten "settings" to root +- legacy.removeChild("settings"); +- LegacyPaperConfig.toNewFormat().apply(legacy); +- globalLoader.save(legacy); // save converted node to new global location +- +- final ConfigurationNode worldDefaults = legacyWorldSettings.node("default").copy(); +- checkState(!worldDefaults.virtual()); +- worldDefaults.node(Configuration.LEGACY_CONFIG_VERSION_FIELD).raw(version); +- legacyWorldSettings.removeChild("default"); +- LegacyPaperWorldConfig.transformation().apply(worldDefaults); +- LegacyPaperWorldConfig.toNewFormat().apply(worldDefaults); +- worldDefaultsLoader.save(worldDefaults); +- +- legacyWorldSettings.childrenMap().forEach((world, legacyWorldNode) -> { +- try { +- legacyWorldNode.node(Configuration.LEGACY_CONFIG_VERSION_FIELD).raw(version); +- LegacyPaperWorldConfig.transformation().apply(legacyWorldNode); +- LegacyPaperWorldConfig.toNewFormat().apply(legacyWorldNode); +- ConfigurationLoaders.naturallySortedWithoutHeader(worldFolder.resolve(world.toString()).resolve(WORLD_CONFIG_FILE_NAME)).save(legacyWorldNode); // save converted node to new location +- } catch (final ConfigurateException ex) { +- ex.printStackTrace(); +- } +- }); +- } +- +- private static boolean needsConverting(final Path legacyConfig) { +- return Files.exists(legacyConfig) && Files.isRegularFile(legacyConfig); +- } +- +- @Deprecated +- public YamlConfiguration createLegacyObject(final MinecraftServer server) { +- YamlConfiguration global = YamlConfiguration.loadConfiguration(this.globalFolder.resolve(this.globalConfigFileName).toFile()); +- ConfigurationSection worlds = global.createSection("__________WORLDS__________"); +- worlds.set("__defaults__", 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; ++ if (Files.exists(legacyConfig) && Files.isRegularFile(legacyConfig)) { ++ throw new RuntimeException("Since Plazma 1.21.4, support for the conversion of legacy paper configuration has been terminated. Remove the legacy paper configuration file or use the previous version of Plazma and convert the configuration first."); ++ } ++ return new PaperConfigurations(configDir); + } + + @Deprecated +@@ -460,16 +_,12 @@ + + @VisibleForTesting + static ConfigurationNode createForTesting(RegistryAccess registryAccess) { ++ throw new UnsupportedOperationException("Not implemented yet"); ++ /* + ObjectMapper.Factory factory = defaultGlobalFactoryBuilder(ObjectMapper.factoryBuilder()).build(); + ConfigurationOptions options = defaultGlobalOptions(registryAccess, defaultOptions(ConfigurationOptions.defaults())) + .serializers(builder -> builder.register(type -> ConfigurationPart.class.isAssignableFrom(erase(type)), factory.asTypeSerializer())); + return BasicConfigurationNode.root(options); +- } +- +- // Symlinks are not correctly checked in createDirectories +- static void createDirectoriesSymlinkAware(Path path) throws IOException { +- if (!Files.isDirectory(path)) { +- Files.createDirectories(path); +- } ++ */ + } + } diff --git a/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java.patch b/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java.patch new file mode 100644 index 0000000..e239b6e --- /dev/null +++ b/plazma-server/paper-patches/files/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java.patch @@ -0,0 +1,16 @@ +--- a/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java ++++ b/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java +@@ -39,11 +_,8 @@ + return null; + } + +- public static FieldDiscoverer worldConfig(WorldConfiguration worldConfiguration) { +- final Map, Object> overrides = Map.of( +- WorldConfiguration.class, worldConfiguration +- ); +- return new InnerClassFieldDiscoverer(overrides); ++ public static FieldDiscoverer worldConfig(final Class worldConfigClass, final W worldConfiguration) { ++ return new InnerClassFieldDiscoverer(Map.of(worldConfigClass, worldConfiguration)); + } + + public static FieldDiscoverer globalConfig() { diff --git a/plazma-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch b/plazma-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch new file mode 100644 index 0000000..fecc260 --- /dev/null +++ b/plazma-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch @@ -0,0 +1,24 @@ +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1102,6 +_,7 @@ + + org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot + this.console.paperConfigurations.reloadConfigs(this.console); ++ this.console.plazmaConfigurations.reloadConfigs(this.console); + org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur - Purpur config files + for (ServerLevel world : this.console.getAllLevels()) { + // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty +@@ -3133,6 +_,13 @@ + return getProperties().properties; + } + // Purpur end - Purpur config files ++ ++ // Plazma start - Configurable Plazma ++ @Override ++ public YamlConfiguration getPlazmaConfig() { ++ return CraftServer.this.console.plazmaConfigurations.createLegacyObject(CraftServer.this.console); ++ } ++ // Plazma end - Configurable Plazma + + @Override + public void restart() { diff --git a/plazma-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/Main.java.patch b/plazma-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/Main.java.patch index 6ea9773..cb3ebf4 100644 --- a/plazma-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/Main.java.patch +++ b/plazma-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/Main.java.patch @@ -23,9 +23,49 @@ this.acceptsAll(Main.asList("demo"), "Demo mode"); -@@ -183,13 +_,6 @@ - .defaultsTo(new File("purpur.yml")) - .describedAs("Yml file"); +@@ -159,16 +_,15 @@ + + // Paper start + acceptsAll(asList("paper-dir", "paper-settings-directory"), "Directory for Paper settings") +- .withRequiredArg() +- .ofType(File.class) +- .defaultsTo(new File(io.papermc.paper.configuration.PaperConfigurations.CONFIG_DIR)) +- .describedAs("Config directory"); ++ .withRequiredArg() ++ .ofType(File.class) ++ .defaultsTo(new File(io.papermc.paper.configuration.PaperConfigurations.CONFIG_DIR)) ++ .describedAs("Config directory"); + acceptsAll(asList("paper", "paper-settings"), "File for Paper settings") + .withRequiredArg() + .ofType(File.class) + .defaultsTo(new File("paper.yml")) + .describedAs("Yml file"); +- + acceptsAll(asList("add-plugin", "add-extra-plugin-jar"), "Specify paths to extra plugin jars to be loaded in addition to those in the plugins folder. This argument can be specified multiple times, once for each extra plugin jar path.") + .withRequiredArg() + .ofType(File.class) +@@ -176,20 +_,21 @@ + .describedAs("Jar file"); + // Paper end + ++ // Plazma start - Configurable Plazma ++ acceptsAll(asList("plazma-dir", "plazma-settings-dir", "plazma-settings-directory"), "Directory for Plazma settings") ++ .withRequiredArg() ++ .ofType(File.class) ++ .defaultsTo(new File(io.papermc.paper.configuration.PaperConfigurations.CONFIG_DIR)) ++ .describedAs("Config directory"); ++ // Plazma end - Configurable Plazma ++ + // Purpur start - Purpur config files + acceptsAll(asList("purpur", "purpur-settings"), "File for purpur settings") +- .withRequiredArg() +- .ofType(File.class) +- .defaultsTo(new File("purpur.yml")) +- .describedAs("Yml file"); ++ .withRequiredArg() ++ .ofType(File.class) ++ .defaultsTo(new File("purpur.yml")) ++ .describedAs("Yml file"); // Purpur end - Purpur config files - // Paper start - acceptsAll(asList("server-name"), "Name of the server") diff --git a/plazma-server/src/main/resources/icon.png b/plazma-server/src/main/resources/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..efa53bcb692650396b2e71b62243a15dd95aa096 GIT binary patch literal 7439 zcmbVR2{@GP-XHrOqAXd4vQ@*(FwBg7H)RWzq?$1cV;jsEgUC>Xv{*uxlATr*5!qAr zB|8nGvP&US-{|e_yytx9J>R*$xvpoPd+z6V|Nh(Wf8W=0O|-4Gxd5*uF8}}#Kv|gB zG4BRD7dI#KyNKvJ&b;yXSezmQ0IK_UE*4s@J{17q0uvn^DUMc_NG!=q6@w$W;8kf} zK1?(KprcRo!C*b`6rc;X4sM7!v%? zP^N5f7z*b91mmzs0?E${!;G2eg>l8J`FOj^1Ak`{X-x7Y`7sSMy;J||Jj&SE){jIW zdNLo7?aYmUC{tri2trd61XYFnbl1uXiSi~>Fy2@^%0yS5nIBam5r-te@EULzm^uiD z)o=m15Ht`Vj0P3~f@&hba6AN}1xL92x!#0?_1{s!&iX$(0!P9!IsV}uoZzBKAmCsi zu#2V!$OWf?1;I7JFc1Q(fxzMjFinU$^iMV$KO(a!F`j>A-SG;?WYogAz;Sq{FX}D? z9LPnBIYJN!%wpi-aGW|A4@GETc9j29Oh^kNnOWw*U%h0H_x&~UBm#fx2Z_P%^o6cG zc1I9+ocyn8;=jqqe`WdC`T#dPlk`8R=-@qT}a zzz5@pVQxuyKeDbo!H?tx#Q6Al60w+_aMh^ZxL=L_yFfq+3HT3P{jD7`hWekg1i>I& z)FChk2#--$2N7H}Fdz&ZiUGkPV5}xo6OPfuFje_lbr!D?~ z7HL0qL&9#b0Z$e;dynQ_JpDd2(e|>_U4@+VM+OUdl^`LLJD}Kn&mxZEq{Vvo!={FD z;Xsf&Z%lzL5069`d&_w;nN%@_2(I3KIlPrlj=CPk^P?{)b9=tJ^HJyK_?P=j!7l>t zW8*j0N8=x>jfM^naElj8)EUl}cmQG9?q=Zqu#&m?^cS~7%H3^Y+>J{P?G|+2r)BQn zTt$){Fsq77g|!Y`=eWE9GKdsTed^qn`B+uNS1i_PpHFqx%WC+5;WeeJ1}xM-I2SF2 zyZ)V4kv&Ni&??Zcz2VFX@0+TVx=v^CK7!4)onxD$+tdh4YqtOfiM1lTY9?|ERksWU zJNECscx|1w%u$QwM$-4u-?A(rQ*?D40aBdbic$LHM~x^rP+v>jDxT$r0kzQs1Bj(p zg)Om}OI^7tV+&x%Gh!n%zf5jtR(4wtxxHT>>UN{;IwDu46b|rFeZ*O@%T4!sh~9O8 zGx||SmKyB_{GwR4S!f?Z`+0%%*AMT3G!x@^O~wo1sfJ5jMZH|CVF^|`=w*-+0a5GT zY{PFfCF=G$QtIO7XJFc{>|qLn;8LkGEx7PambLb9tn}C12>UbHb;H`+oQ@G(@W}~s z!#b-`1Epo;bXZgviDmWNL*a*FVV&jy@9Rff+|UGgFjt+qpj!aLJzKRcx)5tv@G@$H zKaPuq!HNd?D2Uvl)B;*YmpvoiL_YApJ8v|${1|wJHD{MmQ-iwoCOyH-64HgR&>fv= zJb2BlImpQD=GqJoj&vr8#do|8z@RbCM#v(G-EI*|oLN+XkVtRpq?9q4o*jLU)X0M8 zV9jCa5c?(!9>~%^%DBC|yO-N2UU&6)QSzl)uiEX}9yS&Ou}N8h?dH1Mnw-#9bEijQ zHndk+N3GhpZeqUy23dXid++6a;8)4uO%y#dj`rZyKQbZ0xhk?!$nMpaZzPu{x#dP; zli~UvEv|7+3?Rlfm+_e>=5oXj$8wmh&W6DQ;hsIT*L;c-Eq0xS;MlOtVL;G8mB}GR zKXB7EqvK7&#$%=wmG%Zv7CxjrI=6srEc=>T9fFnz=d%Qb6Hwj5X~Fkls{^ zfs3>Nbj8{_Uee_AArP6yBVdnGI!CQe!~-Gv;2v}~I)pXtxrqeiVzz!Q@PvTRGxN7x zTf2M?7$~s$%HH3z!Np*!9ja}8$Qu^jnn9F!mR09c(eYp!+6xuB&MkZ~>SDD$n7tco zcS@#|@N(A&&jxD^A8R8*#XREmBAbpd!T2(;*I-FWs*a!jqjzyhi+KJej;8n&9}ByFF9>DrOY7ZDfe@26GXd4L_D>@JfA); z4-a;kKmdMIh3!j7?h?4PrOfi&kB;>br}ql zQIRnUo0Y+|uU`-D>)&-h6t8?Q6ZvF0Dd$6tLDzACOh5^r{ZuadgIRvMbcfuEt;;6M zVDP?32pi^Y_!2w7pvCUwV62j(P{%y08ss`0oGnf{ANGQcO=Pd3IF;kV+Tz0YdQPEh ze^q|ZnruwlDV?~wyalOojf}6BZ2k4NhdQ@w>bC>DrsyxX5=G}@6SQNl36-&y_H)`) zKw+V0ugiGx(a(}oHVU+=PiD_Z#uWzqV7YAa(j92|jtBj=T&!674Ch_zPw$=6t6 z%LCE+#P_k)FG!jF&6AzduX4(f)RUD%t9DPYy$MbDk+J28eIo(tg^o@a=F{ILM`iSl zk_YcXV=t7%{sY>mTm#N*Vs1Qe7tEvrOoZ8c+4#Mp;$S3v&HfK!^Qok zi!e@&a4=ozeA9lj=dCePA@G!TuXmg`H^}SHyH>Y4QoYi*+SiYz_P5*54OqY3;9JkF z1HD;wI;uXbwfJEwV0#4hT46Cmr!Qc%{>IXa1@0=BS0ks(+w@nwoI~10JVS{Cv&ODZ zGYny)m)=}S%XGQ@$p;&2A{!YsXLa60^9YLdb5SOkMX;r)B7Nz-%Hz<`R~*}B24H3O ziAMkIJ{i}56O~+xZtkjn{Q^t)=CTw0y44Gxr4R9XxURK3h0aa}E|9z*_8_{9w_0Rk z*mONd21lrKHe0ICXP(wQIh`qWK42hi#;3_Yzq`-j4r#s1rh27%m;{hHBXAc*H=5r( zC^#1nIgZO|Zyv9oq{#@03c^HnQ&)z*Mxk2rF7b<%_2n3^c1kdMmZRO*flBA7yyW** z6CdN|uFX{ke8|MQ%JxtvPv_eOQbmeo&folAV;HZ|bh4=I)FqW^xy;eQk)Q?LhJZD_ z)t-2jQl-_E>DZ5BurQ7@qb(xN2Vf+duy~`HC!3ghlUz!NNOJ^uoDDsH`5MOrDqoxc zJ^udrvD;C>2emoR-3qPO$g6hc?Oc0UJ|;-2np=LLNst+P)f{}HWM<-t!(l!3`#BEg zMOUsk_$DPjuwxWvY=2u_@83=wtNPXxAp6SqD50b{7#)?cC~lg`kP=Kx+H-oc+*|GL z5jp#ewFMSC4NVi0xM28+>CTnz4^45sja*}rXA2)O&a9?droJxKm0cJtG$y3$#AYU` zm458@zi1R*%y}M`d!3V)SbI>Vh|?(|Wq2~s$E&mN&5O~J^qiIw5duUfev+Y$bzAkt zHJb`2U1&`u>@r%o6|J&L6SN>w){jAIO=g?;0v+O<&yw7)NJu_-;GXG3sOym^13KN7 z{f;iYkTM}wHS~Rhvj<>mS`KnOeomrkPRPxOa=;e0@~%i)*0NmCXCvJ@kCMofM0q1V z{JiDB?Y<`$<77CS!@EB4U`Lo$Epc924dzx%*D@GmAMui?f_1B;EJDX4jurBI*w6Lt zmVQMYEG;dF3;s^S*~_N&d)~bO&wcjH!jwfRibIZLSv6k}*o`v_uInCCr#UZeW>`Il z-$i|z^kHFNs2s{!p8z`5{86+GOdEPBne+CFG@9&Drris~K@t{30Ii}j;CH4#vu>eR zoxr?ZIc8VRF z9L$ZEzNTnHo^+DAfNn_CxF}|2yX@W4;GJ{RNkyRjbxr1wPU1f6h>6`faqey7EG-vb zw~3@*yBonLl+N4ICiOZKhLiB+Ux~W)yxdQm_u&<=$=JmFWqy zqvtZD{EktMap#ODq(GX`?j9mu_nT&)Hz2oIC(AtoT!^!0CU2Fp#%T2OCIOzz?zUh* zRT~S;*?TFSXZ|*j6Ia)nn9=*~tmBmP=|W z!Od&@$0%mP%7NyP%SH;hmz9%u--^kc3D0lZw{Us?j5T5Lu7u^mE!VvnIu8SepR1a2 znklEWe=1Pd>OZ<|J$&n-+JS-(-HGX~8qIVa?Rk+fUkM;?Je9+1AH8-y!oB6Hvsrz1IR}`wS(GIc(|9$KcHe5{x!-O&oEB^8p;CfI zrPnVgl-K)fmVSKZy;-@XqTqcjJClLVh{~#v6m7wPzL44nDG_LkN)QY#DO`U-$ARnmTvot#UJR&N4uDJ8- zL5JtoP@y$l4!?s^k_O!VLe30FkpqRFL<3#3?QlID_j{FKUYkSeo}q5K(+!nW|1+PS zzIX)F_Nn4jRy2F|f#?nD9(B0$EXCGHv{)rdMm=FIHN!I$Ef6KEwWX#c8`9DNyH;I$ z>l`VkxLCor=hLx6Ry|`fa;65)cLH!(&#*t>1zd>R}!EFJmGMr@zG$B z(?8xG$?IHr{;6PHI-qqqQ~1Q_GSF20NOV=bp}lIc#1WB=Okwroa()r(S00GXW?r|6 z3JEqSkcgL%HG6C*_L*S(^1vH|_{aiU^h3?P#yOjwt#S+I^MN&KQ9m}RMZuB8(>3#z zd7a;1N#r6DZmSCL+mGrR_!bzQq7&E#Mr?lEYCoh+u+iHpP`_3!Sr_nQ?dAM%UwdNV zeKPk1-_Y~UCrxR*yl)a66BQ=8l|a(QNgkODMd;1y+&ZDuI7I7ZTYy+JUxzKjDB+Bq zBu~z`kIyCCZ9cnh99+o=7IG(~u8-ri%ov!`x%DG8Tg}OAU?_HJUf+8yBjUx-#@f52 zEc++HXgLm2|B17=gMKi|vI*k@kg5c);_^?ehn6OrlG0KU0VRAyT31sC%>v2zT#(IcHnSZGHae6rwjMk zl+MzhJnzvm8A$KAs`24$-TCBK9unNLtKbx|XQ%cAl_uY^D?O^jTBrWlL{o0hi3i`< zjk#SpuU3VBHhq=ZvcUmWc4)G2fp0uTxgv&c4>;u9!G=FB@h7}A-M?+De`2A^TLLe#!I!cM7HYOTjx9_;mX+tMyBtRXhvb54D&(Of098EMRq zw1MpR-ZO<@FkhOI(bU|84#{G$O%Asu0Kl6Hp1rH26WcqDE`RToFDMUZQ;#pYe#Z`+ z4(|+?3Fx@V355+3oeJ{wRW*_qm)n~j3a$%`t$$L}G@%YT7%4_Z6|uV>NH}77Yn#N@hjat)ip+-N~%&vB`)3}x54wf92}?9 z_^$Ev=eiX0D}bgY>K=pP+A7LY>OqaAm5ra#wc|vC7Xkcz9`vJZ--@Fa@X;|6`whbO za2`tke5y^=e75l(_5z>)xComHM|&nn)EsOB!V455(TGVT->vX+5wM=)Ju{y}(Hu(F z0X--8%-dPEOh4d;UTuaWE4VGagcXa9rkEP~_etHX$-EU3&&@}7<|rZMHJhqXlNhVv zY4L}>PC6$x(=UKO?j@~(5+a)ezrg`rFT;AL2WN_G#d!~;`a-oiXpI~p4JiBbfaF=W z+9y!u6DE&~bo9F%OcW~Y+g$QIE)T8k{1I~}e_kfc4~ zU2=-5aTvL3?;3SfcN4LErcU^)6Mk_f{QKjXt70g2y*O!05s##mQ>-W9_AaSg6L<9h zjCA4bSiR(+G^HtHYyQ2(^dc=g*OrQgMro53msAlFYrBXhg5Aejw_Z~|Q=l2^?${7; z>bA@F!tSnesWrM&B=gM%f8{Wiu*6rgYB%Ln_cpk&^FWcNp5T>hEJIh>B+OGj?@J!e zN$H>L4@k~VqzmyJIp3L04lh;kJ1@C`if=wW` zwv}K8YB>7Bf0+keYDTZQ0Ql_kjqgz(N66^$A>#3Aj&7Pzeaf>8zdY0nfK2?#G4xeo zf3^hZ_MK1@&69JJhZzl*xA?b*v)23LB##TsMD}0l7@za~&`XdK{3d(Hm1MTKG!yfK z%c8Ne$m!qO%88&gQeviy9c}$W8H}BhXx5?)0%*$}LJex%BYt zT1_PlY*1A%sVrJuHaV2GO8_!qmimBwZd|tEY{TO2AbKaTW};}b^oY z1lWj4(7OiTJ+(IA(LBd>XZ(TI<1SXMXNMO8r(efQntea6leIz?@a%35x9x;$rIiV7 zEIlL|cNww(sdx5mB%+j_C2k$oF!|U#4}LA8F)q?fi|T|LdyO5_na}yb{ZwjjjcYxF zZHgss;bg70GvoZxC;d^JHU;-#U5~!Qheh0f>@T3(9u4l)UXf$mug&HvY2cC!dp;KF zh%-F7QEQQ*&V4SHC!5mTU5VXg1oZDowv>{q_=2W<&&IB*wJ+}|JgWpAgLU<7y0p!-lJBIAZJFg;$GIb>5i2; hwD#}SKSI9$V4I$CYeB{gZteVKi88e|d0>PN{~v>}<#hl6 literal 0 HcmV?d00001