From 216841737341ce8e9a50eb27f11180202e9013a8 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Thu, 9 Jun 2022 01:51:45 -0700 Subject: [PATCH] Move to configurate for paper.yml (#7609) --- .editorconfig | 6 + patches/server/Add-API-for-quit-reason.patch | 4 +- ...nate-Current-redstone-implementation.patch | 39 +- ...dd-Early-Warning-Feature-to-WatchDog.patch | 53 +- .../Add-LivingEntity-getTargetEntity.patch | 2 +- .../server/Add-PlayerKickEvent-causes.patch | 14 +- .../Add-Unix-domain-socket-support.patch | 2 +- .../Add-Velocity-IP-Forwarding-Support.patch | 64 +- ...ing-Trader-spawn-rate-config-options.patch | 40 +- ...-to-configure-frosted_ice-properties.patch | 25 +- ...g-for-mobs-immune-to-default-effects.patch | 34 +- ...tion-for-logging-player-ip-addresses.patch | 26 +- ...tion-for-worlds-affected-by-time-cmd.patch | 18 +- ...to-disable-ender-dragon-legacy-check.patch | 16 +- ...-despawn-distances-for-living-entiti.patch | 64 +- ...-configurable-height-for-slime-spawn.patch | 29 +- ...dd-configurable-portal-search-radius.patch | 26 +- ...n-option-to-prevent-player-names-fro.patch | 16 +- patches/server/Add-critical-damage-API.patch | 2 +- ...Leash-variable-to-EntityUnleashEvent.patch | 4 +- patches/server/Add-entity-liquid-API.patch | 12 - ...n-for-console-having-all-permissions.patch | 22 +- ...to-allow-iron-golems-to-spawn-in-air.patch | 18 +- ...d-option-to-disable-pillager-patrols.patch | 17 +- ...n-to-fix-items-merging-through-walls.patch | 16 +- ...ke-parrots-stay-on-shoulders-despite.patch | 19 +- ...n-to-nerf-pigmen-from-nether-portals.patch | 18 +- ...event-players-from-moving-into-unloa.patch | 18 +- .../server/Add-packet-limiter-config.patch | 129 +- ...aper-mobcaps-and-paper-playermobcaps.patch | 2 +- ...ntom-creative-and-insomniac-controls.patch | 20 +- ...-ray-tracing-methods-to-LivingEntity.patch | 2 +- ...setting-for-proxy-online-mode-status.patch | 34 +- .../Add-support-for-Proxy-Protocol.patch | 18 +- ...pport-for-hex-color-codes-in-console.patch | 19 +- .../Add-tick-times-API-and-mspt-command.patch | 25 +- ...le-for-always-placing-the-dragon-egg.patch | 18 +- ...d-version-history-to-version-command.patch | 6 +- ...Add-zombie-targets-turtle-egg-config.patch | 18 +- ...ld-settings-for-mobs-picking-up-loot.patch | 23 +- patches/server/Adventure.patch | 28 +- ...chunks-are-slime-spawn-chunks-toggle.patch | 18 +- ...llow-Reloading-of-Custom-Permissions.patch | 4 +- ...Allow-disabling-armour-stand-ticking.patch | 17 +- ...mob-spawner-spawn-egg-transformation.patch | 18 +- .../Allow-for-toggling-of-spawn-chunks.patch | 17 +- ...d-mobs-to-jump-and-take-water-damage.patch | 28 +- ...-a-custom-authentication-servers-dow.patch | 25 +- ...-using-signs-inside-spawn-protection.patch | 16 +- patches/server/Anti-Xray.patch | 130 +- .../Asynchronous-chunk-IO-and-loading.patch | 101 +- patches/server/Basic-PlayerProfile-API.patch | 12 +- .../Block-Enderpearl-Travel-Exploit.patch | 19 +- patches/server/Book-Size-Limits.patch | 22 +- ...nd-make-tab-spam-limits-configurable.patch | 25 +- patches/server/Buffer-joins-to-world.patch | 30 +- patches/server/Cap-Entity-Collisions.patch | 19 +- patches/server/Chunk-debug-command.patch | 4 +- ...-should-not-bypass-cramming-gamerule.patch | 20 +- ...n-for-requiring-a-player-participant.patch | 29 +- ...g-option-for-Piglins-guarding-chests.patch | 18 +- ...le-Alternative-LootPool-Luck-Formula.patch | 19 +- ...figurable-Cartographer-Treasure-Maps.patch | 50 +- .../Configurable-Chunk-Inhabited-Time.patch | 21 +- ...urable-Disabling-Cat-Chest-Detection.patch | 16 +- .../Configurable-Grass-Spread-Tick-Rate.patch | 17 +- ...le-Keep-Spawn-Loaded-range-per-world.patch | 27 +- ...urable-Non-Player-Arrow-Despawn-Rate.patch | 26 +- .../Configurable-Player-Collision.patch | 30 +- ...figurable-baby-zombie-movement-speed.patch | 27 +- ...actus-bamboo-and-reed-growth-heights.patch | 37 +- ...-chance-of-villager-zombie-infection.patch | 22 +- ...ble-connection-throttle-kick-message.patch | 18 +- ...figurable-container-update-tick-rate.patch | 16 +- ...onfigurable-door-breaking-difficulty.patch | 36 +- patches/server/Configurable-end-credits.patch | 17 +- .../server/Configurable-feature-seeds.patch | 62 +- .../Configurable-fishing-time-ranges.patch | 21 +- .../Configurable-flying-kick-messages.patch | 20 +- ...ble-inter-world-teleportation-safety.patch | 16 +- ...tem-frame-map-cursor-update-interval.patch | 18 +- ...max-block-light-for-monster-spawning.patch | 16 +- .../Configurable-max-leash-distance.patch | 21 +- .../Configurable-mob-spawner-tick-rate.patch | 16 +- ...onfigurable-packet-in-spam-threshold.patch | 20 +- ...gurable-projectile-relative-velocity.patch | 17 +- ...le-spawn-chances-for-skeleton-horses.patch | 19 +- ...le-speed-for-water-flowing-over-lava.patch | 35 +- ...urable-sprint-interruption-on-attack.patch | 16 +- ...nfigurable-top-of-nether-void-damage.patch | 28 +- ...ading-permissions.yml-before-plugins.patch | 18 +- ...unk-Unloads-based-on-Player-Movement.patch | 20 +- ...ktraces-in-log-messages-crash-report.patch | 48 +- ...oreboards-for-non-players-by-default.patch | 18 +- ...t-selector-resolving-in-books-by-def.patch | 16 +- .../server/Disable-explosion-knockback.patch | 20 +- patches/server/Disable-ice-and-snow.patch | 16 +- patches/server/Disable-thunder.patch | 16 +- .../Distance-manager-tick-timings.patch | 2 +- ...n-t-apply-cramming-damage-to-players.patch | 16 +- ...-entity-collision-code-if-not-needed.patch | 2 +- ...y-scoreboard-teams-to-scoreboard.dat.patch | 16 +- ...ck-and-tnt-entities-at-the-specified.patch | 25 +- .../Duplicate-UUID-Resolve-Option.patch | 74 +- .../Eigencraft-redstone-implementation.patch | 53 +- ...tab-completions-for-brigadier-comman.patch | 33 +- .../server/Entity-Activation-Range-2.0.patch | 2 +- .../Entity-load-save-limit-per-chunk.patch | 56 +- patches/server/EntityMoveEvent.patch | 2 +- ...a-from-ArmorStand-and-SpawnEgg-items.patch | 19 +- patches/server/Fix-Light-Command.patch | 4 +- ...ld-Difficulty-Remembering-Difficulty.patch | 4 +- ...4-Bukkit-world-container-is-not-used.patch | 20 +- ...geEvent-not-firing-for-all-use-cases.patch | 2 +- ...x-and-optimise-world-force-upgrading.patch | 2 +- ...from-signs-not-firing-command-events.patch | 16 +- ...ing-zombie-villager-discount-exploit.patch | 18 +- ...y-type-tags-suggestions-in-selectors.patch | 22 +- ...rs-not-working-in-some-kick-messages.patch | 4 +- .../Fix-invulnerable-end-crystals.patch | 16 +- ...ston-physics-inconsistency-MC-188840.patch | 21 +- patches/server/Fix-sand-duping.patch | 2 +- ...rs-not-spawning-outside-slime-chunks.patch | 4 +- ...k-event-leave-message-not-being-sent.patch | 4 +- .../Flat-bedrock-generator-settings.patch | 17 +- .../Further-improve-server-tick-loop.patch | 2 +- ...de-unnecessary-itemmeta-from-clients.patch | 22 +- ...k-Priority-Urgency-System-for-Chunks.patch | 2 +- patches/server/Implement-Mob-Goal-API.patch | 4 +- .../Implement-Paper-VersionChecker.patch | 2 +- ...lement-alternative-item-despawn-rate.patch | 83 +- ...s-to-convert-between-Component-and-B.patch | 4 +- .../server/Improved-Watchdog-Support.patch | 2 +- .../server/Increase-Light-Queue-Size.patch | 17 +- .../InventoryCloseEvent-Reason-API.patch | 2 +- ...-track-plugin-scoreboards-by-default.patch | 18 +- .../Limit-item-frame-cursors-on-maps.patch | 16 +- patches/server/Limit-recipe-packets.patch | 20 +- ...Load-Chunks-for-Login-Asynchronously.patch | 2 +- ...-API-Replenishable-Lootables-Feature.patch | 55 +- ...5656-Fix-Follow-Range-Initial-Target.patch | 17 +- patches/server/MC-Utils.patch | 15 +- .../Make-EntityUnleashEvent-cancellable.patch | 4 +- .../Make-item-validations-configurable.patch | 36 +- ...e-shield-blocking-delay-configurable.patch | 16 +- ...ault-permission-message-configurable.patch | 28 +- ...ter-animal-spawn-height-configurable.patch | 33 +- ...al-Spawned-mobs-towards-natural-spaw.patch | 22 +- .../server/Optimise-WorldServer-notify.patch | 2 +- .../Optimise-chunk-tick-iteration.patch | 2 +- .../Optimise-nearby-player-lookups.patch | 2 +- .../Optimise-random-block-ticking.patch | 6 +- ...ptimize-Collision-to-not-load-chunks.patch | 2 +- patches/server/Optimize-Hoppers.patch | 30 +- ...erCloseEnoughForSpawning-to-use-dist.patch | 2 +- patches/server/Optimize-explosions.patch | 17 +- ...-maximum-exp-value-when-merging-orbs.patch | 19 +- ...efault-CustomSpawners-in-custom-worl.patch | 16 +- ...t-armor-stands-from-doing-entity-loo.patch | 18 +- ...nilla-per-world-scoreboard-coloring-.patch | 18 +- .../Optional-TNT-doesn-t-move-in-water.patch | 23 +- patches/server/Paper-Metrics.patch | 43 +- patches/server/Paper-command.patch | 71 +- patches/server/Paper-config-files.patch | 3759 +++++++++++++++-- ...spawn-settings-and-per-player-option.patch | 41 +- .../server/Preserve-overstacked-loot.patch | 18 +- ...sted-Ice-from-loading-holding-chunks.patch | 2 +- ...-headless-pistons-from-being-created.patch | 30 +- ...vent-opening-inventories-when-frozen.patch | 2 +- ...and-End-Portal-Frames-from-being-des.patch | 28 +- ...nd-timings-for-sensors-and-behaviors.patch | 77 +- .../server/Remove-Metadata-on-reload.patch | 4 +- ...ite-entity-bounding-box-lookup-calls.patch | 2 +- ...egionFileCache-and-make-configurable.patch | 16 +- ...-packets-for-hard-colliding-entities.patch | 17 +- patches/server/Timings-v2.patch | 81 +- .../Toggle-for-removing-existing-dragon.patch | 21 +- ...r-crits-helps-mitigate-hacked-client.patch | 18 +- patches/server/Update-Log4j.patch | 2 +- .../server/Upstream-config-migrations.patch | 36 - ...oleAppender-for-console-improvements.patch | 2 +- ...ocity-compression-and-cipher-natives.patch | 10 +- ...tance-map-to-optimise-entity-tracker.patch | 2 +- ...etChunkIfLoadedImmediately-in-places.patch | 2 +- patches/server/Validate-usernames.patch | 21 +- patches/server/add-DragonEggFormEvent.patch | 6 +- .../server/add-per-world-spawn-limits.patch | 40 +- ...disable-pathfinding-updates-on-block.patch | 18 +- .../fix-converting-txt-to-json-file.patch | 4 +- patches/server/getPlayerUniqueId-API.patch | 2 +- ...ement-optional-per-player-mob-spawns.patch | 25 +- .../incremental-chunk-and-player-saving.patch | 63 +- ...urable-option-to-disable-creeper-lin.patch | 17 +- 193 files changed, 4094 insertions(+), 3835 deletions(-) delete mode 100644 patches/server/Upstream-config-migrations.patch diff --git a/.editorconfig b/.editorconfig index aa4d12f5a8..a8939e783f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,3 +10,9 @@ indent_style=tab [*.bat] end_of_line=crlf + +[*.yml] +indent_size=2 + +[*.patch] +trim_trailing_whitespace=false diff --git a/patches/server/Add-API-for-quit-reason.patch b/patches/server/Add-API-for-quit-reason.patch index e41cca9860..ddf8d7d333 100644 --- a/patches/server/Add-API-for-quit-reason.patch +++ b/patches/server/Add-API-for-quit-reason.patch @@ -56,8 +56,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper } -- PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName()))); -+ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName())), entityplayer.quitReason); // Paper - quit reason +- PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName()))); ++ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName())), entityplayer.quitReason); // Paper - quit reason if (entityplayer.didPlayerJoinEvent) this.cserver.getPluginManager().callEvent(playerQuitEvent); // Paper - if we disconnected before join ever fired, don't fire quit entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); diff --git a/patches/server/Add-Alternate-Current-redstone-implementation.patch b/patches/server/Add-Alternate-Current-redstone-implementation.patch index afad77a80a..7b2633954d 100644 --- a/patches/server/Add-Alternate-Current-redstone-implementation.patch +++ b/patches/server/Add-Alternate-Current-redstone-implementation.patch @@ -1920,39 +1920,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return LevelHelper.setWireState(level, pos, state, added); + } +} -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - - public enum RedstoneImplementation { -- VANILLA, EIGENCRAFT -+ VANILLA, EIGENCRAFT, ALTERNATE_CURRENT - } - public RedstoneImplementation redstoneImplementation = RedstoneImplementation.VANILLA; - private void redstoneImplementation() { -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - switch (implementation) { - default: -- logError("Invalid redstone-implementation config " + implementation + " - must be one of: vanilla, eigencraft"); -+ logError("Invalid redstone-implementation config " + implementation + " - must be one of: vanilla, eigencraft, alternate-current"); - case "vanilla": - redstoneImplementation = RedstoneImplementation.VANILLA; - log("Using the Vanilla redstone implementation."); -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - redstoneImplementation = RedstoneImplementation.EIGENCRAFT; - log("Using Eigencraft's redstone implementation by theosib."); - break; -+ case "alternate-current": -+ redstoneImplementation = RedstoneImplementation.ALTERNATE_CURRENT; -+ log("Using Alternate Current's redstone implementation by Space Walker."); -+ break; - } - } - diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -2213,7 +2180,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!oldState.is(state.getBlock()) && !world.isClientSide) { - this.updateSurroundingRedstone(world, pos, state, null); // Paper - Optimize redstone + // Paper start - optimize redstone - replace call to updatePowerStrength -+ if (world.paperConfig.redstoneImplementation == com.destroystokyo.paper.PaperWorldConfig.RedstoneImplementation.ALTERNATE_CURRENT) { ++ if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { + world.getWireHandler().onWireAdded(pos); // Alternate Current + } else { + this.updateSurroundingRedstone(world, pos, state, null); // vanilla/Eigencraft @@ -2228,7 +2195,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.updateSurroundingRedstone(world, pos, state, null); // Paper - Optimize redstone + // Paper start - optimize redstone - replace call to updatePowerStrength -+ if (world.paperConfig.redstoneImplementation == com.destroystokyo.paper.PaperWorldConfig.RedstoneImplementation.ALTERNATE_CURRENT) { ++ if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { + world.getWireHandler().onWireRemoved(pos, state); // Alternate Current + } else { + this.updateSurroundingRedstone(world, pos, state, null); // vanilla/Eigencraft @@ -2243,7 +2210,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!world.isClientSide) { + // Paper start - optimize redstone (Alternate Current) + // Alternate Current handles breaking of redstone wires in the WireHandler. -+ if (world.paperConfig.redstoneImplementation == com.destroystokyo.paper.PaperWorldConfig.RedstoneImplementation.ALTERNATE_CURRENT) { ++ if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { + world.getWireHandler().onWireUpdated(pos); + } else + // Paper end diff --git a/patches/server/Add-Early-Warning-Feature-to-WatchDog.patch b/patches/server/Add-Early-Warning-Feature-to-WatchDog.patch index 614d4d1c79..3cffc77b89 100644 --- a/patches/server/Add-Early-Warning-Feature-to-WatchDog.patch +++ b/patches/server/Add-Early-Warning-Feature-to-WatchDog.patch @@ -8,33 +8,6 @@ thread dumps at an interval until the point of crash. This will help diagnose what was going on in that time before the crash. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ import org.bukkit.configuration.file.YamlConfiguration; - import co.aikar.timings.Timings; - import co.aikar.timings.TimingsManager; - import org.spigotmc.SpigotConfig; -+import org.spigotmc.WatchdogThread; - - public class PaperConfig { - -@@ -0,0 +0,0 @@ public class PaperConfig { - } - } - -+ public static int watchdogPrintEarlyWarningEvery = 5000; -+ public static int watchdogPrintEarlyWarningDelay = 10000; -+ private static void watchdogEarlyWarning() { -+ watchdogPrintEarlyWarningEvery = getInt("settings.watchdog.early-warning-every", 5000); -+ watchdogPrintEarlyWarningDelay = getInt("settings.watchdog.early-warning-delay", 10000); -+ WatchdogThread.doStart(SpigotConfig.timeoutTime, SpigotConfig.restartOnCrash ); -+ } -+ - public static int tabSpamIncrement = 1; - public static int tabSpamLimit = 500; - private static void tabSpamLimiters() { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java @@ -47,6 +20,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Arrays.fill( recentTps, 20 ); long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop lastTick = start - TICK_TIME; // Paper +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + // Paper start + paperConfigurations.initializeGlobalConfiguration(); + paperConfigurations.initializeWorldDefaultsConfiguration(); ++ org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); + io.papermc.paper.configuration.PaperConfigurations.registerCommands(this); + com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now + // Paper end diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -76,7 +61,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 SpigotConfig.restartMessage = SpigotConfig.transform( SpigotConfig.getString( "messages.restart", "Server is restarting" ) ); SpigotConfig.commands.put( "restart", new RestartCommand( "restart" ) ); - WatchdogThread.doStart( timeoutTime, restartOnCrash ); -+ //WatchdogThread.doStart( timeoutTime, restartOnCrash ); // Paper - moved to PaperConfig ++ // WatchdogThread.doStart( timeoutTime, restartOnCrash ); // Paper - moved to after paper config initialization } public static boolean bungee; @@ -84,14 +69,6 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -0,0 +0,0 @@ import java.lang.management.MonitorInfo; - import java.lang.management.ThreadInfo; - import java.util.logging.Level; - import java.util.logging.Logger; -+import com.destroystokyo.paper.PaperConfig; - import net.minecraft.server.MinecraftServer; - import org.bukkit.Bukkit; - @@ -0,0 +0,0 @@ public class WatchdogThread extends Thread private static WatchdogThread instance; private long timeoutTime; @@ -107,8 +84,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super( "Paper Watchdog Thread" ); this.timeoutTime = timeoutTime; this.restart = restart; -+ earlyWarningEvery = Math.min(PaperConfig.watchdogPrintEarlyWarningEvery, timeoutTime); // Paper -+ earlyWarningDelay = Math.min(PaperConfig.watchdogPrintEarlyWarningDelay, timeoutTime); // Paper ++ earlyWarningEvery = Math.min(io.papermc.paper.configuration.GlobalConfiguration.get().watchdog.earlyWarningEvery, timeoutTime); // Paper ++ earlyWarningDelay = Math.min(io.papermc.paper.configuration.GlobalConfiguration.get().watchdog.earlyWarningDelay, timeoutTime); // Paper } private static long monotonicMillis() diff --git a/patches/server/Add-LivingEntity-getTargetEntity.patch b/patches/server/Add-LivingEntity-getTargetEntity.patch index 9566205fa0..48df5ecfbd 100644 --- a/patches/server/Add-LivingEntity-getTargetEntity.patch +++ b/patches/server/Add-LivingEntity-getTargetEntity.patch @@ -52,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return result; + } + - public int shieldBlockingDelay = level.paperConfig.shieldBlockingDelay; + public int shieldBlockingDelay = level.paperConfig().misc.shieldBlockingDelay; public int getShieldBlockingDelay() { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java diff --git a/patches/server/Add-PlayerKickEvent-causes.patch b/patches/server/Add-PlayerKickEvent-causes.patch index 0abce2ff0f..643bbeab93 100644 --- a/patches/server/Add-PlayerKickEvent-causes.patch +++ b/patches/server/Add-PlayerKickEvent-causes.patch @@ -64,8 +64,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger()) { if (++this.aboveGroundTickCount > 80) { ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating too long!", this.player.getName().getString()); -- this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickPlayerMessage); // Paper - use configurable kick message -+ this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickPlayerMessage, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_PLAYER); // Paper - use configurable kick message & kick event cause +- this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer); // Paper - use configurable kick message ++ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_PLAYER); // Paper - use configurable kick message & kick event cause return; } } else { @@ -73,8 +73,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.clientVehicleIsFloating && this.player.getRootVehicle().getControllingPassenger() == this.player) { if (++this.aboveGroundVehicleTickCount > 80) { ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating a vehicle too long!", this.player.getName().getString()); -- this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickVehicleMessage); // Paper - use configurable kick message -+ this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickVehicleMessage, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_VEHICLE); // Paper - use configurable kick message & kick event cause +- this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle); // Paper - use configurable kick message ++ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_VEHICLE); // Paper - use configurable kick message & kick event cause return; } } else { @@ -124,7 +124,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.processedDisconnect) { @@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser } - net.kyori.adventure.text.Component leaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? this.player.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(this.player.getScoreboardName())); // Paper - Adventure + net.kyori.adventure.text.Component leaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? this.player.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(this.player.getScoreboardName())); // Paper - Adventure - PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), reason, leaveMessage); // Paper - Adventure + PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), reason, leaveMessage, cause); // Paper - Adventure & kick event reason @@ -143,7 +143,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser // PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.getWorldServer()); // Paper - run this async // CraftBukkit start - if (this.chatSpamTickCount.addAndGet(com.destroystokyo.paper.PaperConfig.tabSpamIncrement) > com.destroystokyo.paper.PaperConfig.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper start - split and make configurable + if (this.chatSpamTickCount.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper start - split and make configurable - server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper + server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause return; @@ -275,7 +275,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser // Paper start if (!org.bukkit.Bukkit.isPrimaryThread()) { - if (recipeSpamPackets.addAndGet(com.destroystokyo.paper.PaperConfig.autoRecipeIncrement) > com.destroystokyo.paper.PaperConfig.autoRecipeLimit) { + if (recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) { - server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]))); // Paper + server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause return; diff --git a/patches/server/Add-Unix-domain-socket-support.patch b/patches/server/Add-Unix-domain-socket-support.patch index 5d355b6e3f..9bb71c57cf 100644 --- a/patches/server/Add-Unix-domain-socket-support.patch +++ b/patches/server/Add-Unix-domain-socket-support.patch @@ -41,7 +41,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); + DedicatedServer.LOGGER.error("You are trying to use a Unix domain socket but you're not on a supported OS."); + return false; -+ } else if (!com.destroystokyo.paper.PaperConfig.velocitySupport && !org.spigotmc.SpigotConfig.bungee) { ++ } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && !org.spigotmc.SpigotConfig.bungee) { + DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); + DedicatedServer.LOGGER.error("Unix domain sockets require IPs to be forwarded from a proxy."); + return false; diff --git a/patches/server/Add-Velocity-IP-Forwarding-Support.patch b/patches/server/Add-Velocity-IP-Forwarding-Support.patch index 49d341b2df..8c5615bbab 100644 --- a/patches/server/Add-Velocity-IP-Forwarding-Support.patch +++ b/patches/server/Add-Velocity-IP-Forwarding-Support.patch @@ -13,48 +13,6 @@ of messages, is packed into a binary format that is smaller than BungeeCord's forwarding, and is integrated into the Minecraft login process by using the 1.13 login plugin message packet. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ import java.io.IOException; - import java.lang.reflect.InvocationTargetException; - import java.lang.reflect.Method; - import java.lang.reflect.Modifier; -+import java.nio.charset.StandardCharsets; - import java.util.HashMap; - import java.util.List; - import java.util.Map; -@@ -0,0 +0,0 @@ public class PaperConfig { - } - - public static boolean isProxyOnlineMode() { -- return Bukkit.getOnlineMode() || (SpigotConfig.bungee && bungeeOnlineMode); -+ return Bukkit.getOnlineMode() || (SpigotConfig.bungee && bungeeOnlineMode) || (velocitySupport && velocityOnlineMode); - } - - public static int packetInSpamThreshold = 300; -@@ -0,0 +0,0 @@ public class PaperConfig { - tabSpamLimit = getInt("settings.spam-limiter.tab-spam-limit", tabSpamLimit); - } - -+ public static boolean velocitySupport; -+ public static boolean velocityOnlineMode; -+ public static byte[] velocitySecretKey; -+ private static void velocitySupport() { -+ velocitySupport = getBoolean("settings.velocity-support.enabled", false); -+ velocityOnlineMode = getBoolean("settings.velocity-support.online-mode", false); -+ String secret = getString("settings.velocity-support.secret", ""); -+ if (velocitySupport && secret.isEmpty()) { -+ fatal("Velocity support is enabled, but no secret key was specified. A secret key is required!"); -+ } else { -+ velocitySecretKey = secret.getBytes(StandardCharsets.UTF_8); -+ } -+ } -+ - public static boolean asyncChunks = false; - private static void asyncChunks() { - ConfigurationSection section; diff --git a/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java b/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -63,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package com.destroystokyo.paper.proxy; + -+import com.destroystokyo.paper.PaperConfig; ++import io.papermc.paper.configuration.GlobalConfiguration; +import com.google.common.net.InetAddresses; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; @@ -90,7 +48,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + try { + final Mac mac = Mac.getInstance("HmacSHA256"); -+ mac.init(new SecretKeySpec(PaperConfig.velocitySecretKey, "HmacSHA256")); ++ mac.init(new SecretKeySpec(GlobalConfiguration.get().proxies.velocity.secret.getBytes(java.nio.charset.StandardCharsets.UTF_8), "HmacSHA256")); + final byte[] mySignature = mac.doFinal(data); + if (!MessageDigest.isEqual(signature, mySignature)) { + return false; @@ -131,14 +89,6 @@ diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListene index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -0,0 +0,0 @@ import org.bukkit.craftbukkit.util.Waitable; - import org.bukkit.event.player.AsyncPlayerPreLoginEvent; - import org.bukkit.event.player.PlayerPreLoginEvent; - // CraftBukkit end -+import io.netty.buffer.Unpooled; // Paper - - public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener { - @@ -0,0 +0,0 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener @Nullable private ProfilePublicKey playerProfilePublicKey; @@ -152,9 +102,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.connection.send(new ClientboundHelloPacket("", this.server.getKeyPair().getPublic().getEncoded(), this.nonce)); } else { + // Paper start - Velocity support -+ if (com.destroystokyo.paper.PaperConfig.velocitySupport) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { + this.velocityLoginMessageId = java.util.concurrent.ThreadLocalRandom.current().nextInt(); -+ net.minecraft.network.protocol.login.ClientboundCustomQueryPacket packet1 = new net.minecraft.network.protocol.login.ClientboundCustomQueryPacket(this.velocityLoginMessageId, com.destroystokyo.paper.proxy.VelocityProxy.PLAYER_INFO_CHANNEL, new net.minecraft.network.FriendlyByteBuf(Unpooled.EMPTY_BUFFER)); ++ net.minecraft.network.protocol.login.ClientboundCustomQueryPacket packet1 = new net.minecraft.network.protocol.login.ClientboundCustomQueryPacket(this.velocityLoginMessageId, com.destroystokyo.paper.proxy.VelocityProxy.PLAYER_INFO_CHANNEL, new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.EMPTY_BUFFER)); + this.connection.send(packet1); + return; + } @@ -167,7 +117,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void fireEvents() throws Exception { + // Paper start - Velocity support -+ if (ServerLoginPacketListenerImpl.this.velocityLoginMessageId == -1 && com.destroystokyo.paper.PaperConfig.velocitySupport) { ++ if (ServerLoginPacketListenerImpl.this.velocityLoginMessageId == -1 && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { + disconnect("This server requires you to connect with Velocity."); + return; + } @@ -180,7 +130,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void handleCustomQueryPacket(ServerboundCustomQueryPacket packet) { + // Paper start - Velocity support -+ if (com.destroystokyo.paper.PaperConfig.velocitySupport && packet.getTransactionId() == this.velocityLoginMessageId) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && packet.getTransactionId() == this.velocityLoginMessageId) { + net.minecraft.network.FriendlyByteBuf buf = packet.getData(); + if (buf == null) { + this.disconnect("This server requires you to connect with Velocity."); @@ -225,7 +175,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public long getConnectionThrottle() { // Spigot Start - Automatically set connection throttle for bungee configurations - if (org.spigotmc.SpigotConfig.bungee) { -+ if (org.spigotmc.SpigotConfig.bungee || com.destroystokyo.paper.PaperConfig.velocitySupport) { // Paper - Velocity support ++ if (org.spigotmc.SpigotConfig.bungee || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { // Paper - Velocity support return -1; } else { return this.configuration.getInt("settings.connection-throttle"); diff --git a/patches/server/Add-Wandering-Trader-spawn-rate-config-options.patch b/patches/server/Add-Wandering-Trader-spawn-rate-config-options.patch index 4658da764c..5bc6a14c4c 100644 --- a/patches/server/Add-Wandering-Trader-spawn-rate-config-options.patch +++ b/patches/server/Add-Wandering-Trader-spawn-rate-config-options.patch @@ -10,30 +10,6 @@ Usages of the vanilla WanderingTraderSpawnDelay and WanderingTraderSpawnChance v in IWorldServerData are removed as they were only used in certain places, with hardcoded values used in other places. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - } - -+ public int wanderingTraderSpawnMinuteTicks = 1200; -+ public int wanderingTraderSpawnDayTicks = 24000; -+ public int wanderingTraderSpawnChanceFailureIncrement = 25; -+ public int wanderingTraderSpawnChanceMin = 25; -+ public int wanderingTraderSpawnChanceMax = 75; -+ private void wanderingTraderSettings() { -+ wanderingTraderSpawnMinuteTicks = getInt("wandering-trader.spawn-minute-length", wanderingTraderSpawnMinuteTicks); -+ wanderingTraderSpawnDayTicks = getInt("wandering-trader.spawn-day-length", wanderingTraderSpawnDayTicks); -+ wanderingTraderSpawnChanceFailureIncrement = getInt("wandering-trader.spawn-chance-failure-increment", wanderingTraderSpawnChanceFailureIncrement); -+ wanderingTraderSpawnChanceMin = getInt("wandering-trader.spawn-chance-min", wanderingTraderSpawnChanceMin); -+ wanderingTraderSpawnChanceMax = getInt("wandering-trader.spawn-chance-max", wanderingTraderSpawnChanceMax); -+ } -+ - public short keepLoadedRange; - private void keepLoadedRange() { - keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java @@ -69,9 +45,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { + // Paper start + if (this.tickDelay == Integer.MIN_VALUE) { -+ this.tickDelay = world.paperConfig.wanderingTraderSpawnMinuteTicks; -+ this.spawnDelay = world.paperConfig.wanderingTraderSpawnDayTicks; -+ this.spawnChance = world.paperConfig.wanderingTraderSpawnChanceMin; ++ this.tickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; ++ this.spawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; ++ this.spawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; + } if (!world.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) { return 0; @@ -83,14 +59,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.tickDelay = 1200; - this.spawnDelay -= 1200; - this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); -+ this.tickDelay = world.paperConfig.wanderingTraderSpawnMinuteTicks; -+ this.spawnDelay = this.spawnDelay - world.paperConfig.wanderingTraderSpawnMinuteTicks; ++ this.tickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; ++ this.spawnDelay = this.spawnDelay - world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; + //this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways if (this.spawnDelay > 0) { return 0; } else { - this.spawnDelay = 24000; -+ this.spawnDelay = world.paperConfig.wanderingTraderSpawnDayTicks; ++ this.spawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; if (!world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { return 0; } else { @@ -98,13 +74,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.spawnChance = Mth.clamp(this.spawnChance + 25, (int) 25, (int) 75); - this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); -+ this.spawnChance = Mth.clamp(i + world.paperConfig.wanderingTraderSpawnChanceFailureIncrement, world.paperConfig.wanderingTraderSpawnChanceMin, world.paperConfig.wanderingTraderSpawnChanceMax); ++ this.spawnChance = Mth.clamp(i + world.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax); + //this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways if (this.random.nextInt(100) > i) { return 0; } else if (this.spawn(world)) { - this.spawnChance = 25; -+ this.spawnChance = world.paperConfig.wanderingTraderSpawnChanceMin; ++ this.spawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; + // Paper end return 1; } else { diff --git a/patches/server/Add-ability-to-configure-frosted_ice-properties.patch b/patches/server/Add-ability-to-configure-frosted_ice-properties.patch index 447da7b16a..dd3ac5482e 100644 --- a/patches/server/Add-ability-to-configure-frosted_ice-properties.patch +++ b/patches/server/Add-ability-to-configure-frosted_ice-properties.patch @@ -4,25 +4,6 @@ Date: Thu, 21 Apr 2016 23:51:55 -0700 Subject: [PATCH] Add ability to configure frosted_ice properties -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void useVanillaScoreboardColoring() { - useVanillaScoreboardColoring = getBoolean("use-vanilla-world-scoreboard-name-coloring", false); - } -+ -+ public boolean frostedIceEnabled = true; -+ public int frostedIceDelayMin = 20; -+ public int frostedIceDelayMax = 40; -+ private void frostedIce() { -+ this.frostedIceEnabled = this.getBoolean("frosted-ice.enabled", this.frostedIceEnabled); -+ this.frostedIceDelayMin = this.getInt("frosted-ice.delay.min", this.frostedIceDelayMin); -+ this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax); -+ log("Frosted Ice: " + (this.frostedIceEnabled ? "enabled" : "disabled") + " / delay: min=" + this.frostedIceDelayMin + ", max=" + this.frostedIceDelayMax); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java @@ -31,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { -+ if (!world.paperConfig.frostedIceEnabled) return; // Paper - add ability to disable frosted ice ++ if (!world.paperConfig().environment.frostedIce.enabled) return; // Paper - add ability to disable frosted ice if ((random.nextInt(3) == 0 || this.fewerNeigboursThan(world, pos, 4)) && world.getMaxLocalRawBrightness(pos) > 11 - state.getValue(AGE) - state.getLightBlock(world, pos) && this.slightlyMelt(state, world, pos)) { BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); @@ -40,13 +21,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockState blockState = world.getBlockState(mutableBlockPos); if (blockState.is(this) && !this.slightlyMelt(blockState, world, mutableBlockPos)) { - world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, 20, 40)); -+ world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, world.paperConfig.frostedIceDelayMin, world.paperConfig.frostedIceDelayMax)); // Paper - use configurable min/max delay ++ world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, world.paperConfig().environment.frostedIce.delay.min, world.paperConfig().environment.frostedIce.delay.max)); // Paper - use configurable min/max delay } } } else { - world.scheduleTick(pos, this, Mth.nextInt(random, 20, 40)); -+ world.scheduleTick(pos, this, Mth.nextInt(random, world.paperConfig.frostedIceDelayMin, world.paperConfig.frostedIceDelayMax)); // Paper - use configurable min/max delay ++ world.scheduleTick(pos, this, Mth.nextInt(random, world.paperConfig().environment.frostedIce.delay.min, world.paperConfig().environment.frostedIce.delay.max)); // Paper - use configurable min/max delay } } diff --git a/patches/server/Add-config-for-mobs-immune-to-default-effects.patch b/patches/server/Add-config-for-mobs-immune-to-default-effects.patch index cb1eb5a46d..91a6aae3d4 100644 --- a/patches/server/Add-config-for-mobs-immune-to-default-effects.patch +++ b/patches/server/Add-config-for-mobs-immune-to-default-effects.patch @@ -4,32 +4,6 @@ Date: Wed, 2 Dec 2020 21:03:02 -0800 Subject: [PATCH] Add config for mobs immune to default effects -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - log("Hopper Ignore Container Entities inside Occluding Blocks: " + (hoppersIgnoreOccludingBlocks ? "enabled" : "disabled")); - } - -+ public boolean undeadImmuneToCertainEffects = true; -+ public boolean spidersImmuneToPoisonEffect = true; -+ public boolean witherImmuneToWitherEffect = true; -+ public boolean witherSkeletonImmuneToWitherEffect = true; -+ private void mobEffectChanges() { -+ undeadImmuneToCertainEffects = getBoolean("mob-effects.undead-immune-to-certain-effects", undeadImmuneToCertainEffects); -+ log("Undead immune to harmful effects: " + undeadImmuneToCertainEffects); -+ spidersImmuneToPoisonEffect = getBoolean("mob-effects.spiders-immune-to-poison-effect", spidersImmuneToPoisonEffect); -+ log("Spiders immune to poison effect: " + spidersImmuneToPoisonEffect); -+ witherImmuneToWitherEffect = getBoolean("mob-effects.immune-to-wither-effect.wither", witherImmuneToWitherEffect); -+ log("Wither immune to wither effect: " + witherImmuneToWitherEffect); -+ witherSkeletonImmuneToWitherEffect = getBoolean("mob-effects.immune-to-wither-effect.wither-skeleton", witherSkeletonImmuneToWitherEffect); -+ log("Wither skeleton immune to wither effect: " + witherSkeletonImmuneToWitherEffect); -+ } -+ - public boolean nerfNetherPortalPigmen = false; - private void nerfNetherPortalPigmen() { - nerfNetherPortalPigmen = getBoolean("game-mechanics.nerf-pigmen-from-nether-portals", nerfNetherPortalPigmen); diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -39,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 MobEffect mobeffectlist = effect.getEffect(); - if (mobeffectlist == MobEffects.REGENERATION || mobeffectlist == MobEffects.POISON) { -+ if ((mobeffectlist == MobEffects.REGENERATION || mobeffectlist == MobEffects.POISON) && this.level.paperConfig.undeadImmuneToCertainEffects) { // Paper ++ if ((mobeffectlist == MobEffects.REGENERATION || mobeffectlist == MobEffects.POISON) && this.level.paperConfig().entities.mobEffects.undeadImmuneToCertainEffects) { // Paper return false; } } @@ -52,7 +26,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public boolean canBeAffected(MobEffectInstance effect) { - return effect.getEffect() == MobEffects.WITHER ? false : super.canBeAffected(effect); -+ return effect.getEffect() == MobEffects.WITHER && this.level.paperConfig.witherImmuneToWitherEffect ? false : super.canBeAffected(effect); // Paper ++ return effect.getEffect() == MobEffects.WITHER && this.level.paperConfig().entities.mobEffects.immuneToWitherEffect.wither ? false : super.canBeAffected(effect); // Paper } private class WitherDoNothingGoal extends Goal { @@ -65,7 +39,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public boolean canBeAffected(MobEffectInstance effect) { - return effect.getEffect() == MobEffects.POISON ? false : super.canBeAffected(effect); -+ return effect.getEffect() == MobEffects.POISON && this.level.paperConfig.spidersImmuneToPoisonEffect ? false : super.canBeAffected(effect); // Paper ++ return effect.getEffect() == MobEffects.POISON && this.level.paperConfig().entities.mobEffects.spidersImmuneToPoisonEffect ? false : super.canBeAffected(effect); // Paper } public boolean isClimbing() { @@ -78,6 +52,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public boolean canBeAffected(MobEffectInstance effect) { - return effect.getEffect() == MobEffects.WITHER ? false : super.canBeAffected(effect); -+ return effect.getEffect() == MobEffects.WITHER && this.level.paperConfig.witherSkeletonImmuneToWitherEffect ? false : super.canBeAffected(effect); // Paper ++ return effect.getEffect() == MobEffects.WITHER && this.level.paperConfig().entities.mobEffects.immuneToWitherEffect.witherSkeleton ? false : super.canBeAffected(effect); // Paper } } diff --git a/patches/server/Add-config-option-for-logging-player-ip-addresses.patch b/patches/server/Add-config-option-for-logging-player-ip-addresses.patch index 400903fc5e..a28107ba71 100644 --- a/patches/server/Add-config-option-for-logging-player-ip-addresses.patch +++ b/patches/server/Add-config-option-for-logging-player-ip-addresses.patch @@ -4,22 +4,6 @@ Date: Tue, 5 Oct 2021 20:04:21 +0200 Subject: [PATCH] Add config option for logging player ip addresses -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - } - } - -+ public static boolean logPlayerIpAddresses = true; -+ private static void playerIpAddresses() { -+ logPlayerIpAddresses = getBoolean("settings.log-player-ip-addresses", logPlayerIpAddresses); -+ } -+ - public static int maxJoinsPerTick; - private static void maxJoinsPerTick() { - maxJoinsPerTick = getInt("settings.max-joins-per-tick", 3); diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java @@ -28,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 packet.handle(listener); } catch (Exception exception) { net.minecraft.network.Connection networkmanager = listener.getConnection(); -+ String playerIP = com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : ""; // Paper ++ String playerIP = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : ""; // Paper if (networkmanager.getPlayer() != null) { - LOGGER.error("Error whilst processing packet {} for {}[{}]", packet, networkmanager.getPlayer().getScoreboardName(), networkmanager.getRemoteAddress(), exception); + LOGGER.error("Error whilst processing packet {} for {}[{}]", packet, networkmanager.getPlayer().getScoreboardName(), playerIP, exception); // Paper @@ -47,7 +31,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.buf = null; - LOGGER.debug("Ping: (1.6) from {}", ctx.channel().remoteAddress()); -+ LOGGER.debug("Ping: (1.6) from {}", com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? ctx.channel().remoteAddress() : ""); // Paper ++ LOGGER.debug("Ping: (1.6) from {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? ctx.channel().remoteAddress() : ""); // Paper InetSocketAddress virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(host, port); com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest( @@ -60,7 +44,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", networkmanager.getRemoteAddress(), exception); -+ ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : "", exception); // Paper ++ ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : "", exception); // Paper MutableComponent ichatmutablecomponent = Component.literal("Internal server error"); networkmanager.send(new ClientboundDisconnectPacket(ichatmutablecomponent), (future) -> { @@ -74,7 +58,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public String getUserName() { - return this.gameProfile != null ? this.gameProfile + " (" + this.connection.getRemoteAddress() + ")" : String.valueOf(this.connection.getRemoteAddress()); + // Paper start -+ String ip = com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? String.valueOf(this.connection.getRemoteAddress()) : ""; ++ String ip = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(this.connection.getRemoteAddress()) : ""; + return this.gameProfile != null ? this.gameProfile + " (" + ip + ")" : String.valueOf(ip); + // Paper end } @@ -89,7 +73,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (connection.getRemoteAddress() != null) { - s1 = connection.getRemoteAddress().toString(); -+ s1 = com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? connection.getRemoteAddress().toString() : ""; // Paper ++ s1 = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? connection.getRemoteAddress().toString() : ""; // Paper } else { s1 = "local"; } diff --git a/patches/server/Add-config-option-for-worlds-affected-by-time-cmd.patch b/patches/server/Add-config-option-for-worlds-affected-by-time-cmd.patch index aa89ad62a5..73c480fbb1 100644 --- a/patches/server/Add-config-option-for-worlds-affected-by-time-cmd.patch +++ b/patches/server/Add-config-option-for-worlds-affected-by-time-cmd.patch @@ -4,20 +4,6 @@ Date: Sun, 2 Jan 2022 22:34:51 -0800 Subject: [PATCH] Add config option for worlds affected by time cmd -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void sendFullPosForHardCollidingEntities() { - sendFullPosForHardCollidingEntities = getBoolean("settings.send-full-pos-for-hard-colliding-entities", true); - } -+ -+ public static boolean timeCommandAffectsAllWorlds = false; // See https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/aeaeb359317e6ba25b7c45cf6d70ff945a3777cf -+ private static void timeCommandAffectsAllWorlds() { -+ timeCommandAffectsAllWorlds = getBoolean("settings.time-command-affects-all-worlds", timeCommandAffectsAllWorlds); -+ } - } diff --git a/src/main/java/net/minecraft/server/commands/TimeCommand.java b/src/main/java/net/minecraft/server/commands/TimeCommand.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/commands/TimeCommand.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static int setTime(CommandSourceStack source, int time) { - Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in -+ Iterator iterator = com.destroystokyo.paper.PaperConfig.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change ++ Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change while (iterator.hasNext()) { ServerLevel worldserver = (ServerLevel) iterator.next(); @@ -36,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static int addTime(CommandSourceStack source, int time) { - Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in -+ Iterator iterator = com.destroystokyo.paper.PaperConfig.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change ++ Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change while (iterator.hasNext()) { ServerLevel worldserver = (ServerLevel) iterator.next(); diff --git a/patches/server/Add-config-to-disable-ender-dragon-legacy-check.patch b/patches/server/Add-config-to-disable-ender-dragon-legacy-check.patch index 528f6629e5..39aa7357be 100644 --- a/patches/server/Add-config-to-disable-ender-dragon-legacy-check.patch +++ b/patches/server/Add-config-to-disable-ender-dragon-legacy-check.patch @@ -4,20 +4,6 @@ Date: Fri, 22 Jun 2018 10:38:31 -0500 Subject: [PATCH] Add config to disable ender dragon legacy check -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void shieldBlockingDelay() { - shieldBlockingDelay = getInt("game-mechanics.shield-blocking-delay", 5); - } -+ -+ public boolean scanForLegacyEnderDragon = true; -+ private void scanForLegacyEnderDragon() { -+ scanForLegacyEnderDragon = getBoolean("game-mechanics.scan-for-legacy-ender-dragon", true); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public EndDragonFight(ServerLevel world, long gatewaysSeed, CompoundTag nbt) { + // Paper start -+ this.needsStateScanning = world.paperConfig.scanForLegacyEnderDragon; ++ this.needsStateScanning = world.paperConfig().entities.spawning.scanForLegacyEnderDragon; + if (!this.needsStateScanning) this.dragonKilled = true; + // Paper end this.level = world; diff --git a/patches/server/Add-configurable-despawn-distances-for-living-entiti.patch b/patches/server/Add-configurable-despawn-distances-for-living-entiti.patch index dfdecd922a..c7d27a86ea 100644 --- a/patches/server/Add-configurable-despawn-distances-for-living-entiti.patch +++ b/patches/server/Add-configurable-despawn-distances-for-living-entiti.patch @@ -4,66 +4,6 @@ Date: Tue, 1 Mar 2016 13:51:54 -0600 Subject: [PATCH] Add configurable despawn distances for living entities -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ package com.destroystokyo.paper; - import java.util.List; - - import java.util.stream.Collectors; -+import it.unimi.dsi.fastutil.objects.Reference2IntMap; -+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; -+import net.minecraft.world.entity.MobCategory; - import org.bukkit.Bukkit; - import org.bukkit.configuration.file.YamlConfiguration; - import org.spigotmc.SpigotWorldConfig; -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - public void removeOldValues() { - boolean needsSave = false; - -+ if (PaperConfig.version < 24) { -+ needsSave = true; -+ -+ set("despawn-ranges.soft", null); -+ set("despawn-ranges.hard", null); -+ } -+ - if (needsSave) { - saveConfig(); - } -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void nerfedMobsShouldJump() { - nerfedMobsShouldJump = getBoolean("spawner-nerfed-mobs-should-jump", false); - } -+ -+ public final Reference2IntMap softDespawnDistances = new Reference2IntOpenHashMap<>(MobCategory.values().length); -+ public final Reference2IntMap hardDespawnDistances = new Reference2IntOpenHashMap<>(MobCategory.values().length); -+ private void despawnDistances() { -+ if (PaperConfig.version < 24) { -+ int softDistance = getInt("despawn-ranges.soft", 32, false); // 32^2 = 1024, Minecraft Default -+ int hardDistance = getInt("despawn-ranges.hard", 128, false); // 128^2 = 16384, Minecraft Default -+ for (MobCategory value : MobCategory.values()) { -+ if (softDistance != 32) { -+ softDespawnDistances.put(value, softDistance); -+ } -+ if (hardDistance != 128) { -+ hardDespawnDistances.put(value, hardDistance); -+ } -+ } -+ } -+ for (MobCategory category : MobCategory.values()) { -+ int softDistance = getInt("despawn-ranges." + category.getName() + ".soft", softDespawnDistances.getOrDefault(category, category.getNoDespawnDistance())); -+ int hardDistance = getInt("despawn-ranges." + category.getName() + ".hard", hardDespawnDistances.getOrDefault(category, category.getDespawnDistance())); -+ if (softDistance > hardDistance) { -+ softDistance = hardDistance; -+ } -+ log("Mobs in " + category.getName() + " Despawn Ranges: Soft" + softDistance + " Hard: " + hardDistance); -+ softDespawnDistances.put(category, softDistance); -+ hardDespawnDistances.put(category, hardDistance); -+ } -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java @@ -73,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (entityhuman != null) { double d0 = entityhuman.distanceToSqr((Entity) this); - int i = this.getType().getCategory().getDespawnDistance(); -+ int i = this.level.paperConfig.hardDespawnDistances.getInt(this.getType().getCategory()); // Paper - custom despawn distances ++ int i = this.level.paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()).hard(); // Paper - custom despawn distances int j = i * i; if (d0 > (double) j && this.removeWhenFarAway(d0)) { @@ -81,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - int k = this.getType().getCategory().getNoDespawnDistance(); -+ int k = this.level.paperConfig.softDespawnDistances.getInt(this.getType().getCategory()); // Paper - custom despawn distances ++ int k = this.level.paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()).soft(); // Paper - custom despawn distances int l = k * k; if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > (double) l && this.removeWhenFarAway(d0)) { diff --git a/patches/server/Add-configurable-height-for-slime-spawn.patch b/patches/server/Add-configurable-height-for-slime-spawn.patch index 5ada055593..e4776cd7cc 100644 --- a/patches/server/Add-configurable-height-for-slime-spawn.patch +++ b/patches/server/Add-configurable-height-for-slime-spawn.patch @@ -4,27 +4,6 @@ Date: Mon, 2 Aug 2021 11:24:39 -0400 Subject: [PATCH] Add configurable height for slime spawn -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", false); - } - -+ public double slimeMaxSpawnHeightInSwamp = 70; -+ public double slimeMinSpawnHeightInSwamp = 50; -+ public double slimeMaxSpawnHeightInSlimeChunks = 40; -+ private void slimeSpawnHeight() { -+ slimeMaxSpawnHeightInSwamp = getDouble("slime-spawn-height.swamp-biome.maximum", this.slimeMaxSpawnHeightInSwamp); -+ slimeMinSpawnHeightInSwamp = getDouble("slime-spawn-height.swamp-biome.minimum", this.slimeMinSpawnHeightInSwamp); -+ slimeMaxSpawnHeightInSlimeChunks = getDouble("slime-spawn-height.slime-chunk.maximum", this.slimeMaxSpawnHeightInSlimeChunks); -+ } -+ -+ - public int portalSearchRadius; - public int portalCreateRadius; - public boolean portalSearchVanillaDimensionScaling; diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Slime.java @@ -35,8 +14,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (world.getDifficulty() != Difficulty.PEACEFUL) { - if (world.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > 50 && pos.getY() < 70 && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { + // Paper start - Replace rules for Height in Swamp Biome -+ final double maxHeightSwamp = world.getMinecraftWorld().paperConfig.slimeMaxSpawnHeightInSwamp; -+ final double minHeightSwamp = world.getMinecraftWorld().paperConfig.slimeMinSpawnHeightInSwamp; ++ final double maxHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.swampBiome.maximum; ++ final double minHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.swampBiome.minimum; + if (world.getBiome(pos).is(net.minecraft.world.level.biome.Biomes.SWAMP) && pos.getY() > minHeightSwamp && pos.getY() < maxHeightSwamp && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { + // Paper end return checkMobSpawnRules(type, world, spawnReason, pos, random); @@ -44,11 +23,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class Slime extends Mob implements Enemy { ChunkPos chunkcoordintpair = new ChunkPos(pos); - boolean flag = world.getMinecraftWorld().paperConfig.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper + boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper - if (random.nextInt(10) == 0 && flag && pos.getY() < 40) { + // Paper start - Replace rules for Height in Slime Chunks -+ final double maxHeightSlimeChunk = world.getMinecraftWorld().paperConfig.slimeMaxSpawnHeightInSlimeChunks; ++ final double maxHeightSlimeChunk = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.slimeChunk.maximum; + if (random.nextInt(10) == 0 && flag && pos.getY() < maxHeightSlimeChunk) { + // Paper end return checkMobSpawnRules(type, world, spawnReason, pos, random); diff --git a/patches/server/Add-configurable-portal-search-radius.patch b/patches/server/Add-configurable-portal-search-radius.patch index 954533b6b4..2ebe8e5c4a 100644 --- a/patches/server/Add-configurable-portal-search-radius.patch +++ b/patches/server/Add-configurable-portal-search-radius.patch @@ -4,24 +4,6 @@ Date: Thu, 3 Mar 2016 02:46:17 -0600 Subject: [PATCH] Add configurable portal search radius -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void allChunksAreSlimeChunks() { - allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", false); - } -+ -+ public int portalSearchRadius; -+ public int portalCreateRadius; -+ public boolean portalSearchVanillaDimensionScaling; -+ private void portalSearchRadius() { -+ portalSearchRadius = getInt("portal-search-radius", 128); -+ portalCreateRadius = getInt("portal-create-radius", 16); -+ portalSearchVanillaDimensionScaling = getBoolean("portal-search-vanilla-dimension-scaling", true); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java @@ -32,12 +14,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start - CraftPortalEvent event = this.callPortalEvent(this, destination, blockposition, PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, flag2 ? 16 : 128, 16); + // Paper start -+ int portalSearchRadius = destination.paperConfig.portalSearchRadius; -+ if (level.paperConfig.portalSearchVanillaDimensionScaling && flag2) { // == THE_NETHER ++ int portalSearchRadius = destination.paperConfig().environment.portalSearchRadius; ++ if (level.paperConfig().environment.portalSearchVanillaDimensionScaling && flag2) { // == THE_NETHER + portalSearchRadius = (int) (portalSearchRadius / destination.dimensionType().coordinateScale()); + } + // Paper end -+ CraftPortalEvent event = this.callPortalEvent(this, destination, blockposition, PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, portalSearchRadius, destination.paperConfig.portalCreateRadius); // Paper start - configurable portal radius ++ CraftPortalEvent event = this.callPortalEvent(this, destination, blockposition, PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, portalSearchRadius, destination.paperConfig().environment.portalCreateRadius); // Paper start - configurable portal radius if (event == null) { return null; } @@ -50,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public Optional findPortalAround(BlockPos pos, boolean destIsNether, WorldBorder worldBorder) { // CraftBukkit start - return this.findPortalAround(pos, worldBorder, destIsNether ? 16 : 128); // Search Radius -+ return this.findPortalAround(pos, worldBorder, destIsNether ? level.paperConfig.portalCreateRadius : level.paperConfig.portalSearchRadius); // Search Radius // Paper - search Radius ++ return this.findPortalAround(pos, worldBorder, destIsNether ? level.paperConfig().environment.portalCreateRadius : level.paperConfig().environment.portalSearchRadius); // Search Radius // Paper - search Radius } public Optional findPortalAround(BlockPos blockposition, WorldBorder worldborder, int i) { diff --git a/patches/server/Add-configuration-option-to-prevent-player-names-fro.patch b/patches/server/Add-configuration-option-to-prevent-player-names-fro.patch index 6f9c18a75d..084a44840e 100644 --- a/patches/server/Add-configuration-option-to-prevent-player-names-fro.patch +++ b/patches/server/Add-configuration-option-to-prevent-player-names-fro.patch @@ -5,20 +5,6 @@ Subject: [PATCH] Add configuration option to prevent player names from being suggested -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - flyingKickPlayerMessage = getString("messages.kick.flying-player", flyingKickPlayerMessage); - flyingKickVehicleMessage = getString("messages.kick.flying-vehicle", flyingKickVehicleMessage); - } -+ -+ public static boolean suggestPlayersWhenNullTabCompletions = true; -+ private static void suggestPlayersWhenNull() { -+ suggestPlayersWhenNullTabCompletions = getBoolean("settings.suggest-player-names-when-null-tab-completions", suggestPlayersWhenNullTabCompletions); -+ } - } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -30,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Override + public boolean suggestPlayerNamesWhenNullTabCompletions() { -+ return com.destroystokyo.paper.PaperConfig.suggestPlayersWhenNullTabCompletions; ++ return io.papermc.paper.configuration.GlobalConfiguration.get().commands.suggestPlayerNamesWhenNullTabCompletions; + } // Paper end } diff --git a/patches/server/Add-critical-damage-API.patch b/patches/server/Add-critical-damage-API.patch index 12d22e27dc..d1a0b37983 100644 --- a/patches/server/Add-critical-damage-API.patch +++ b/patches/server/Add-critical-damage-API.patch @@ -39,7 +39,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity; + boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity; // Paper - Add critical damage API - conflict on change - flag2 = flag2 && !level.paperConfig.disablePlayerCrits; // Paper + flag2 = flag2 && !level.paperConfig().entities.behavior.disablePlayerCrits; // Paper flag2 = flag2 && !this.isSprinting(); @@ -0,0 +0,0 @@ public abstract class Player extends LivingEntity { } diff --git a/patches/server/Add-dropLeash-variable-to-EntityUnleashEvent.patch b/patches/server/Add-dropLeash-variable-to-EntityUnleashEvent.patch index 0740c351dd..0b3653bd69 100644 --- a/patches/server/Add-dropLeash-variable-to-EntityUnleashEvent.patch +++ b/patches/server/Add-dropLeash-variable-to-EntityUnleashEvent.patch @@ -75,7 +75,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class PathfinderMob extends Mob { if (this instanceof TamableAnimal && ((TamableAnimal) this).isInSittingPose()) { - if (f > entity.level.paperConfig.maxLeashDistance) { // Paper + if (f > entity.level.paperConfig().misc.maxLeashDistance) { // Paper - this.level.getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE)); // CraftBukkit - this.dropLeash(true, true); + // Paper start - drop leash variable @@ -89,7 +89,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class PathfinderMob extends Mob { this.onLeashDistance(f); - if (f > entity.level.paperConfig.maxLeashDistance) { // Paper + if (f > entity.level.paperConfig().misc.maxLeashDistance) { // Paper - this.level.getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE)); // CraftBukkit - this.dropLeash(true, true); + // Paper start - drop leash variable diff --git a/patches/server/Add-entity-liquid-API.patch b/patches/server/Add-entity-liquid-API.patch index abdb1682ae..6551761c5a 100644 --- a/patches/server/Add-entity-liquid-API.patch +++ b/patches/server/Add-entity-liquid-API.patch @@ -4,18 +4,6 @@ Date: Thu, 2 Jul 2020 18:11:43 -0500 Subject: [PATCH] Add entity liquid API -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { - return this.isInWater() || this.isInRain(); - } - -- @Deprecated public final boolean isInWaterOrRainOrBubble() { return isInWaterRainOrBubble(); } // Paper - OBFHELPER - public boolean isInWaterRainOrBubble() { - return this.isInWater() || this.isInRain() || this.isInBubbleColumn(); - } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java diff --git a/patches/server/Add-option-for-console-having-all-permissions.patch b/patches/server/Add-option-for-console-having-all-permissions.patch index bba6948e03..924509df87 100644 --- a/patches/server/Add-option-for-console-having-all-permissions.patch +++ b/patches/server/Add-option-for-console-having-all-permissions.patch @@ -4,20 +4,6 @@ Date: Sat, 16 May 2020 10:12:15 +0200 Subject: [PATCH] Add option for console having all permissions -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - config.set("settings.unsupported-settings.allow-permanent-block-break-exploits-readme", "This setting controls if players should be able to break bedrock, end portals and other intended to be permanent blocks."); - allowBlockPermanentBreakingExploits = getBoolean("settings.unsupported-settings.allow-permanent-block-break-exploits", allowBlockPermanentBreakingExploits); - } -+ -+ public static boolean consoleHasAllPermissions = false; -+ private static void consoleHasAllPermissions() { -+ consoleHasAllPermissions = getBoolean("settings.console-has-all-permissions", consoleHasAllPermissions); -+ } - } diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java @@ -29,12 +15,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Override + public boolean hasPermission(String name) { -+ return com.destroystokyo.paper.PaperConfig.consoleHasAllPermissions || super.hasPermission(name); ++ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name); + } + + @Override + public boolean hasPermission(org.bukkit.permissions.Permission perm) { -+ return com.destroystokyo.paper.PaperConfig.consoleHasAllPermissions || super.hasPermission(perm); ++ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm); + } // Paper end } @@ -50,12 +36,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + @Override + public boolean hasPermission(String name) { -+ return com.destroystokyo.paper.PaperConfig.consoleHasAllPermissions || super.hasPermission(name); ++ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name); + } + + @Override + public boolean hasPermission(org.bukkit.permissions.Permission perm) { -+ return com.destroystokyo.paper.PaperConfig.consoleHasAllPermissions || super.hasPermission(perm); ++ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm); + } + // Paper end } diff --git a/patches/server/Add-option-to-allow-iron-golems-to-spawn-in-air.patch b/patches/server/Add-option-to-allow-iron-golems-to-spawn-in-air.patch index 202843529c..75092de1b1 100644 --- a/patches/server/Add-option-to-allow-iron-golems-to-spawn-in-air.patch +++ b/patches/server/Add-option-to-allow-iron-golems-to-spawn-in-air.patch @@ -4,22 +4,6 @@ Date: Sat, 13 Apr 2019 16:50:58 -0500 Subject: [PATCH] Add option to allow iron golems to spawn in air -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - scanForLegacyEnderDragon = getBoolean("game-mechanics.scan-for-legacy-ender-dragon", true); - } - -+ public boolean ironGolemsCanSpawnInAir = false; -+ private void ironGolemsCanSpawnInAir() { -+ ironGolemsCanSpawnInAir = getBoolean("iron-golems-can-spawn-in-air", ironGolemsCanSpawnInAir); -+ } -+ - public boolean armorStandEntityLookups = true; - private void armorStandEntityLookups() { - armorStandEntityLookups = getBoolean("armor-stands-do-collision-entity-lookups", true); diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java @@ -29,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockState iblockdata = world.getBlockState(blockposition1); - if (!iblockdata.entityCanStandOn(world, blockposition1, this)) { -+ if (!iblockdata.entityCanStandOn(world, blockposition1, this) && !level.paperConfig.ironGolemsCanSpawnInAir) { // Paper ++ if (!iblockdata.entityCanStandOn(world, blockposition1, this) && !level.paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper return false; } else { for (int i = 1; i < 3; ++i) { diff --git a/patches/server/Add-option-to-disable-pillager-patrols.patch b/patches/server/Add-option-to-disable-pillager-patrols.patch index 5352553667..87f9f19b5d 100644 --- a/patches/server/Add-option-to-disable-pillager-patrols.patch +++ b/patches/server/Add-option-to-disable-pillager-patrols.patch @@ -4,21 +4,6 @@ Date: Wed, 9 Oct 2019 21:46:15 -0500 Subject: [PATCH] Add option to disable pillager patrols -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void disableRelativeProjectileVelocity() { - disableRelativeProjectileVelocity = getBoolean("game-mechanics.disable-relative-projectile-velocity", false); - } -+ -+ public boolean disablePillagerPatrols = false; -+ private void pillagerSettings() { -+ disablePillagerPatrols = getBoolean("game-mechanics.disable-pillager-patrols", disablePillagerPatrols); -+ } - } - diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java @@ -27,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { -+ if (world.paperConfig.disablePillagerPatrols) return 0; // Paper ++ if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper if (!spawnMonsters) { return 0; } else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) { diff --git a/patches/server/Add-option-to-fix-items-merging-through-walls.patch b/patches/server/Add-option-to-fix-items-merging-through-walls.patch index ea5ba11e7a..6b3ef66736 100644 --- a/patches/server/Add-option-to-fix-items-merging-through-walls.patch +++ b/patches/server/Add-option-to-fix-items-merging-through-walls.patch @@ -4,20 +4,6 @@ Date: Wed, 10 Mar 2021 10:06:45 -0800 Subject: [PATCH] Add option to fix items merging through walls -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void mapItemFrameCursorLimit() { - mapItemFrameCursorLimit = getInt("map-item-frame-cursor-limit", mapItemFrameCursorLimit); - } -+ -+ public boolean fixItemsMergingThroughWalls; -+ private void fixItemsMergingThroughWalls() { -+ fixItemsMergingThroughWalls = getBoolean("fix-items-merging-through-walls", fixItemsMergingThroughWalls); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (entityitem.isMergable()) { + // Paper Start - Fix items merging through walls -+ if (this.level.paperConfig.fixItemsMergingThroughWalls) { ++ if (this.level.paperConfig().fixes.fixItemsMergingThroughWalls) { + net.minecraft.world.level.ClipContext rayTrace = new net.minecraft.world.level.ClipContext(this.position(), entityitem.position(), + net.minecraft.world.level.ClipContext.Block.COLLIDER, net.minecraft.world.level.ClipContext.Fluid.NONE, this); + net.minecraft.world.phys.BlockHitResult rayTraceResult = level.clip(rayTrace); diff --git a/patches/server/Add-option-to-make-parrots-stay-on-shoulders-despite.patch b/patches/server/Add-option-to-make-parrots-stay-on-shoulders-despite.patch index 893842e56e..c4b1788bd3 100644 --- a/patches/server/Add-option-to-make-parrots-stay-on-shoulders-despite.patch +++ b/patches/server/Add-option-to-make-parrots-stay-on-shoulders-despite.patch @@ -10,21 +10,6 @@ I suspect Mojang may switch to this behavior before full release. To be converted into a Paper-API event at some point in the future? -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - maxCollisionsPerEntity = getInt( "max-entity-collisions", this.spigotConfig.getInt("max-entity-collisions", this.maxCollisionsPerEntity, false) ); - log( "Max Entity Collisions: " + maxCollisionsPerEntity ); - } -+ -+ public boolean parrotsHangOnBetter; -+ private void parrotsHangOnBetter() { -+ parrotsHangOnBetter = getBoolean("parrots-are-unaffected-by-player-movement", false); -+ log("Parrots are unaffected by player movement: " + parrotsHangOnBetter); -+ } - } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -35,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.player.setShiftKeyDown(true); + + // Paper start - Hang on! -+ if (this.player.level.paperConfig.parrotsHangOnBetter) { ++ if (this.player.level.paperConfig().entities.behavior.parrotsAreUnaffectedByPlayerMovement) { + this.player.removeEntitiesOnShoulder(); + } + // Paper end @@ -52,7 +37,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.playShoulderEntityAmbientSound(this.getShoulderEntityRight()); if (!this.level.isClientSide && (this.fallDistance > 0.5F || this.isInWater()) || this.abilities.flying || this.isSleeping() || this.isInPowderSnow) { - this.removeEntitiesOnShoulder(); -+ if (!this.level.paperConfig.parrotsHangOnBetter) this.removeEntitiesOnShoulder(); // Paper - Hang on! ++ if (!this.level.paperConfig().entities.behavior.parrotsAreUnaffectedByPlayerMovement) this.removeEntitiesOnShoulder(); // Paper - Hang on! } } diff --git a/patches/server/Add-option-to-nerf-pigmen-from-nether-portals.patch b/patches/server/Add-option-to-nerf-pigmen-from-nether-portals.patch index e15e25c48a..f6ea9a9d7d 100644 --- a/patches/server/Add-option-to-nerf-pigmen-from-nether-portals.patch +++ b/patches/server/Add-option-to-nerf-pigmen-from-nether-portals.patch @@ -4,22 +4,6 @@ Date: Fri, 7 Feb 2020 14:36:56 -0600 Subject: [PATCH] Add option to nerf pigmen from nether portals -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - log("Hopper Ignore Container Entities inside Occluding Blocks: " + (hoppersIgnoreOccludingBlocks ? "enabled" : "disabled")); - } - -+ public boolean nerfNetherPortalPigmen = false; -+ private void nerfNetherPortalPigmen() { -+ nerfNetherPortalPigmen = getBoolean("game-mechanics.nerf-pigmen-from-nether-portals", nerfNetherPortalPigmen); -+ } -+ - public int lightQueueSize = 20; - private void lightQueueSize() { - lightQueueSize = getInt("light-queue-size", lightQueueSize); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java @@ -59,7 +43,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (entity != null) { entity.setPortalCooldown(); + entity.fromNetherPortal = true; // Paper -+ if (world.paperConfig.nerfNetherPortalPigmen) ((net.minecraft.world.entity.Mob) entity).aware = false; // Paper ++ if (world.paperConfig().entities.behavior.nerfPigmenFromNetherPortals) ((net.minecraft.world.entity.Mob) entity).aware = false; // Paper } } } diff --git a/patches/server/Add-option-to-prevent-players-from-moving-into-unloa.patch b/patches/server/Add-option-to-prevent-players-from-moving-into-unloa.patch index 9355df75ef..9942074746 100644 --- a/patches/server/Add-option-to-prevent-players-from-moving-into-unloa.patch +++ b/patches/server/Add-option-to-prevent-players-from-moving-into-unloa.patch @@ -5,20 +5,6 @@ Subject: [PATCH] Add option to prevent players from moving into unloaded chunks #1551 -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - waterOverLavaFlowSpeed = getInt("water-over-lava-flow-speed", 5); - log("Water over lava flow speed: " + waterOverLavaFlowSpeed); - } -+ -+ public boolean preventMovingIntoUnloadedChunks = false; -+ private void preventMovingIntoUnloadedChunks() { -+ preventMovingIntoUnloadedChunks = getBoolean("prevent-moving-into-unloaded-chunks", false); -+ } - } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -41,7 +27,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 speed *= 2f; // TODO: Get the speed of the vehicle instead of the player + // Paper start - Prevent moving into unloaded chunks -+ if (player.level.paperConfig.preventMovingIntoUnloadedChunks && ( ++ if (player.level.paperConfig().chunks.preventMovingIntoUnloadedChunks && ( + !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position()))) || + !worldserver.areChunksLoadedForMove(entity.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(entity.position()))) + )) { @@ -71,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 speed = this.player.getAbilities().walkingSpeed * 10f; } + // Paper start - Prevent moving into unloaded chunks -+ if (player.level.paperConfig.preventMovingIntoUnloadedChunks && (this.player.getX() != toX || this.player.getZ() != toZ) && !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position())))) { ++ if (player.level.paperConfig().chunks.preventMovingIntoUnloadedChunks && (this.player.getX() != toX || this.player.getZ() != toZ) && !worldserver.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position())))) { + this.internalTeleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot(), Collections.emptySet(), true); + return; + } diff --git a/patches/server/Add-packet-limiter-config.patch b/patches/server/Add-packet-limiter-config.patch index 01b9fd79e7..a0ca4a3871 100644 --- a/patches/server/Add-packet-limiter-config.patch +++ b/patches/server/Add-packet-limiter-config.patch @@ -23,113 +23,6 @@ and an action can be defined: DROP or KICK If interval or rate are less-than 0, the limit is ignored -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - itemValidationBookAuthorLength = getInt("settings.item-validation.book.author", itemValidationBookAuthorLength); - itemValidationBookPageLength = getInt("settings.item-validation.book.page", itemValidationBookPageLength); - } -+ -+ public static final class PacketLimit { -+ public final double packetLimitInterval; -+ public final double maxPacketRate; -+ public final ViolateAction violateAction; -+ -+ public PacketLimit(final double packetLimitInterval, final double maxPacketRate, final ViolateAction violateAction) { -+ this.packetLimitInterval = packetLimitInterval; -+ this.maxPacketRate = maxPacketRate; -+ this.violateAction = violateAction; -+ } -+ -+ public static enum ViolateAction { -+ KICK, DROP; -+ } -+ } -+ -+ public static String kickMessage; -+ public static PacketLimit allPacketsLimit; -+ public static java.util.Map>, PacketLimit> packetSpecificLimits = new java.util.HashMap<>(); -+ -+ private static void packetLimiter() { -+ packetSpecificLimits.clear(); -+ kickMessage = org.bukkit.ChatColor.translateAlternateColorCodes('&', getString("settings.packet-limiter.kick-message", "&cSent too many packets")); -+ allPacketsLimit = new PacketLimit( -+ getDouble("settings.packet-limiter.limits.all.interval", 7.0), -+ getDouble("settings.packet-limiter.limits.all.max-packet-rate", 500.0), -+ PacketLimit.ViolateAction.KICK -+ ); -+ if (allPacketsLimit.maxPacketRate <= 0.0 || allPacketsLimit.packetLimitInterval <= 0.0) { -+ allPacketsLimit = null; -+ } -+ final ConfigurationSection section = config.getConfigurationSection("settings.packet-limiter.limits"); -+ -+ // add default packets -+ -+ // auto recipe limiting -+ getDouble("settings.packet-limiter.limits." + -+ "PacketPlayInAutoRecipe" + ".interval", 4.0); -+ getDouble("settings.packet-limiter.limits." + -+ "PacketPlayInAutoRecipe" + ".max-packet-rate", 5.0); -+ getString("settings.packet-limiter.limits." + -+ "PacketPlayInAutoRecipe" + ".action", PacketLimit.ViolateAction.DROP.name()); -+ -+ final Map mojangToSpigot = new HashMap<>(); -+ final Map maps = io.papermc.paper.util.ObfHelper.INSTANCE.mappingsByObfName(); -+ if (maps != null) { -+ maps.forEach((spigotName, classMapping) -> -+ mojangToSpigot.put(classMapping.mojangName(), classMapping.obfName())); -+ } -+ -+ for (final String packetClassName : section.getKeys(false)) { -+ if (packetClassName.equals("all")) { -+ continue; -+ } -+ Class packetClazz = null; -+ -+ for (final String subpackage : List.of("game", "handshake", "login", "status")) { -+ final String fullName = "net.minecraft.network.protocol." + subpackage + "." + packetClassName; -+ try { -+ packetClazz = Class.forName(fullName); -+ break; -+ } catch (final ClassNotFoundException ex) { -+ try { -+ final String spigot = mojangToSpigot.get(fullName); -+ if (spigot != null) { -+ packetClazz = Class.forName(spigot); -+ } -+ } catch (final ClassNotFoundException ignore) {} -+ } -+ } -+ -+ if (packetClazz == null || !net.minecraft.network.protocol.Packet.class.isAssignableFrom(packetClazz)) { -+ MinecraftServer.LOGGER.warn("Packet '" + packetClassName + "' does not exist, cannot limit it! Please update paper.yml"); -+ continue; -+ } -+ -+ if (!(section.get(packetClassName.concat(".interval")) instanceof Number) || !(section.get(packetClassName.concat(".max-packet-rate")) instanceof Number)) { -+ throw new RuntimeException("Packet limit setting " + packetClassName + " is missing interval or max-packet-rate!"); -+ } -+ -+ final String actionString = section.getString(packetClassName.concat(".action"), "KICK"); -+ PacketLimit.ViolateAction action = PacketLimit.ViolateAction.KICK; -+ for (PacketLimit.ViolateAction test : PacketLimit.ViolateAction.values()) { -+ if (actionString.equalsIgnoreCase(test.name())) { -+ action = test; -+ break; -+ } -+ } -+ -+ final double interval = section.getDouble(packetClassName.concat(".interval")); -+ final double rate = section.getDouble(packetClassName.concat(".max-packet-rate")); -+ -+ if (interval > 0.0 && rate > 0.0) { -+ packetSpecificLimits.put((Class)packetClazz, new PacketLimit(interval, rate, action)); -+ } -+ } -+ } - } diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/Connection.java @@ -140,15 +33,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end - allow controlled flushing + // Paper start - packet limiter + protected final Object PACKET_LIMIT_LOCK = new Object(); -+ protected final io.papermc.paper.util.IntervalledCounter allPacketCounts = com.destroystokyo.paper.PaperConfig.allPacketsLimit != null ? new io.papermc.paper.util.IntervalledCounter( -+ (long)(com.destroystokyo.paper.PaperConfig.allPacketsLimit.packetLimitInterval * 1.0e9) ++ protected final @Nullable io.papermc.paper.util.IntervalledCounter allPacketCounts = io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.isEnabled() ? new io.papermc.paper.util.IntervalledCounter( ++ (long)(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.interval() * 1.0e9) + ) : null; + protected final java.util.Map>, io.papermc.paper.util.IntervalledCounter> packetSpecificLimits = new java.util.HashMap<>(); + + private boolean stopReadingPackets; + private void killForPacketSpam() { -+ this.sendPacket(new ClientboundDisconnectPacket(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(com.destroystokyo.paper.PaperConfig.kickMessage, true)[0]), (future) -> { -+ this.disconnect(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(com.destroystokyo.paper.PaperConfig.kickMessage, true)[0]); ++ this.sendPacket(new ClientboundDisconnectPacket(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage, true)[0]), (future) -> { ++ this.disconnect(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage, true)[0]); + }); + this.setReadOnly(); + this.stopReadingPackets = true; @@ -166,29 +59,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; + } + if (this.allPacketCounts != null || -+ com.destroystokyo.paper.PaperConfig.packetSpecificLimits.containsKey(packet.getClass())) { ++ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) { + long time = System.nanoTime(); + synchronized (PACKET_LIMIT_LOCK) { + if (this.allPacketCounts != null) { + this.allPacketCounts.updateAndAdd(1, time); -+ if (this.allPacketCounts.getRate() >= com.destroystokyo.paper.PaperConfig.allPacketsLimit.maxPacketRate) { ++ if (this.allPacketCounts.getRate() >= io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.maxPacketRate()) { + this.killForPacketSpam(); + return; + } + } + + for (Class check = packet.getClass(); check != Object.class; check = check.getSuperclass()) { -+ com.destroystokyo.paper.PaperConfig.PacketLimit packetSpecificLimit = -+ com.destroystokyo.paper.PaperConfig.packetSpecificLimits.get(check); ++ io.papermc.paper.configuration.GlobalConfiguration.PacketLimiter.PacketLimit packetSpecificLimit = ++ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.get(check); + if (packetSpecificLimit == null) { + continue; + } + io.papermc.paper.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> { -+ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.packetLimitInterval * 1.0e9)); ++ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.interval() * 1.0e9)); + }); + counter.updateAndAdd(1, time); -+ if (counter.getRate() >= packetSpecificLimit.maxPacketRate) { -+ switch (packetSpecificLimit.violateAction) { ++ if (counter.getRate() >= packetSpecificLimit.maxPacketRate()) { ++ switch (packetSpecificLimit.action()) { + case DROP: + return; + case KICK: diff --git a/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch b/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch index 1a1df8f325..a8418c10a5 100644 --- a/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch +++ b/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch @@ -208,7 +208,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + final ServerLevel level = serverPlayer.getLevel(); + -+ if (!level.paperConfig.perPlayerMobSpawns) { ++ if (!level.paperConfig().entities.spawning.perPlayerMobSpawns) { + sender.sendMessage(Component.text("Use '/paper mobcaps' for worlds where per-player mob spawning is disabled.", NamedTextColor.RED)); + return; + } diff --git a/patches/server/Add-phantom-creative-and-insomniac-controls.patch b/patches/server/Add-phantom-creative-and-insomniac-controls.patch index 1be89534c3..3399991fb9 100644 --- a/patches/server/Add-phantom-creative-and-insomniac-controls.patch +++ b/patches/server/Add-phantom-creative-and-insomniac-controls.patch @@ -4,22 +4,6 @@ Date: Sat, 25 Apr 2020 15:13:41 -0500 Subject: [PATCH] Add phantom creative and insomniac controls -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - perPlayerMobSpawns = getBoolean("per-player-mob-spawns", true); - } -+ -+ public boolean phantomIgnoreCreative = true; -+ public boolean phantomOnlyAttackInsomniacs = true; -+ private void phantomSettings() { -+ phantomIgnoreCreative = getBoolean("phantoms-do-not-spawn-on-creative-players", phantomIgnoreCreative); -+ phantomOnlyAttackInsomniacs = getBoolean("phantoms-only-attack-insomniacs", phantomOnlyAttackInsomniacs); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/EntitySelector.java @@ -40,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Player entityhuman = (Player) iterator.next(); if (Phantom.this.canAttack(entityhuman, TargetingConditions.DEFAULT)) { -+ if (!level.paperConfig.phantomOnlyAttackInsomniacs || EntitySelector.isInsomniac.test(entityhuman)) // Paper ++ if (!level.paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.isInsomniac.test(entityhuman)) // Paper Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason return true; } @@ -53,7 +37,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Player entityhuman = (Player) iterator.next(); - if (!entityhuman.isSpectator()) { -+ if (!entityhuman.isSpectator() && (!world.paperConfig.phantomIgnoreCreative || !entityhuman.isCreative())) { // Paper ++ if (!entityhuman.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityhuman.isCreative())) { // Paper BlockPos blockposition = entityhuman.blockPosition(); if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) { diff --git a/patches/server/Add-ray-tracing-methods-to-LivingEntity.patch b/patches/server/Add-ray-tracing-methods-to-LivingEntity.patch index cf6261cfad..5f590ed01a 100644 --- a/patches/server/Add-ray-tracing-methods-to-LivingEntity.patch +++ b/patches/server/Add-ray-tracing-methods-to-LivingEntity.patch @@ -52,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return level.clip(raytrace); + } + - public int shieldBlockingDelay = level.paperConfig.shieldBlockingDelay; + public int shieldBlockingDelay = level.paperConfig().misc.shieldBlockingDelay; public int getShieldBlockingDelay() { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java diff --git a/patches/server/Add-setting-for-proxy-online-mode-status.patch b/patches/server/Add-setting-for-proxy-online-mode-status.patch index 3215842db8..5fd9b7c733 100644 --- a/patches/server/Add-setting-for-proxy-online-mode-status.patch +++ b/patches/server/Add-setting-for-proxy-online-mode-status.patch @@ -5,32 +5,6 @@ Subject: [PATCH] Add setting for proxy online mode status TODO: Add isProxyOnlineMode check to Metrics -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ import org.bukkit.configuration.InvalidConfigurationException; - import org.bukkit.configuration.file.YamlConfiguration; - import co.aikar.timings.Timings; - import co.aikar.timings.TimingsManager; -+import org.spigotmc.SpigotConfig; - - public class PaperConfig { - -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void saveEmptyScoreboardTeams() { - saveEmptyScoreboardTeams = getBoolean("settings.save-empty-scoreboard-teams", false); - } -+ -+ public static boolean bungeeOnlineMode = true; -+ private static void bungeeOnlineMode() { -+ bungeeOnlineMode = getBoolean("settings.bungee-online-mode", true); -+ } -+ -+ public static boolean isProxyOnlineMode() { -+ return Bukkit.getOnlineMode() || (SpigotConfig.bungee && bungeeOnlineMode); -+ } - } diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/players/GameProfileCache.java @@ -39,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } }; -+ if (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode()) // Paper - only run in online mode - 100 COL ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()) // Paper - only run in online mode - 100 COL repository.findProfilesByNames(new String[]{name}, Agent.MINECRAFT, profilelookupcallback); GameProfile gameprofile = (GameProfile) atomicreference.get(); @@ -48,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static boolean usesAuthentication() { - return GameProfileCache.usesAuthentication; -+ return com.destroystokyo.paper.PaperConfig.isProxyOnlineMode(); // Paper ++ return io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode(); // Paper } public void add(GameProfile profile) { @@ -62,7 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (server.usesAuthentication() || org.spigotmc.SpigotConfig.bungee) { // Spigot: bungee = online mode, for now. + if (server.usesAuthentication() -+ || (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode())) { // Spigot: bungee = online mode, for now. // Paper - Handle via setting ++ || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode())) { // Spigot: bungee = online mode, for now. // Paper - Handle via setting server.getProfileRepository().findProfilesByNames(astring, Agent.MINECRAFT, callback); } else { String[] astring1 = astring; @@ -75,7 +49,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 GameProfile profile = null; // Only fetch an online UUID in online mode - if ( this.getOnlineMode() || org.spigotmc.SpigotConfig.bungee ) -+ if ( this.getOnlineMode() || com.destroystokyo.paper.PaperConfig.isProxyOnlineMode() ) // Paper - Handle via setting ++ if ( this.getOnlineMode() || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ) // Paper - Handle via setting { profile = this.console.getProfileCache().get(name).orElse(null); } diff --git a/patches/server/Add-support-for-Proxy-Protocol.patch b/patches/server/Add-support-for-Proxy-Protocol.patch index f1383f2048..ae949371a7 100644 --- a/patches/server/Add-support-for-Proxy-Protocol.patch +++ b/patches/server/Add-support-for-Proxy-Protocol.patch @@ -16,20 +16,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end implementation("org.apache.logging.log4j:log4j-iostreams:2.17.1") // Paper implementation("org.apache.logging.log4j:log4j-slf4j18-impl:2.17.1") // Paper -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void useDimensionTypeForCustomSpawners() { - useDimensionTypeForCustomSpawners = getBoolean("settings.use-dimension-type-for-custom-spawners", false); - } -+ -+ public static boolean useProxyProtocol; -+ private static void useProxyProtocol() { -+ useProxyProtocol = getBoolean("settings.proxy-protocol", false); -+ } - } diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java @@ -39,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end + // Paper start - indicate Proxy Protocol usage -+ if (com.destroystokyo.paper.PaperConfig.useProxyProtocol) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.proxyProtocol) { + ServerConnectionListener.LOGGER.info("Paper: Using Proxy Protocol"); + } + // Paper end @@ -52,7 +38,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Object object = j > 0 ? new RateKickingConnection(j) : new Connection(PacketFlow.SERVERBOUND); + // Paper start - Add support for Proxy Protocol -+ if (com.destroystokyo.paper.PaperConfig.useProxyProtocol) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.proxyProtocol) { + channel.pipeline().addAfter("timeout", "haproxy-decoder", new io.netty.handler.codec.haproxy.HAProxyMessageDecoder()); + channel.pipeline().addAfter("haproxy-decoder", "haproxy-handler", new ChannelInboundHandlerAdapter() { + @Override diff --git a/patches/server/Add-support-for-hex-color-codes-in-console.patch b/patches/server/Add-support-for-hex-color-codes-in-console.patch index 2c3d4d9f46..7347e7cb8f 100644 --- a/patches/server/Add-support-for-hex-color-codes-in-console.patch +++ b/patches/server/Add-support-for-hex-color-codes-in-console.patch @@ -5,21 +5,6 @@ Subject: [PATCH] Add support for hex color codes in console Converts upstream's hex color code legacy format into actual hex color codes in the console. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - } - - public static boolean deobfuscateStacktraces = true; -+ public static boolean useRgbForNamedTextColors = true; - private static void loggerSettings() { - deobfuscateStacktraces = getBoolean("settings.loggers.deobfuscate-stacktraces", deobfuscateStacktraces); -+ useRgbForNamedTextColors = getBoolean("settings.loggers.use-rgb-for-named-text-colors", useRgbForNamedTextColors); - } - - public static boolean allowBlockPermanentBreakingExploits = false; diff --git a/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java b/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java @@ -59,7 +44,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package io.papermc.paper.console; + -+import com.destroystokyo.paper.PaperConfig; ++import io.papermc.paper.configuration.GlobalConfiguration; +import io.papermc.paper.adventure.PaperAdventure; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextColor; @@ -227,7 +212,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + Matcher matcher = NAMED_PATTERN.matcher(content); + StringBuilder buffer = new StringBuilder(); -+ final String[] ansiCodes = PaperConfig.useRgbForNamedTextColors ? RGB_ANSI_CODES : ANSI_ANSI_CODES; ++ final String[] ansiCodes = GlobalConfiguration.get().logging.useRgbForNamedTextColors ? RGB_ANSI_CODES : ANSI_ANSI_CODES; + while (matcher.find()) { + int format = LOOKUP.indexOf(Character.toLowerCase(matcher.group().charAt(1))); + if (format != -1) { diff --git a/patches/server/Add-tick-times-API-and-mspt-command.patch b/patches/server/Add-tick-times-API-and-mspt-command.patch index 8491ec021f..96c7b88d6f 100644 --- a/patches/server/Add-tick-times-API-and-mspt-command.patch +++ b/patches/server/Add-tick-times-API-and-mspt-command.patch @@ -109,18 +109,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return text(DF.format(avg), avg >= 50 ? RED : avg >= 40 ? YELLOW : GREEN); + } +} -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java +diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { +--- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java ++++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +@@ -0,0 +0,0 @@ + package io.papermc.paper.configuration; - commands = new HashMap(); - commands.put("paper", new PaperCommand("paper")); -+ commands.put("mspt", new MSPTCommand("mspt")); ++import com.destroystokyo.paper.MSPTCommand; + import com.destroystokyo.paper.Metrics; + import com.destroystokyo.paper.PaperCommand; + import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray; +@@ -0,0 +0,0 @@ public class PaperConfigurations extends Configurations Co-authored-by: Jake Potrebic -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - config.addDefault(path, def); - return config.getString(path, config.getString(path)); - } -+ -+ public static boolean useDisplayNameInQuit = false; -+ private static void useDisplayNameInQuit() { -+ if (version < 21) { -+ boolean oldValue = getBoolean("use-display-name-in-quit-message", useDisplayNameInQuit); -+ set("settings.use-display-name-in-quit-message", oldValue); -+ } -+ useDisplayNameInQuit = getBoolean("settings.use-display-name-in-quit-message", useDisplayNameInQuit); -+ } - } diff --git a/src/main/java/io/papermc/paper/adventure/AdventureComponent.java b/src/main/java/io/papermc/paper/adventure/AdventureComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -1473,7 +1455,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return; } - String leaveMessage = ChatFormatting.YELLOW + this.player.getScoreboardName() + " left the game."; -+ net.kyori.adventure.text.Component leaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? this.player.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(this.player.getScoreboardName())); // Paper - Adventure ++ net.kyori.adventure.text.Component leaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? this.player.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(this.player.getScoreboardName())); // Paper - Adventure - PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), s, leaveMessage); + PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), reason, leaveMessage); // Paper - Adventure @@ -1666,7 +1648,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), entityplayer.kickLeaveMessage != null ? entityplayer.kickLeaveMessage : "\u00A7e" + entityplayer.getScoreboardName() + " left the game"); -+ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName()))); ++ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName()))); this.cserver.getPluginManager().callEvent(playerQuitEvent); entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); @@ -1958,9 +1940,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public String getMotd() { return this.console.getMotd(); @@ -0,0 +0,0 @@ public final class CraftServer implements Server { - return null; - } + return this.spigot; } + // Spigot end + + // Paper start + private Iterable adventure$audiences; @@ -1971,7 +1953,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + return this.adventure$audiences; + } - // Paper end ++ // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/All-chunks-are-slime-spawn-chunks-toggle.patch b/patches/server/All-chunks-are-slime-spawn-chunks-toggle.patch index 0c4e4c9d5e..da66e3dd55 100644 --- a/patches/server/All-chunks-are-slime-spawn-chunks-toggle.patch +++ b/patches/server/All-chunks-are-slime-spawn-chunks-toggle.patch @@ -4,20 +4,6 @@ Date: Thu, 3 Mar 2016 01:19:22 -0600 Subject: [PATCH] All chunks are slime spawn chunks toggle -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void disableChestCatDetection() { - disableChestCatDetection = getBoolean("game-mechanics.disable-chest-cat-detection", false); - } -+ -+ public boolean allChunksAreSlimeChunks; -+ private void allChunksAreSlimeChunks() { -+ allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", false); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Slime.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ChunkPos chunkcoordintpair = new ChunkPos(pos); - boolean flag = WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot -+ boolean flag = world.getMinecraftWorld().paperConfig.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper ++ boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper if (random.nextInt(10) == 0 && flag && pos.getY() < 40) { return checkMobSpawnRules(type, world, spawnReason, pos, random); @@ -40,7 +26,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean isSlimeChunk() { // 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk - return WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; -+ return this.worldServer.paperConfig.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper ++ return this.worldServer.paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper } @Override diff --git a/patches/server/Allow-Reloading-of-Custom-Permissions.patch b/patches/server/Allow-Reloading-of-Custom-Permissions.patch index a2c4d63f75..2b666f0301 100644 --- a/patches/server/Allow-Reloading-of-Custom-Permissions.patch +++ b/patches/server/Allow-Reloading-of-Custom-Permissions.patch @@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + @Override + public void reloadPermissions() { + pluginManager.clearPermissions(); -+ if (com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) loadCustomPermissions(); ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions(); + for (Plugin plugin : pluginManager.getPlugins()) { + for (Permission perm : plugin.getDescription().getPermissions()) { + try { @@ -27,7 +27,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + } -+ if (!com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) loadCustomPermissions(); ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions(); + DefaultPermissions.registerCorePermissions(); + CraftDefaultPermissions.registerCorePermissions(); + } diff --git a/patches/server/Allow-disabling-armour-stand-ticking.patch b/patches/server/Allow-disabling-armour-stand-ticking.patch index ee516f5d12..b690016c2d 100644 --- a/patches/server/Allow-disabling-armour-stand-ticking.patch +++ b/patches/server/Allow-disabling-armour-stand-ticking.patch @@ -4,21 +4,6 @@ Date: Wed, 15 Aug 2018 01:26:09 -0700 Subject: [PATCH] Allow disabling armour stand ticking -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void armorStandEntityLookups() { - armorStandEntityLookups = getBoolean("armor-stands-do-collision-entity-lookups", true); - } -+ -+ public boolean armorStandTick = true; -+ private void armorStandTick() { -+ this.armorStandTick = this.getBoolean("armor-stands-tick", this.armorStandTick); -+ log("ArmorStand ticking is " + (this.armorStandTick ? "enabled" : "disabled") + " by default"); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java @@ -36,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public ArmorStand(EntityType type, Level world) { super(type, world); -+ if (world != null) this.canTick = world.paperConfig.armorStandTick; // Paper - armour stand ticking ++ if (world != null) this.canTick = world.paperConfig().entities.armorStands.tick; // Paper - armour stand ticking this.handItems = NonNullList.withSize(2, ItemStack.EMPTY); this.armorItems = NonNullList.withSize(4, ItemStack.EMPTY); this.headPose = ArmorStand.DEFAULT_HEAD_POSE; diff --git a/patches/server/Allow-disabling-mob-spawner-spawn-egg-transformation.patch b/patches/server/Allow-disabling-mob-spawner-spawn-egg-transformation.patch index 91db7a8951..f3526079f7 100644 --- a/patches/server/Allow-disabling-mob-spawner-spawn-egg-transformation.patch +++ b/patches/server/Allow-disabling-mob-spawner-spawn-egg-transformation.patch @@ -4,22 +4,6 @@ Date: Fri, 9 Oct 2020 20:30:12 -0400 Subject: [PATCH] Allow disabling mob spawner spawn egg transformation -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - fixCuringZombieVillagerDiscountExploit = getBoolean("game-mechanics.fix-curing-zombie-villager-discount-exploit", fixCuringZombieVillagerDiscountExploit); - } - -+ public boolean disableMobSpawnerSpawnEggTransformation = false; -+ private void disableMobSpawnerSpawnEggTransformation() { -+ disableMobSpawnerSpawnEggTransformation = getBoolean("game-mechanics.disable-mob-spawner-spawn-egg-transformation", disableMobSpawnerSpawnEggTransformation); -+ } -+ - public short keepLoadedRange; - private void keepLoadedRange() { - keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); diff --git a/src/main/java/net/minecraft/world/item/SpawnEggItem.java b/src/main/java/net/minecraft/world/item/SpawnEggItem.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/item/SpawnEggItem.java @@ -29,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockState iblockdata = world.getBlockState(blockposition); - if (iblockdata.is(Blocks.SPAWNER)) { -+ if (!world.paperConfig.disableMobSpawnerSpawnEggTransformation && iblockdata.is(Blocks.SPAWNER)) { // Paper ++ if (!world.paperConfig().entities.spawning.disableMobSpawnerSpawnEggTransformation && iblockdata.is(Blocks.SPAWNER)) { // Paper BlockEntity tileentity = world.getBlockEntity(blockposition); if (tileentity instanceof SpawnerBlockEntity) { diff --git a/patches/server/Allow-for-toggling-of-spawn-chunks.patch b/patches/server/Allow-for-toggling-of-spawn-chunks.patch index 3c94f266a3..f9959c7fcc 100644 --- a/patches/server/Allow-for-toggling-of-spawn-chunks.patch +++ b/patches/server/Allow-for-toggling-of-spawn-chunks.patch @@ -4,21 +4,6 @@ Date: Thu, 3 Mar 2016 03:53:43 -0600 Subject: [PATCH] Allow for toggling of spawn chunks -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - hardDespawnDistances.put(category, hardDistance); - } - } -+ -+ public boolean keepSpawnInMemory; -+ private void keepSpawnInMemory() { -+ keepSpawnInMemory = getBoolean("keep-spawn-loaded", true); -+ log("Keep spawn chunk loaded: " + keepSpawnInMemory); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/Level.java @@ -27,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }); // CraftBukkit end timings = new co.aikar.timings.WorldTimingsHandler(this); // Paper - code below can generate new world and access timings -+ this.keepSpawnInMemory = this.paperConfig.keepSpawnInMemory; // Paper ++ this.keepSpawnInMemory = this.paperConfig().spawn.keepSpawnLoaded; // Paper this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime); this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime); } diff --git a/patches/server/Allow-nerfed-mobs-to-jump-and-take-water-damage.patch b/patches/server/Allow-nerfed-mobs-to-jump-and-take-water-damage.patch index 67b273d72f..92dc643a4c 100644 --- a/patches/server/Allow-nerfed-mobs-to-jump-and-take-water-damage.patch +++ b/patches/server/Allow-nerfed-mobs-to-jump-and-take-water-damage.patch @@ -4,32 +4,6 @@ Date: Tue, 1 Mar 2016 13:24:16 -0600 Subject: [PATCH] Allow nerfed mobs to jump and take water damage -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - fishingMaxTicks = getInt("fishing-time-range.MaximumTicks", 600); - log("Fishing time ranges are between " + fishingMinTicks +" and " + fishingMaxTicks + " ticks"); - } -+ -+ public boolean nerfedMobsShouldJump; -+ private void nerfedMobsShouldJump() { -+ nerfedMobsShouldJump = getBoolean("spawner-nerfed-mobs-should-jump", false); -+ } - } -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { - return this.isInWater() || this.isInRain(); - } - -+ @Deprecated public final boolean isInWaterOrRainOrBubble() { return isInWaterRainOrBubble(); } // Paper - OBFHELPER - public boolean isInWaterRainOrBubble() { - return this.isInWater() || this.isInRain() || this.isInBubbleColumn(); - } diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java @@ -69,7 +43,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public FloatGoal(Mob mob) { this.mob = mob; -+ if (mob.getCommandSenderWorld().paperConfig.nerfedMobsShouldJump) mob.goalFloat = this; // Paper ++ if (mob.getCommandSenderWorld().paperConfig().entities.behavior.spawnerNerfedMobsShouldJump) mob.goalFloat = this; // Paper this.setFlags(EnumSet.of(Goal.Flag.JUMP)); mob.getNavigation().setCanFloat(true); } diff --git a/patches/server/Allow-specifying-a-custom-authentication-servers-dow.patch b/patches/server/Allow-specifying-a-custom-authentication-servers-dow.patch index cfe13c2af0..236ac24837 100644 --- a/patches/server/Allow-specifying-a-custom-authentication-servers-dow.patch +++ b/patches/server/Allow-specifying-a-custom-authentication-servers-dow.patch @@ -5,27 +5,6 @@ Subject: [PATCH] Allow specifying a custom "authentication servers down" kick message -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ - package com.destroystokyo.paper; - -+import com.google.common.base.Strings; - import com.google.common.base.Throwables; - - import java.io.File; -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void suggestPlayersWhenNull() { - suggestPlayersWhenNullTabCompletions = getBoolean("settings.suggest-player-names-when-null-tab-completions", suggestPlayersWhenNullTabCompletions); - } -+ -+ public static String authenticationServersDownKickMessage = ""; // empty = use translatable message -+ private static void authenticationServersDownKickMessage() { -+ authenticationServersDownKickMessage = Strings.emptyToNull(getString("messages.kick.authentication-servers-down", authenticationServersDownKickMessage)); -+ } - } diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -35,8 +14,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT; } else { + // Paper start -+ if (com.destroystokyo.paper.PaperConfig.authenticationServersDownKickMessage != null) { -+ ServerLoginPacketListenerImpl.this.disconnect(Component.literal(com.destroystokyo.paper.PaperConfig.authenticationServersDownKickMessage)); ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.authenticationServersDown.isEmpty()) { ++ ServerLoginPacketListenerImpl.this.disconnect(Component.literal(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.authenticationServersDown)); + } else // Paper end ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); ServerLoginPacketListenerImpl.LOGGER.error("Couldn't verify username because servers are unavailable"); diff --git a/patches/server/Allow-using-signs-inside-spawn-protection.patch b/patches/server/Allow-using-signs-inside-spawn-protection.patch index c6c968f4f6..6aa816b431 100644 --- a/patches/server/Allow-using-signs-inside-spawn-protection.patch +++ b/patches/server/Allow-using-signs-inside-spawn-protection.patch @@ -4,20 +4,6 @@ Date: Wed, 15 Apr 2020 01:54:02 +0200 Subject: [PATCH] Allow using signs inside spawn protection -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - delayChunkUnloadsBy *= 20; - } - } -+ -+ public boolean allowUsingSignsInsideSpawnProtection = false; -+ private void allowUsingSignsInsideSpawnProtection() { -+ allowUsingSignsInsideSpawnProtection = getBoolean("allow-using-signs-inside-spawn-protection", allowUsingSignsInsideSpawnProtection); -+ } - } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (blockposition.getY() < i) { - if (this.awaitingPositionFromClient == null && this.player.distanceToSqr((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D) < 64.0D && worldserver.mayInteract(this.player, blockposition)) { -+ if (this.awaitingPositionFromClient == null && this.player.distanceToSqr((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D) < 64.0D && (worldserver.mayInteract(this.player, blockposition) || (worldserver.paperConfig.allowUsingSignsInsideSpawnProtection && worldserver.getBlockState(blockposition).getBlock() instanceof net.minecraft.world.level.block.SignBlock))) { // Paper - sign check ++ if (this.awaitingPositionFromClient == null && this.player.distanceToSqr((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D) < 64.0D && (worldserver.mayInteract(this.player, blockposition) || (worldserver.paperConfig().spawn.allowUsingSignsInsideSpawnProtection && worldserver.getBlockState(blockposition).getBlock() instanceof net.minecraft.world.level.block.SignBlock))) { // Paper - sign check this.player.stopUsingItem(); // CraftBukkit - SPIGOT-4706 InteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock); diff --git a/patches/server/Anti-Xray.patch b/patches/server/Anti-Xray.patch index c0db4db1b4..8b0f0cc056 100644 --- a/patches/server/Anti-Xray.patch +++ b/patches/server/Anti-Xray.patch @@ -4,65 +4,6 @@ Date: Thu, 25 Nov 2021 13:27:51 +0100 Subject: [PATCH] Anti-Xray -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ - package com.destroystokyo.paper; - -+import java.util.Arrays; - import java.util.List; - - import java.util.stream.Collectors; - import it.unimi.dsi.fastutil.objects.Reference2IntMap; - import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; - import net.minecraft.world.entity.MobCategory; -+import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray.EngineMode; - import org.bukkit.Bukkit; - import org.bukkit.configuration.file.YamlConfiguration; - import org.spigotmc.SpigotWorldConfig; -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void lightQueueSize() { - lightQueueSize = getInt("light-queue-size", lightQueueSize); - } -+ -+ public boolean antiXray; -+ public EngineMode engineMode; -+ public int maxBlockHeight; -+ public int updateRadius; -+ public boolean lavaObscures; -+ public boolean usePermission; -+ public List hiddenBlocks; -+ public List replacementBlocks; -+ private void antiXray() { -+ antiXray = getBoolean("anti-xray.enabled", false); -+ engineMode = EngineMode.getById(getInt("anti-xray.engine-mode", EngineMode.HIDE.getId())); -+ engineMode = engineMode == null ? EngineMode.HIDE : engineMode; -+ maxBlockHeight = getInt("anti-xray.max-block-height", 64); -+ updateRadius = getInt("anti-xray.update-radius", 2); -+ lavaObscures = getBoolean("anti-xray.lava-obscures", false); -+ usePermission = getBoolean("anti-xray.use-permission", false); -+ hiddenBlocks = getList("anti-xray.hidden-blocks", Arrays.asList("copper_ore", "deepslate_copper_ore", "gold_ore", "deepslate_gold_ore", "iron_ore", "deepslate_iron_ore", -+ "coal_ore", "deepslate_coal_ore", "lapis_ore", "deepslate_lapis_ore", "mossy_cobblestone", "obsidian", "chest", "diamond_ore", "deepslate_diamond_ore", -+ "redstone_ore", "deepslate_redstone_ore", "clay", "emerald_ore", "deepslate_emerald_ore", "ender_chest")); -+ replacementBlocks = getList("anti-xray.replacement-blocks", Arrays.asList("stone", "oak_planks", "deepslate")); -+ if (PaperConfig.version < 19) { -+ hiddenBlocks.remove("lit_redstone_ore"); -+ int index = replacementBlocks.indexOf("planks"); -+ if (index != -1) { -+ replacementBlocks.set(index, "oak_planks"); -+ } -+ set("anti-xray.hidden-blocks", hiddenBlocks); -+ set("anti-xray.replacement-blocks", replacementBlocks); -+ } -+ log("Anti-Xray: " + (antiXray ? "enabled" : "disabled") + " / Engine Mode: " + engineMode.getDescription() + " / Up to " + ((maxBlockHeight >> 4) << 4) + " blocks / Update Radius: " + updateRadius); -+ if (antiXray && usePermission) { -+ Bukkit.getLogger().warning("You have enabled permission-based Anti-Xray checking - depending on your permission plugin, this may cause performance issues"); -+ } -+ } - } - diff --git a/src/main/java/com/destroystokyo/paper/antixray/BitStorageReader.java b/src/main/java/com/destroystokyo/paper/antixray/BitStorageReader.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -264,7 +205,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package com.destroystokyo.paper.antixray; + -+import com.destroystokyo.paper.PaperWorldConfig; ++import io.papermc.paper.configuration.WorldConfiguration; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Registry; @@ -284,11 +225,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.*; +import org.bukkit.Bukkit; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; + ++import java.lang.reflect.Type; +import java.util.*; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.IntSupplier; ++import java.util.function.Predicate; + +public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockController { + @@ -317,7 +262,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + public ChunkPacketBlockControllerAntiXray(Level level, Executor executor) { + this.executor = executor; -+ PaperWorldConfig paperWorldConfig = level.paperConfig; ++ WorldConfiguration.AntiCheat.AntiXRay paperWorldConfig = level.paperConfig().anticheat.antiXray; + engineMode = paperWorldConfig.engineMode; + maxBlockHeight = paperWorldConfig.maxBlockHeight >> 4 << 4; + updateRadius = paperWorldConfig.updateRadius; @@ -901,6 +846,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + HIDE(1, "hide ores"), + OBFUSCATE(2, "obfuscate"); + ++ public static final ScalarSerializer SERIALIZER = new Serializer(); ++ + private final int id; + private final String description; + @@ -926,6 +873,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public String getDescription() { + return description; + } ++ ++ static class Serializer extends ScalarSerializer { ++ ++ Serializer() { ++ super(EngineMode.class); ++ } ++ ++ @Override ++ public EngineMode deserialize(Type type, Object obj) throws SerializationException { ++ if (obj instanceof Integer num) { ++ return Objects.requireNonNullElse(EngineMode.getById(num), HIDE); ++ } ++ throw new SerializationException(obj + " is not of a valid type (" + type + ") for this node"); ++ } ++ ++ @Override ++ protected Object serialize(EngineMode item, Predicate> typeSupported) { ++ return item.getId(); ++ } ++ } + } +} diff --git a/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfo.java b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfo.java @@ -1049,6 +1016,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + chunkPacketBlockControllerAntiXray.obfuscate(this); + } +} +diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java ++++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +@@ -0,0 +0,0 @@ package io.papermc.paper.configuration; + + import com.destroystokyo.paper.Metrics; + import com.destroystokyo.paper.PaperCommand; ++import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray; + import com.google.common.collect.Table; + import com.mojang.logging.LogUtils; + import io.leangen.geantyref.TypeToken; +@@ -0,0 +0,0 @@ public class PaperConfigurations extends Configurations(new TypeToken>() {}, Registry.ENTITY_TYPE, true)) + .register(new RegistryValueSerializer<>(Item.class, Registry.ITEM, true)) diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java @@ -1193,8 +1180,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { // Holder holder = worlddimension.typeHolder(); // CraftBukkit - decompile error // Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error -- super(iworlddataserver, resourcekey, worlddimension.typeHolder(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env); -+ super(iworlddataserver, resourcekey, worlddimension.typeHolder(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, executor); // Paper - Async-Anti-Xray - Pass executor +- super(iworlddataserver, resourcekey, worlddimension.typeHolder(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), spigotConfig)); // Paper ++ super(iworlddataserver, resourcekey, worlddimension.typeHolder(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), spigotConfig), executor); // Paper - Async-Anti-Xray - Pass executor this.pvpMode = minecraftserver.isPvpAllowed(); this.convertable = convertable_conversionsession; this.uuid = WorldUUID.getUUID(convertable_conversionsession.levelDirectory.path().toFile()); @@ -1225,27 +1212,28 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot + } + // Paper end - public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper + public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray - ++ public final co.aikar.timings.WorldTimingsHandler timings; // Paper public static BlockPos lastPhysicsProblem; // Spigot + private org.spigotmc.TickLimiter entityLimiter; @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public abstract ResourceKey getTypeKey(); -- protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env) { -+ protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor +- protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator) { // Paper ++ protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot - this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper + this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper this.generator = gen; @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - this.keepSpawnInMemory = this.paperConfig.keepSpawnInMemory; // Paper + this.keepSpawnInMemory = this.paperConfig().spawn.keepSpawnLoaded; // Paper this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime); this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime); -+ this.chunkPacketBlockController = this.paperConfig.antiXray ? new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray ++ this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray } // Paper start diff --git a/patches/server/Asynchronous-chunk-IO-and-loading.patch b/patches/server/Asynchronous-chunk-IO-and-loading.patch index e9632bb95e..29e98e3f04 100644 --- a/patches/server/Asynchronous-chunk-IO-and-loading.patch +++ b/patches/server/Asynchronous-chunk-IO-and-loading.patch @@ -160,76 +160,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public static Timing getTickList(ServerLevel worldserver, String timingsType) { -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ - package com.destroystokyo.paper; - -+import com.destroystokyo.paper.io.chunk.ChunkTaskManager; - import com.google.common.base.Strings; - import com.google.common.base.Throwables; - -@@ -0,0 +0,0 @@ public class PaperConfig { - } - tabSpamLimit = getInt("settings.spam-limiter.tab-spam-limit", tabSpamLimit); - } -+ -+ public static boolean asyncChunks = false; -+ private static void asyncChunks() { -+ ConfigurationSection section; -+ if (version < 15) { -+ section = config.createSection("settings.async-chunks"); -+ section.set("threads", -1); -+ } else { -+ section = config.getConfigurationSection("settings.async-chunks"); -+ if (section == null) { -+ section = config.createSection("settings.async-chunks"); -+ } -+ } -+ // Clean up old configs -+ if (section.contains("load-threads")) { -+ if (!section.contains("threads")) { -+ section.set("threads", section.get("load-threads")); -+ } -+ section.set("load-threads", null); -+ } -+ section.set("generation", null); -+ section.set("enabled", null); -+ section.set("thread-per-world-generation", null); -+ -+ int threads = getInt("settings.async-chunks.threads", -1); -+ int cpus = Runtime.getRuntime().availableProcessors() / 2; -+ if (threads <= 0) { -+ if (cpus <= 4) { -+ threads = cpus <= 2 ? 1 : 2; -+ } else { -+ threads = (int) Math.min(Integer.getInteger("paper.maxChunkThreads", 4), cpus / 2); -+ } -+ } -+ if (cpus == 1 && !Boolean.getBoolean("Paper.allowAsyncChunksSingleCore")) { -+ asyncChunks = false; -+ } else { -+ asyncChunks = true; -+ } -+ -+ // Let Shared Host set some limits -+ String sharedHostThreads = System.getenv("PAPER_ASYNC_CHUNKS_SHARED_HOST_THREADS"); -+ if (sharedHostThreads != null) { -+ try { -+ threads = Math.max(1, Math.min(threads, Integer.parseInt(sharedHostThreads))); -+ } catch (NumberFormatException ignored) {} -+ } -+ -+ if (!asyncChunks) { -+ log("Async Chunks: Disabled - Chunks will be managed synchronously, and will cause tremendous lag."); -+ } else { -+ ChunkTaskManager.initGlobalLoadThreads(threads); -+ log("Async Chunks: Enabled - Chunks will be loaded much faster, without lag."); -+ } -+ } - } diff --git a/src/main/java/com/destroystokyo/paper/io/IOUtil.java b/src/main/java/com/destroystokyo/paper/io/IOUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -1793,6 +1723,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import com.destroystokyo.paper.io.IOUtil; +import com.destroystokyo.paper.io.PrioritizedTaskQueue; +import com.destroystokyo.paper.io.QueueExecutorThread; ++import io.papermc.paper.configuration.GlobalConfiguration; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; @@ -1919,6 +1850,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + ++ public static void processConfiguration(GlobalConfiguration.AsyncChunks config) { ++ int cpus = Runtime.getRuntime().availableProcessors() / 2; ++ if (config.threads <= 0) { ++ if (cpus <= 4) { ++ config.threads = cpus <= 2 ? 1 : 2; ++ } else { ++ config.threads = (int) Math.min(Integer.getInteger("paper.maxChunkThreads", 4), cpus / 2); ++ } ++ } ++ if (cpus == 1 && !Boolean.getBoolean("Paper.allowAsyncChunksSingleCore")) { ++ config.asyncChunks = false; ++ } else { ++ config.asyncChunks = true; ++ } ++ ++ // Let Shared Host set some limits ++ String sharedHostThreads = System.getenv("PAPER_ASYNC_CHUNKS_SHARED_HOST_THREADS"); ++ if (sharedHostThreads != null) { ++ try { ++ config.threads = Math.max(1, Math.min(config.threads, Integer.parseInt(sharedHostThreads))); ++ } catch (NumberFormatException ignored) {} ++ } ++ ++ if (config.asyncChunks) { ++ ChunkTaskManager.initGlobalLoadThreads(config.threads); ++ } ++ } ++ + public static void initGlobalLoadThreads(int threads) { + if (threads <= 0 || globalWorkers != null) { + return; @@ -3405,7 +3364,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end return regionfile; } else { - if (this.regionCache.size() >= com.destroystokyo.paper.PaperConfig.regionFileCacheSize) { // Paper - configurable + if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - configurable @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync); diff --git a/patches/server/Basic-PlayerProfile-API.patch b/patches/server/Basic-PlayerProfile-API.patch index db170f2416..92ed87bbaf 100644 --- a/patches/server/Basic-PlayerProfile-API.patch +++ b/patches/server/Basic-PlayerProfile-API.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package com.destroystokyo.paper.profile; + -+import com.destroystokyo.paper.PaperConfig; ++import io.papermc.paper.configuration.GlobalConfiguration; +import com.google.common.base.Charsets; +import com.google.common.collect.Iterables; +import com.mojang.authlib.GameProfile; @@ -190,7 +190,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Override + public boolean completeFromCache() { -+ return completeFromCache(false, PaperConfig.isProxyOnlineMode()); ++ return completeFromCache(false, GlobalConfiguration.get().proxies.isProxyOnlineMode()); + } + + public boolean completeFromCache(boolean onlineMode) { @@ -233,7 +233,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public boolean complete(boolean textures) { -+ return complete(textures, PaperConfig.isProxyOnlineMode()); ++ return complete(textures, GlobalConfiguration.get().proxies.isProxyOnlineMode()); + } + public boolean complete(boolean textures, boolean onlineMode) { + MinecraftServer server = MinecraftServer.getServer(); @@ -593,8 +593,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } File file = (File) optionset.valueOf("universe"); // CraftBukkit -- Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), file); -+ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file); // Paper +- Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper ++ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper // CraftBukkit start String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName); LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath()); @@ -644,7 +644,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public final class CraftServer implements Server { public boolean suggestPlayerNamesWhenNullTabCompletions() { - return com.destroystokyo.paper.PaperConfig.suggestPlayersWhenNullTabCompletions; + return io.papermc.paper.configuration.GlobalConfiguration.get().commands.suggestPlayerNamesWhenNullTabCompletions; } + + @Override diff --git a/patches/server/Block-Enderpearl-Travel-Exploit.patch b/patches/server/Block-Enderpearl-Travel-Exploit.patch index da3b40a25b..f478c4ce7f 100644 --- a/patches/server/Block-Enderpearl-Travel-Exploit.patch +++ b/patches/server/Block-Enderpearl-Travel-Exploit.patch @@ -11,21 +11,6 @@ This disables that by not saving the thrower when the chunk is unloaded. This is mainly useful for survival servers that do not allow freeform teleporting. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void disableSprintInterruptionOnAttack() { - disableSprintInterruptionOnAttack = getBoolean("game-mechanics.disable-sprint-interruption-on-attack", false); - } -+ -+ public boolean disableEnderpearlExploit = true; -+ private void disableEnderpearlExploit() { -+ disableEnderpearlExploit = getBoolean("game-mechanics.disable-unloaded-chunk-enderpearl-exploit", disableEnderpearlExploit); -+ log("Disable Unloaded Chunk Enderpearl Exploit: " + (disableEnderpearlExploit ? "enabled" : "disabled")); -+ } - } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -35,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void onTickingEnd(Entity entity) { ServerLevel.this.entityTickList.remove(entity); + // Paper start - Reset pearls when they stop being ticked -+ if (paperConfig.disableEnderpearlExploit && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) { ++ if (paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) { + pearl.cachedOwner = null; + pearl.ownerUUID = null; + } @@ -51,7 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void readAdditionalSaveData(CompoundTag nbt) { if (nbt.hasUUID("Owner")) { this.ownerUUID = nbt.getUUID("Owner"); -+ if (this instanceof ThrownEnderpearl && this.level != null && this.level.paperConfig.disableEnderpearlExploit) { this.ownerUUID = null; } // Paper - Don't store shooter name for pearls to block enderpearl travel exploit ++ if (this instanceof ThrownEnderpearl && this.level != null && this.level.paperConfig().fixes.disableUnloadedChunkEnderpearlExploit) { this.ownerUUID = null; } // Paper - Don't store shooter name for pearls to block enderpearl travel exploit } this.leftOwner = nbt.getBoolean("LeftOwner"); diff --git a/patches/server/Book-Size-Limits.patch b/patches/server/Book-Size-Limits.patch index ac4065520b..784f426fff 100644 --- a/patches/server/Book-Size-Limits.patch +++ b/patches/server/Book-Size-Limits.patch @@ -5,24 +5,6 @@ Subject: [PATCH] Book Size Limits Puts some limits on the size of books. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - } - } - -+ public static int maxBookPageSize = 2560; -+ public static double maxBookTotalSizeMultiplier = 0.98D; -+ private static void maxBookSize() { -+ maxBookPageSize = Math.min(8192, getInt("settings.book-size.page-max", maxBookPageSize)); -+ maxBookTotalSizeMultiplier = getDouble("settings.book-size.total-multiplier", maxBookTotalSizeMultiplier); -+ } -+ - public static boolean asyncChunks = false; - private static void asyncChunks() { - ConfigurationSection section; diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -35,8 +17,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (!this.cserver.isPrimaryThread()) { + List pageList = packet.getPages(); + long byteTotal = 0; -+ int maxBookPageSize = com.destroystokyo.paper.PaperConfig.maxBookPageSize; -+ double multiplier = Math.max(0.3D, Math.min(1D, com.destroystokyo.paper.PaperConfig.maxBookTotalSizeMultiplier)); ++ int maxBookPageSize = io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.pageMax; ++ double multiplier = Math.max(0.3D, Math.min(1D, io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.totalMultiplier)); + long byteAllowed = maxBookPageSize; + for (String testString : pageList) { + int byteLength = testString.getBytes(java.nio.charset.StandardCharsets.UTF_8).length; diff --git a/patches/server/Break-up-and-make-tab-spam-limits-configurable.patch b/patches/server/Break-up-and-make-tab-spam-limits-configurable.patch index b0fb581767..221127d001 100644 --- a/patches/server/Break-up-and-make-tab-spam-limits-configurable.patch +++ b/patches/server/Break-up-and-make-tab-spam-limits-configurable.patch @@ -21,29 +21,6 @@ Splitting the field up and making it configurable allows for server owners to take the burden of this into their own hand without having to rely on plugins doing unsafe things. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - Bukkit.getLogger().log(Level.INFO, "Using Aikar's Alternative Luck Formula to apply Luck attribute to all loot pool calculations. See https://luckformula.emc.gs"); - } - } -+ -+ public static int tabSpamIncrement = 1; -+ public static int tabSpamLimit = 500; -+ private static void tabSpamLimiters() { -+ tabSpamIncrement = getInt("settings.spam-limiter.tab-spam-increment", tabSpamIncrement); -+ // Older versions used a smaller limit, which is too low for 1.13, we'll bump this up if default -+ if (version < 14) { -+ if (tabSpamIncrement == 10) { -+ set("settings.spam-limiter.tab-spam-increment", 2); -+ tabSpamIncrement = 2; -+ } -+ } -+ tabSpamLimit = getInt("settings.spam-limiter.tab-spam-limit", tabSpamLimit); -+ } - } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -69,7 +46,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.getWorldServer()); // Paper - run this async // CraftBukkit start - if (this.chatSpamTickCount.addAndGet(1) > 500 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { -+ if (this.chatSpamTickCount.addAndGet(com.destroystokyo.paper.PaperConfig.tabSpamIncrement) > com.destroystokyo.paper.PaperConfig.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper start - split and make configurable ++ if (this.chatSpamTickCount.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper start - split and make configurable server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper return; } diff --git a/patches/server/Buffer-joins-to-world.patch b/patches/server/Buffer-joins-to-world.patch index 2634c25596..d11cf04663 100644 --- a/patches/server/Buffer-joins-to-world.patch +++ b/patches/server/Buffer-joins-to-world.patch @@ -7,46 +7,22 @@ This patch buffers the number of logins which will attempt to join the world per tick, this attempts to reduce the impact that join floods has on the server -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - } - } - -+ public static int maxJoinsPerTick; -+ private static void maxJoinsPerTick() { -+ maxJoinsPerTick = getInt("settings.max-joins-per-tick", 3); -+ } -+ - public static void registerCommands() { - for (Map.Entry entry : commands.entrySet()) { - MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Paper", entry.getValue()); diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java -@@ -0,0 +0,0 @@ import net.minecraft.network.protocol.Packet; - import net.minecraft.network.protocol.PacketFlow; - import net.minecraft.network.protocol.game.ClientboundDisconnectPacket; - import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; -+import net.minecraft.server.MinecraftServer; - import net.minecraft.server.RunningOnDifferentThreadException; - import net.minecraft.server.network.ServerGamePacketListenerImpl; - import net.minecraft.server.network.ServerLoginPacketListenerImpl; @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { } // Paper end -+ private static final int MAX_PER_TICK = com.destroystokyo.paper.PaperConfig.maxJoinsPerTick; // Paper ++ private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper + private static int joinAttemptsThisTick; // Paper + private static int currTick; // Paper public void tick() { this.flushQueue(); + // Paper start -+ if (currTick != MinecraftServer.currentTick) { -+ currTick = MinecraftServer.currentTick; ++ if (currTick != net.minecraft.server.MinecraftServer.currentTick) { ++ currTick = net.minecraft.server.MinecraftServer.currentTick; + joinAttemptsThisTick = 0; + } + // Paper end diff --git a/patches/server/Cap-Entity-Collisions.patch b/patches/server/Cap-Entity-Collisions.patch index 47578814fd..7f3b59fb6d 100644 --- a/patches/server/Cap-Entity-Collisions.patch +++ b/patches/server/Cap-Entity-Collisions.patch @@ -11,21 +11,6 @@ just as it does in Vanilla, but entity pushing logic will be capped. You can set this to 0 to disable collisions. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - treasureMapsAlreadyDiscoveredVillager = getBoolean("treasure-maps-find-already-discovered.villager-trade", treasureMapsAlreadyDiscoveredVillager); - treasureMapsAlreadyDiscoveredLootTable = getBooleanOrNull("treasure-maps-find-already-discovered.loot-tables", treasureMapsAlreadyDiscoveredLootTable); - } -+ -+ public int maxCollisionsPerEntity = 8; -+ private void maxEntityCollision() { -+ maxCollisionsPerEntity = getInt( "max-entity-collisions", this.spigotConfig.getInt("max-entity-collisions", this.maxCollisionsPerEntity, false) ); -+ log( "Max Entity Collisions: " + maxCollisionsPerEntity ); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java @@ -47,8 +32,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - for (j = 0; j < list.size(); ++j) { -+ this.numCollisions = Math.max(0, this.numCollisions - this.level.paperConfig.maxCollisionsPerEntity); // Paper -+ for (j = 0; j < list.size() && this.numCollisions < this.level.paperConfig.maxCollisionsPerEntity; ++j) { // Paper ++ this.numCollisions = Math.max(0, this.numCollisions - this.level.paperConfig().collisions.maxEntityCollisions); // Paper ++ for (j = 0; j < list.size() && this.numCollisions < this.level.paperConfig().collisions.maxEntityCollisions; ++j) { // Paper Entity entity = (Entity) list.get(j); + entity.numCollisions++; // Paper + this.numCollisions++; // Paper diff --git a/patches/server/Chunk-debug-command.patch b/patches/server/Chunk-debug-command.patch index b97361140b..fb2866807c 100644 --- a/patches/server/Chunk-debug-command.patch +++ b/patches/server/Chunk-debug-command.patch @@ -71,7 +71,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super(name); @@ -0,0 +0,0 @@ public class PaperCommand extends Command { if (args.length == 3) - return getListMatchingLast(sender, args, EntityType.getEntityNameList().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new)); + return getListMatchingLast(sender, args, Registry.ENTITY_TYPE.keySet().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new)); break; + case "debug": + if (args.length == 2) { @@ -366,7 +366,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + worldData.addProperty("name", world.getWorld().getName()); + worldData.addProperty("view-distance", world.spigotConfig.viewDistance); + worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); -+ worldData.addProperty("keep-spawn-loaded-range", world.paperConfig.keepLoadedRange); ++ worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange); + worldData.addProperty("visible-chunk-count", visibleChunks.size()); + worldData.addProperty("loaded-chunk-count", chunkMap.entitiesInLevel.size()); + worldData.addProperty("verified-fully-loaded-chunks", fullLoadedChunks); diff --git a/patches/server/Climbing-should-not-bypass-cramming-gamerule.patch b/patches/server/Climbing-should-not-bypass-cramming-gamerule.patch index a186f8bde7..699c5cb4e4 100644 --- a/patches/server/Climbing-should-not-bypass-cramming-gamerule.patch +++ b/patches/server/Climbing-should-not-bypass-cramming-gamerule.patch @@ -4,22 +4,6 @@ Date: Sun, 23 Aug 2020 20:59:00 +0200 Subject: [PATCH] Climbing should not bypass cramming gamerule -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - wanderingTraderSpawnChanceMax = getInt("wandering-trader.spawn-chance-max", wanderingTraderSpawnChanceMax); - } - -+ public boolean fixClimbingBypassingCrammingRule = false; -+ private void fixClimbingBypassingCrammingRule() { -+ fixClimbingBypassingCrammingRule = getBoolean("fix-climbing-bypassing-cramming-rule", fixClimbingBypassingCrammingRule); -+ } -+ - public short keepLoadedRange; - private void keepLoadedRange() { - keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java @@ -69,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // Paper end - don't run getEntities if we're not going to use its result - List list = this.level.getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); -+ List list = this.level.getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushable(this, level.paperConfig.fixClimbingBypassingCrammingRule)); // Paper - fix climbing bypassing cramming rule ++ List list = this.level.getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushable(this, level.paperConfig().collisions.fixClimbingBypassingCrammingRule)); // Paper - fix climbing bypassing cramming rule if (!list.isEmpty()) { // Paper - move up @@ -81,7 +65,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public boolean isPushable() { - return this.isAlive() && !this.isSpectator() && !this.onClimbable() && this.collides; // CraftBukkit -+ return this.isCollidable(level.paperConfig.fixClimbingBypassingCrammingRule); ++ return this.isCollidable(level.paperConfig().collisions.fixClimbingBypassingCrammingRule); + } + + @Override diff --git a/patches/server/Collision-option-for-requiring-a-player-participant.patch b/patches/server/Collision-option-for-requiring-a-player-participant.patch index 5e3d203450..5b130b8f6c 100644 --- a/patches/server/Collision-option-for-requiring-a-player-participant.patch +++ b/patches/server/Collision-option-for-requiring-a-player-participant.patch @@ -4,29 +4,6 @@ Date: Sat, 14 Nov 2020 16:48:37 +0100 Subject: [PATCH] Collision option for requiring a player participant -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - } - -+ public boolean onlyPlayersCollide = false; -+ public boolean allowVehicleCollisions = true; -+ private void onlyPlayersCollide() { -+ onlyPlayersCollide = getBoolean("only-players-collide", onlyPlayersCollide); -+ allowVehicleCollisions = getBoolean("allow-vehicle-collisions", allowVehicleCollisions); -+ if (onlyPlayersCollide && !allowVehicleCollisions) { -+ log("Collisions will only work if a player is one of the two entities colliding."); -+ } else if (onlyPlayersCollide) { -+ log("Collisions will only work if a player OR a vehicle is one of the two entities colliding."); -+ } -+ } -+ - public int wanderingTraderSpawnMinuteTicks = 1200; - public int wanderingTraderSpawnDayTicks = 24000; - public int wanderingTraderSpawnChanceFailureIncrement = 25; diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java @@ -35,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void push(Entity entity) { if (!this.isPassengerOfSameVehicle(entity)) { if (!entity.noPhysics && !this.noPhysics) { -+ if (this.level.paperConfig.onlyPlayersCollide && !(entity instanceof ServerPlayer || this instanceof ServerPlayer)) return; // Paper ++ if (this.level.paperConfig().collisions.onlyPlayersCollide && !(entity instanceof ServerPlayer || this instanceof ServerPlayer)) return; // Paper double d0 = entity.getX() - this.getX(); double d1 = entity.getZ() - this.getZ(); double d2 = Mth.absMax(d0, d1); @@ -47,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void push(Entity entity) { if (!this.level.isClientSide) { if (!entity.noPhysics && !this.noPhysics) { -+ if (!this.level.paperConfig.allowVehicleCollisions && this.level.paperConfig.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper ++ if (!this.level.paperConfig().collisions.allowVehicleCollisions && this.level.paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper if (!this.hasPassenger(entity)) { // CraftBukkit start VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), entity.getBukkitEntity()); @@ -59,7 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void push(Entity entity) { -+ if (!this.level.paperConfig.allowVehicleCollisions && this.level.paperConfig.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper ++ if (!this.level.paperConfig().collisions.allowVehicleCollisions && this.level.paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper if (entity instanceof Boat) { if (entity.getBoundingBox().minY < this.getBoundingBox().maxY) { // CraftBukkit start diff --git a/patches/server/Config-option-for-Piglins-guarding-chests.patch b/patches/server/Config-option-for-Piglins-guarding-chests.patch index 4951f9a6f3..a0492bbcc7 100644 --- a/patches/server/Config-option-for-Piglins-guarding-chests.patch +++ b/patches/server/Config-option-for-Piglins-guarding-chests.patch @@ -4,22 +4,6 @@ Date: Wed, 2 Dec 2020 03:07:58 -0800 Subject: [PATCH] Config option for Piglins guarding chests -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - zombiesTargetTurtleEggs = getBoolean("zombies-target-turtle-eggs", zombiesTargetTurtleEggs); - } - -+ public boolean piglinsGuardChests = true; -+ private void piglinsGuardChests() { -+ piglinsGuardChests = getBoolean("piglins-guard-chests", piglinsGuardChests); -+ } -+ - public enum RedstoneImplementation { - VANILLA, EIGENCRAFT - } diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java @@ -28,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public static void angerNearbyPiglins(Player player, boolean blockOpen) { -+ if (!player.level.paperConfig.piglinsGuardChests) return; // Paper ++ if (!player.level.paperConfig().entities.behavior.piglinsGuardChests) return; // Paper List list = player.level.getEntitiesOfClass(Piglin.class, player.getBoundingBox().inflate(16.0D)); list.stream().filter(PiglinAi::isIdle).filter((entitypiglin) -> { diff --git a/patches/server/Configurable-Alternative-LootPool-Luck-Formula.patch b/patches/server/Configurable-Alternative-LootPool-Luck-Formula.patch index 3dc4ee6675..2fe24213c5 100644 --- a/patches/server/Configurable-Alternative-LootPool-Luck-Formula.patch +++ b/patches/server/Configurable-Alternative-LootPool-Luck-Formula.patch @@ -35,23 +35,6 @@ This change will result in some major changes to fishing formulas. I would love to see this change in Vanilla, so Mojang please pull :) -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - SpigotConfig.save(); - } - } -+ -+ public static boolean useAlternativeLuckFormula = false; -+ private static void useAlternativeLuckFormula() { -+ useAlternativeLuckFormula = getBoolean("settings.use-alternative-luck-formula", false); -+ if (useAlternativeLuckFormula) { -+ Bukkit.getLogger().log(Level.INFO, "Using Aikar's Alternative Luck Formula to apply Luck attribute to all loot pool calculations. See https://luckformula.emc.gs"); -+ } -+ } - } diff --git a/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java b/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java @@ -69,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // This is vanilla + float qualityModifer = (float) LootPoolSingletonContainer.this.quality * luck; + double baseWeight = (LootPoolSingletonContainer.this.weight + qualityModifer); -+ if (com.destroystokyo.paper.PaperConfig.useAlternativeLuckFormula) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.useAlternativeLuckFormula) { + // Random boost to avoid losing precision in the final int cast on return + final int weightBoost = 100; + baseWeight *= weightBoost; diff --git a/patches/server/Configurable-Cartographer-Treasure-Maps.patch b/patches/server/Configurable-Cartographer-Treasure-Maps.patch index 91557b3cb8..8773107bcc 100644 --- a/patches/server/Configurable-Cartographer-Treasure-Maps.patch +++ b/patches/server/Configurable-Cartographer-Treasure-Maps.patch @@ -8,48 +8,6 @@ Allow configuring for cartographers to return the same map location Also allow turning off treasure maps all together as they can eat up Map ID's which are limited in quantity. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - set("despawn-ranges.hard", null); - } - -+ if (this.config.isSet("world-settings.default.treasure-maps-return-already-discovered") || this.config.isSet("world-settings." + worldName + ".treasure-maps-return-already-discovered")) { -+ set("treasure-maps-return-already-discovered", null); -+ needsSave = true; -+ } -+ - if (needsSave) { - saveConfig(); - } -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - Bukkit.getLogger().warning("Spawn Egg and Armor Stand NBT filtering disabled, this is a potential security risk"); - } - } -+ -+ public boolean enableTreasureMaps = true; -+ public boolean treasureMapsAlreadyDiscoveredVillager = false; -+ public Boolean treasureMapsAlreadyDiscoveredLootTable = null; -+ private Boolean getBooleanOrNull(String path, Boolean defaultValue) { -+ this.config.addDefault("world-settings.default." + path, defaultValue == null ? "default" : defaultValue); -+ final Object value = this.config.get("world-settings." + worldName + "." + path, this.config.get("world-settings.default." + path)); -+ if (value instanceof Boolean bool) { -+ return bool; -+ } -+ return null; -+ } -+ private void treasureMapsAlreadyDiscovered() { -+ enableTreasureMaps = getBoolean("enable-treasure-maps", true); -+ if (getBoolean("treasure-maps-return-already-discovered", false, false)) { -+ treasureMapsAlreadyDiscoveredLootTable = true; -+ treasureMapsAlreadyDiscoveredVillager = true; -+ } -+ treasureMapsAlreadyDiscoveredVillager = getBoolean("treasure-maps-find-already-discovered.villager-trade", treasureMapsAlreadyDiscoveredVillager); -+ treasureMapsAlreadyDiscoveredLootTable = getBooleanOrNull("treasure-maps-find-already-discovered.loot-tables", treasureMapsAlreadyDiscoveredLootTable); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/npc/VillagerTrades.java b/src/main/java/net/minecraft/world/entity/npc/VillagerTrades.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/npc/VillagerTrades.java @@ -59,8 +17,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else { ServerLevel serverLevel = (ServerLevel)entity.level; - BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, entity.blockPosition(), 100, true); -+ if (!serverLevel.paperConfig.enableTreasureMaps) return null; // Paper -+ BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, entity.blockPosition(), 100, !serverLevel.paperConfig.treasureMapsAlreadyDiscoveredVillager); // Paper ++ if (!serverLevel.paperConfig().environment.treasureMaps.enabled) return null; // Paper ++ BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, entity.blockPosition(), 100, !serverLevel.paperConfig().environment.treasureMaps.findAlreadyDiscoveredVillager); // Paper if (blockPos != null) { ItemStack itemStack = MapItem.create(serverLevel, blockPos.getX(), blockPos.getZ(), (byte)2, true, true); MapItem.renderBiomePreviewMap(serverLevel, itemStack); @@ -74,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ServerLevel serverLevel = context.getLevel(); - BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, new BlockPos(vec3), this.searchRadius, this.skipKnownStructures); + // Paper start -+ if (!serverLevel.paperConfig.enableTreasureMaps) { ++ if (!serverLevel.paperConfig().environment.treasureMaps.enabled) { + /* + * NOTE: I fear users will just get a plain map as their "treasure" + * This is preferable to disrespecting the config. @@ -82,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return stack; + } + // Paper end -+ BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, new BlockPos(vec3), this.searchRadius, serverLevel.paperConfig.treasureMapsAlreadyDiscoveredLootTable == null ? this.skipKnownStructures : serverLevel.paperConfig.treasureMapsAlreadyDiscoveredLootTable); // Paper ++ BlockPos blockPos = serverLevel.findNearestMapStructure(this.destination, new BlockPos(vec3), this.searchRadius, serverLevel.paperConfig().environment.treasureMaps.findAlreadyDiscoveredLootTable.or(this.skipKnownStructures)); // Paper if (blockPos != null) { ItemStack itemStack = MapItem.create(serverLevel, blockPos.getX(), blockPos.getZ(), this.zoom, true, true); MapItem.renderBiomePreviewMap(serverLevel, itemStack); diff --git a/patches/server/Configurable-Chunk-Inhabited-Time.patch b/patches/server/Configurable-Chunk-Inhabited-Time.patch index ec5be6804e..f4117b3456 100644 --- a/patches/server/Configurable-Chunk-Inhabited-Time.patch +++ b/patches/server/Configurable-Chunk-Inhabited-Time.patch @@ -10,25 +10,6 @@ For people who want all chunks to be treated equally, you can chose a fixed valu This allows to fine-tune vanilla gameplay. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - skeleHorseSpawnChance = 0.01D; // Vanilla value - } - } -+ -+ public int fixedInhabitedTime; -+ private void fixedInhabitedTime() { -+ if (PaperConfig.version < 16) { -+ if (!config.getBoolean("world-settings.default.use-chunk-inhabited-timer", true)) config.set("world-settings.default.fixed-chunk-inhabited-time", 0); -+ if (!config.getBoolean("world-settings." + worldName + ".use-chunk-inhabited-timer", true)) config.set("world-settings." + worldName + ".fixed-chunk-inhabited-time", 0); -+ set("use-chunk-inhabited-timer", null); -+ } -+ fixedInhabitedTime = getInt("fixed-chunk-inhabited-time", -1); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -40,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + @Override + public long getInhabitedTime() { -+ return this.level.paperConfig.fixedInhabitedTime < 0 ? super.getInhabitedTime() : this.level.paperConfig.fixedInhabitedTime; ++ return this.level.paperConfig().chunks.fixedChunkInhabitedTime < 0 ? super.getInhabitedTime() : this.level.paperConfig().chunks.fixedChunkInhabitedTime; + } + // Paper end + diff --git a/patches/server/Configurable-Disabling-Cat-Chest-Detection.patch b/patches/server/Configurable-Disabling-Cat-Chest-Detection.patch index 08ba68be30..3f6d94cc1d 100644 --- a/patches/server/Configurable-Disabling-Cat-Chest-Detection.patch +++ b/patches/server/Configurable-Disabling-Cat-Chest-Detection.patch @@ -5,20 +5,6 @@ Subject: [PATCH] Configurable Disabling Cat Chest Detection Offers a gameplay feature to stop cats from blocking chests -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void containerUpdateTickRate() { - containerUpdateTickRate = getInt("container-update-tick-rate", 1); - } -+ -+ public boolean disableChestCatDetection; -+ private void disableChestCatDetection() { -+ disableChestCatDetection = getBoolean("game-mechanics.disable-chest-cat-detection", false); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/block/ChestBlock.java b/src/main/java/net/minecraft/world/level/block/ChestBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/ChestBlock.java @@ -28,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static boolean isCatSittingOnChest(LevelAccessor world, BlockPos pos) { + // Paper start - Option to disable chest cat detection -+ if (((Level) world).paperConfig.disableChestCatDetection) { ++ if (world.getMinecraftWorld().paperConfig().entities.behavior.disableChestCatDetection) { + return false; + } + // Paper end diff --git a/patches/server/Configurable-Grass-Spread-Tick-Rate.patch b/patches/server/Configurable-Grass-Spread-Tick-Rate.patch index 74d966e439..c98654ab27 100644 --- a/patches/server/Configurable-Grass-Spread-Tick-Rate.patch +++ b/patches/server/Configurable-Grass-Spread-Tick-Rate.patch @@ -4,21 +4,6 @@ Date: Sun, 3 Apr 2016 16:28:17 -0400 Subject: [PATCH] Configurable Grass Spread Tick Rate -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - fixedInhabitedTime = getInt("fixed-chunk-inhabited-time", -1); - } -+ -+ public int grassUpdateRate = 1; -+ private void grassUpdateRate() { -+ grassUpdateRate = Math.max(0, getInt("grass-spread-tick-rate", grassUpdateRate)); -+ log("Grass Spread Tick Rate: " + grassUpdateRate); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java @@ -35,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { -+ if (this instanceof GrassBlock && world.paperConfig.grassUpdateRate != 1 && (world.paperConfig.grassUpdateRate < 1 || (MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig.grassUpdateRate != 0)) { return; } // Paper ++ if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper if (!SpreadingSnowyDirtBlock.canBeGrass(state, world, pos)) { // CraftBukkit start if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) { diff --git a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch index 6a68c250ce..8922420e54 100644 --- a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch +++ b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch @@ -5,23 +5,6 @@ Subject: [PATCH] Configurable Keep Spawn Loaded range per world This lets you disable it for some worlds and lower it for others. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - } - -+ public short keepLoadedRange; -+ private void keepLoadedRange() { -+ keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); -+ log( "Keep Spawn Loaded Range: " + (keepLoadedRange/16)); -+ } -+ - private boolean getBoolean(String path, boolean def) { - return this.getBoolean(path, def, true); - } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java @@ -55,7 +38,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - } + // Paper start - configurable spawn reason -+ int radiusBlocks = worldserver.paperConfig.keepLoadedRange; ++ int radiusBlocks = worldserver.paperConfig().spawn.keepSpawnLoadedRange; + int radiusChunks = radiusBlocks / 16 + ((radiusBlocks & 15) != 0 ? 1 : 0); + int totalChunks = ((radiusChunks) * 2 + 1); + totalChunks *= totalChunks; @@ -174,8 +157,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.getChunkSource().addRegionTicket(TicketType.START, new ChunkPos(pos), 11, Unit.INSTANCE); + if (this.keepSpawnInMemory) { + // if this keepSpawnInMemory is false a plugin has already removed our tickets, do not re-add -+ this.removeTicketsForSpawn(this.paperConfig.keepLoadedRange, prevSpawn); -+ this.addTicketsForSpawn(this.paperConfig.keepLoadedRange, pos); ++ this.removeTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange, prevSpawn); ++ this.addTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange, pos); + } this.getServer().getPlayerList().broadcastAll(new ClientboundSetDefaultSpawnPositionPacket(pos, angle)); } @@ -235,12 +218,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockPos chunkcoordinates = this.world.getSharedSpawnPos(); if (keepLoaded) { - this.world.getChunkSource().addRegionTicket(TicketType.START, new ChunkPos(chunkcoordinates), 11, Unit.INSTANCE); -+ this.world.addTicketsForSpawn(this.world.paperConfig.keepLoadedRange, chunkcoordinates); ++ this.world.addTicketsForSpawn(this.world.paperConfig().spawn.keepSpawnLoadedRange, chunkcoordinates); } else { - // TODO: doesn't work well if spawn changed.... - this.world.getChunkSource().removeRegionTicket(TicketType.START, new ChunkPos(chunkcoordinates), 11, Unit.INSTANCE); + // TODO: doesn't work well if spawn changed.... // Paper - resolved -+ this.world.removeTicketsForSpawn(this.world.paperConfig.keepLoadedRange, chunkcoordinates); ++ this.world.removeTicketsForSpawn(this.world.paperConfig().spawn.keepSpawnLoadedRange, chunkcoordinates); } + // Paper end } diff --git a/patches/server/Configurable-Non-Player-Arrow-Despawn-Rate.patch b/patches/server/Configurable-Non-Player-Arrow-Despawn-Rate.patch index fe145bb911..c559618d52 100644 --- a/patches/server/Configurable-Non-Player-Arrow-Despawn-Rate.patch +++ b/patches/server/Configurable-Non-Player-Arrow-Despawn-Rate.patch @@ -5,30 +5,6 @@ Subject: [PATCH] Configurable Non Player Arrow Despawn Rate Can set a much shorter despawn rate for arrows that players can not pick up. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void nonPlayerEntitiesOnScoreboards() { - nonPlayerEntitiesOnScoreboards = getBoolean("allow-non-player-entities-on-scoreboards", false); - } -+ -+ public int nonPlayerArrowDespawnRate = -1; -+ public int creativeArrowDespawnRate = -1; -+ private void nonPlayerArrowDespawnRate() { -+ nonPlayerArrowDespawnRate = getInt("non-player-arrow-despawn-rate", -1); -+ if (nonPlayerArrowDespawnRate == -1) { -+ nonPlayerArrowDespawnRate = spigotConfig.arrowDespawnRate; -+ } -+ creativeArrowDespawnRate = getInt("creative-arrow-despawn-rate", -1); -+ if (creativeArrowDespawnRate == -1) { -+ creativeArrowDespawnRate = spigotConfig.arrowDespawnRate; -+ } -+ log("Non Player Arrow Despawn Rate: " + nonPlayerArrowDespawnRate); -+ log("Creative Arrow Despawn Rate: " + creativeArrowDespawnRate); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java @@ -38,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void tickDespawn() { ++this.life; - if (this.life >= ((this instanceof ThrownTrident) ? level.spigotConfig.tridentDespawnRate : level.spigotConfig.arrowDespawnRate)) { // Spigot -+ if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? level.paperConfig.creativeArrowDespawnRate : (pickup == Pickup.DISALLOWED ? level.paperConfig.nonPlayerArrowDespawnRate : ((this instanceof ThrownTrident) ? level.spigotConfig.tridentDespawnRate : level.spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - TODO: Extract this to init? ++ if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? level.paperConfig().entities.spawning.creativeArrowDespawnRate.value() : (pickup == Pickup.DISALLOWED ? level.paperConfig().entities.spawning.nonPlayerArrowDespawnRate.value() : ((this instanceof ThrownTrident) ? level.spigotConfig.tridentDespawnRate : level.spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - TODO: Extract this to init? this.discard(); } diff --git a/patches/server/Configurable-Player-Collision.patch b/patches/server/Configurable-Player-Collision.patch index 589c003ad8..805a20fb18 100644 --- a/patches/server/Configurable-Player-Collision.patch +++ b/patches/server/Configurable-Player-Collision.patch @@ -4,20 +4,6 @@ Date: Wed, 13 Apr 2016 02:10:49 -0400 Subject: [PATCH] Configurable Player Collision -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void regionFileCacheSize() { - regionFileCacheSize = Math.max(getInt("settings.region-file-cache-size", 256), 4); - } -+ -+ public static boolean enablePlayerCollisions = true; -+ private static void enablePlayerCollisions() { -+ enablePlayerCollisions = getBoolean("settings.enable-player-collisions", true); -+ } - } diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 buf.writeByte(this.options); buf.writeUtf(this.nametagVisibility); - buf.writeUtf(this.collisionRule); -+ buf.writeUtf(!com.destroystokyo.paper.PaperConfig.enablePlayerCollisions ? "never" : this.collisionRule); // Paper ++ buf.writeUtf(!io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions ? "never" : this.collisionRule); // Paper buf.writeEnum(this.color); buf.writeComponent(this.playerPrefix); buf.writeComponent(this.playerSuffix); @@ -35,28 +21,20 @@ diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -0,0 +0,0 @@ import net.minecraft.world.level.storage.loot.LootTables; - import net.minecraft.world.level.storage.loot.PredicateManager; - import net.minecraft.world.phys.Vec2; - import net.minecraft.world.phys.Vec3; -+import net.minecraft.world.scores.PlayerTeam; // Paper - import org.apache.commons.lang3.Validate; - import org.slf4j.Logger; - @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop toRemove = scoreboard.getPlayerTeams().stream().filter(team -> team.getName().startsWith("collideRule_")).map(PlayerTeam::getName).collect(java.util.stream.Collectors.toList()); ++ final java.util.Collection toRemove = scoreboard.getPlayerTeams().stream().filter(team -> team.getName().startsWith("collideRule_")).map(net.minecraft.world.scores.PlayerTeam::getName).collect(java.util.stream.Collectors.toList()); + for (String teamName : toRemove) { + scoreboard.removePlayerTeam(scoreboard.getPlayerTeam(teamName)); // Clean up after ourselves + } + -+ if (!com.destroystokyo.paper.PaperConfig.enablePlayerCollisions) { ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions) { + this.getPlayerList().collideRuleTeamName = org.apache.commons.lang3.StringUtils.left("collideRule_" + java.util.concurrent.ThreadLocalRandom.current().nextInt(), 16); -+ PlayerTeam collideTeam = scoreboard.addPlayerTeam(this.getPlayerList().collideRuleTeamName); ++ net.minecraft.world.scores.PlayerTeam collideTeam = scoreboard.addPlayerTeam(this.getPlayerList().collideRuleTeamName); + collideTeam.setSeeFriendlyInvisibles(false); // Because we want to mimic them not being on a team at all + } + // Paper end diff --git a/patches/server/Configurable-baby-zombie-movement-speed.patch b/patches/server/Configurable-baby-zombie-movement-speed.patch index dbf57d9c10..2af65fafc8 100644 --- a/patches/server/Configurable-baby-zombie-movement-speed.patch +++ b/patches/server/Configurable-baby-zombie-movement-speed.patch @@ -4,36 +4,15 @@ Date: Tue, 1 Mar 2016 13:09:16 -0600 Subject: [PATCH] Configurable baby zombie movement speed -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - bambooMinHeight = getInt("max-growth-height.bamboo.min", 11); - log("Max height for cactus growth " + cactusMaxHeight + ". Max height for reed growth " + reedMaxHeight + ". Max height for bamboo growth " + bambooMaxHeight + ". Min height for fully-grown bamboo " + bambooMinHeight + "."); - } -+ -+ public double babyZombieMovementModifier; -+ private void babyZombieMovementModifier() { -+ babyZombieMovementModifier = getDouble("baby-zombie-movement-modifier", 0.5D); -+ if (PaperConfig.version < 20) { -+ babyZombieMovementModifier = getDouble("baby-zombie-movement-speed", 0.5D); -+ set("baby-zombie-movement-modifier", babyZombieMovementModifier); -+ } -+ -+ log("Baby zombies will move at the speed of " + babyZombieMovementModifier); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java +++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -0,0 +0,0 @@ import org.bukkit.event.entity.EntityTransformEvent; - public class Zombie extends Monster { +@@ -0,0 +0,0 @@ public class Zombie extends Monster { private static final UUID SPEED_MODIFIER_BABY_UUID = UUID.fromString("B9766B59-9566-4402-BC1F-2EE2A276D836"); -- private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5D, AttributeModifier.Operation.MULTIPLY_BASE); -+ private final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5D, AttributeModifier.Operation.MULTIPLY_BASE); private final AttributeModifier babyModifier = this.SPEED_MODIFIER_BABY; // Paper - remove static - Make baby speed configurable + private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5D, AttributeModifier.Operation.MULTIPLY_BASE); ++ private final AttributeModifier babyModifier = new net.minecraft.world.entity.ai.attributes.AttributeModifier(SPEED_MODIFIER_BABY.getId(), SPEED_MODIFIER_BABY.getName(), this.level.paperConfig().entities.behavior.babyZombieMovementModifier, SPEED_MODIFIER_BABY.getOperation()); // Paper - Make baby speed configurable private static final EntityDataAccessor DATA_BABY_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor DATA_SPECIAL_TYPE_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.INT); public static final EntityDataAccessor DATA_DROWNED_CONVERSION_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.BOOLEAN); diff --git a/patches/server/Configurable-cactus-bamboo-and-reed-growth-heights.patch b/patches/server/Configurable-cactus-bamboo-and-reed-growth-heights.patch index 692bc28e37..f224bf8445 100644 --- a/patches/server/Configurable-cactus-bamboo-and-reed-growth-heights.patch +++ b/patches/server/Configurable-cactus-bamboo-and-reed-growth-heights.patch @@ -6,27 +6,6 @@ Subject: [PATCH] Configurable cactus bamboo and reed growth heights Bamboo - Both the minimum fully-grown heights and the maximum are configurable - Machine_Maker -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - config.addDefault("world-settings.default." + path, def.stream().map(Enum::name).collect(Collectors.toList())); - return ((List) (config.getList("world-settings." + worldName + "." + path, config.getList("world-settings.default." + path)))).stream().map(s -> Enum.valueOf(type, s)).collect(Collectors.toList()); - } -+ -+ public int cactusMaxHeight; -+ public int reedMaxHeight; -+ public int bambooMaxHeight; -+ public int bambooMinHeight; -+ private void blockGrowthHeight() { -+ cactusMaxHeight = getInt("max-growth-height.cactus", 3); -+ reedMaxHeight = getInt("max-growth-height.reeds", 3); -+ bambooMaxHeight = getInt("max-growth-height.bamboo.max", 16); -+ bambooMinHeight = getInt("max-growth-height.bamboo.min", 11); -+ log("Max height for cactus growth " + cactusMaxHeight + ". Max height for reed growth " + reedMaxHeight + ". Max height for bamboo growth " + bambooMaxHeight + ". Min height for fully-grown bamboo " + bambooMinHeight + "."); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/block/BambooBlock.java b/src/main/java/net/minecraft/world/level/block/BambooBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/BambooBlock.java @@ -36,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int i = this.getHeightBelowUpToMax(world, pos) + 1; - if (i < 16) { -+ if (i < world.paperConfig.bambooMaxHeight) { // Paper ++ if (i < world.paperConfig().maxGrowthHeight.bamboo.max) { // Paper this.growBamboo(state, world, pos, random, i); } } @@ -45,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int j = this.getHeightBelowUpToMax(world, pos); - return i + j + 1 < 16 && (Integer) world.getBlockState(pos.above(i)).getValue(BambooBlock.STAGE) != 1; -+ return i + j + 1 < ((Level) world).paperConfig.bambooMaxHeight && (Integer) world.getBlockState(pos.above(i)).getValue(BambooBlock.STAGE) != 1; // Paper ++ return i + j + 1 < ((Level) world).paperConfig().maxGrowthHeight.bamboo.max && (Integer) world.getBlockState(pos.above(i)).getValue(BambooBlock.STAGE) != 1; // Paper } @Override @@ -54,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockState iblockdata1 = world.getBlockState(blockposition1); - if (k >= 16 || !iblockdata1.is(Blocks.BAMBOO) || (Integer) iblockdata1.getValue(BambooBlock.STAGE) == 1 || !world.isEmptyBlock(blockposition1.above())) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here -+ if (k >= world.paperConfig.bambooMaxHeight || !iblockdata1.is(Blocks.BAMBOO) || (Integer) iblockdata1.getValue(BambooBlock.STAGE) == 1 || !world.isEmptyBlock(blockposition1.above())) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here // Paper - Configurable cactus bamboo and reed growth heights ++ if (k >= world.paperConfig().maxGrowthHeight.bamboo.max || !iblockdata1.is(Blocks.BAMBOO) || (Integer) iblockdata1.getValue(BambooBlock.STAGE) == 1 || !world.isEmptyBlock(blockposition1.above())) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here // Paper - Configurable cactus bamboo and reed growth heights return; } @@ -63,7 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int j = (Integer) state.getValue(BambooBlock.AGE) != 1 && !iblockdata2.is(Blocks.BAMBOO) ? 0 : 1; - int k = (height < 11 || random.nextFloat() >= 0.25F) && height != 15 ? 0 : 1; -+ int k = (height < world.paperConfig.bambooMinHeight || random.nextFloat() >= 0.25F) && height != (world.paperConfig.bambooMaxHeight - 1) ? 0 : 1; // Paper ++ int k = (height < world.paperConfig().maxGrowthHeight.bamboo.min || random.nextFloat() >= 0.25F) && height != (world.paperConfig().maxGrowthHeight.bamboo.max - 1) ? 0 : 1; // Paper // CraftBukkit start if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, pos.above(), (BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(BambooBlock.AGE, j)).setValue(BambooBlock.LEAVES, blockpropertybamboosize)).setValue(BambooBlock.STAGE, k), 3)) { @@ -72,7 +51,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int i; - for (i = 0; i < 16 && world.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO); ++i) { -+ for (i = 0; i < ((Level) world).paperConfig.bambooMaxHeight && world.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO); ++i) { // Paper ++ for (i = 0; i < ((Level) world).paperConfig().maxGrowthHeight.bamboo.max && world.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO); ++i) { // Paper ; } @@ -81,7 +60,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int i; - for (i = 0; i < 16 && world.getBlockState(pos.below(i + 1)).is(Blocks.BAMBOO); ++i) { -+ for (i = 0; i < ((Level) world).paperConfig.bambooMaxHeight && world.getBlockState(pos.below(i + 1)).is(Blocks.BAMBOO); ++i) { // Paper ++ for (i = 0; i < ((Level) world).paperConfig().maxGrowthHeight.bamboo.max && world.getBlockState(pos.below(i + 1)).is(Blocks.BAMBOO); ++i) { // Paper ; } @@ -94,7 +73,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - if (i < 3) { -+ if (i < world.paperConfig.cactusMaxHeight) { // Paper - Configurable growth height ++ if (i < world.paperConfig().maxGrowthHeight.cactus) { // Paper - Configurable growth height int j = (Integer) state.getValue(CactusBlock.AGE); if (j >= (byte) range(3, ((100.0F / world.spigotConfig.cactusModifier) * 15) + 0.5F, 15)) { // Spigot @@ -107,7 +86,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - if (i < 3) { -+ if (i < world.paperConfig.reedMaxHeight) { // Paper - Configurable growth height ++ if (i < world.paperConfig().maxGrowthHeight.reeds) { // Paper - Configurable growth height int j = (Integer) state.getValue(SugarCaneBlock.AGE); if (j >= (byte) range(3, ((100.0F / world.spigotConfig.caneModifier) * 15) + 0.5F, 15)) { // Spigot diff --git a/patches/server/Configurable-chance-of-villager-zombie-infection.patch b/patches/server/Configurable-chance-of-villager-zombie-infection.patch index 8e7129a002..06b72ca790 100644 --- a/patches/server/Configurable-chance-of-villager-zombie-infection.patch +++ b/patches/server/Configurable-chance-of-villager-zombie-infection.patch @@ -7,22 +7,6 @@ This allows you to solve an issue in vanilla behavior where: * On easy difficulty your villagers will NEVER get infected, meaning they will always die. * On normal difficulty they will have a 50% of getting infected or dying. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - nerfNetherPortalPigmen = getBoolean("game-mechanics.nerf-pigmen-from-nether-portals", nerfNetherPortalPigmen); - } - -+ public double zombieVillagerInfectionChance = -1.0; -+ private void zombieVillagerInfectionChance() { -+ zombieVillagerInfectionChance = getDouble("zombie-villager-infection-chance", zombieVillagerInfectionChance); -+ } -+ - public int lightQueueSize = 20; - private void lightQueueSize() { - lightQueueSize = getInt("light-queue-size", lightQueueSize); diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java @@ -34,11 +18,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if ((world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager) { - if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { + // Paper start -+ if (level.paperConfig.zombieVillagerInfectionChance != 0.0 && (level.paperConfig.zombieVillagerInfectionChance != -1.0 || world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager) { -+ if (level.paperConfig.zombieVillagerInfectionChance == -1.0 && world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { ++ if (level.paperConfig().entities.behavior.zombieVillagerInfectionChance != 0.0 && (level.paperConfig().entities.behavior.zombieVillagerInfectionChance != -1.0 || world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager) { ++ if (level.paperConfig().entities.behavior.zombieVillagerInfectionChance == -1.0 && world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { return flag; } -+ if (level.paperConfig.zombieVillagerInfectionChance != -1.0 && (this.random.nextDouble() * 100.0) > level.paperConfig.zombieVillagerInfectionChance) { ++ if (level.paperConfig().entities.behavior.zombieVillagerInfectionChance != -1.0 && (this.random.nextDouble() * 100.0) > level.paperConfig().entities.behavior.zombieVillagerInfectionChance) { + return flag; + } // Paper end diff --git a/patches/server/Configurable-connection-throttle-kick-message.patch b/patches/server/Configurable-connection-throttle-kick-message.patch index e801c24559..015d3c41f2 100644 --- a/patches/server/Configurable-connection-throttle-kick-message.patch +++ b/patches/server/Configurable-connection-throttle-kick-message.patch @@ -4,22 +4,6 @@ Date: Tue, 2 Oct 2018 09:57:50 +0100 Subject: [PATCH] Configurable connection throttle kick message -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - authenticationServersDownKickMessage = Strings.emptyToNull(getString("messages.kick.authentication-servers-down", authenticationServersDownKickMessage)); - } - -+ public static String connectionThrottleKickMessage = "Connection throttled! Please wait before reconnecting."; -+ private static void connectionThrottleKickMessage() { -+ connectionThrottleKickMessage = getString("messages.kick.connection-throttle", connectionThrottleKickMessage); -+ } -+ - private static void savePlayerData() { - Object val = config.get("settings.save-player-data"); - if (val instanceof Boolean) { diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java @@ -29,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (ServerHandshakePacketListenerImpl.throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - ServerHandshakePacketListenerImpl.throttleTracker.get(address) < connectionThrottle) { ServerHandshakePacketListenerImpl.throttleTracker.put(address, currentTime); - MutableComponent chatmessage = Component.literal("Connection throttled! Please wait before reconnecting."); -+ MutableComponent chatmessage = Component.literal(com.destroystokyo.paper.PaperConfig.connectionThrottleKickMessage); // Paper - Configurable connection throttle kick message ++ MutableComponent chatmessage = Component.literal(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.connectionThrottle); // Paper - Configurable connection throttle kick message this.connection.send(new ClientboundLoginDisconnectPacket(chatmessage)); this.connection.disconnect(chatmessage); return; diff --git a/patches/server/Configurable-container-update-tick-rate.patch b/patches/server/Configurable-container-update-tick-rate.patch index b3303b37db..12f14df49c 100644 --- a/patches/server/Configurable-container-update-tick-rate.patch +++ b/patches/server/Configurable-container-update-tick-rate.patch @@ -4,20 +4,6 @@ Date: Wed, 2 Mar 2016 23:34:44 -0600 Subject: [PATCH] Configurable container update tick rate -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void mobSpawnerTickRate() { - mobSpawnerTickRate = getInt("mob-spawner-tick-rate", 1); - } -+ -+ public int containerUpdateTickRate; -+ private void containerUpdateTickRate() { -+ containerUpdateTickRate = getInt("container-update-tick-rate", 1); -+ } - } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -38,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - Configurable container update tick rate + if (--containerUpdateDelay <= 0) { + this.containerMenu.broadcastChanges(); -+ containerUpdateDelay = level.paperConfig.containerUpdateTickRate; ++ containerUpdateDelay = level.paperConfig().tickRates.containerUpdate; + } + // Paper end if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) { diff --git a/patches/server/Configurable-door-breaking-difficulty.patch b/patches/server/Configurable-door-breaking-difficulty.patch index f89bf53629..f421b0bac5 100644 --- a/patches/server/Configurable-door-breaking-difficulty.patch +++ b/patches/server/Configurable-door-breaking-difficulty.patch @@ -5,38 +5,6 @@ Subject: [PATCH] Configurable door breaking difficulty Co-authored-by: Doc -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void disableMobSpawnerSpawnEggTransformation() { - disableMobSpawnerSpawnEggTransformation = getBoolean("game-mechanics.disable-mob-spawner-spawn-egg-transformation", disableMobSpawnerSpawnEggTransformation); - } -+ -+ private final List> entitiesValidForBreakDoors = Arrays.asList(net.minecraft.world.entity.EntityType.ZOMBIE, net.minecraft.world.entity.EntityType.ZOMBIE_VILLAGER, net.minecraft.world.entity.EntityType.HUSK, net.minecraft.world.entity.EntityType.ZOMBIFIED_PIGLIN, net.minecraft.world.entity.EntityType.VINDICATOR); -+ public java.util.Map, java.util.List> entitiesDifficultyBreakDoors = new it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap<>(); -+ private void setupEntityBreakingDoors() { -+ for (net.minecraft.world.entity.EntityType entityType : entitiesValidForBreakDoors) { -+ java.util.function.Predicate difficultyPredicate = net.minecraft.world.entity.monster.Zombie.DOOR_BREAKING_PREDICATE; -+ if (entityType == net.minecraft.world.entity.EntityType.VINDICATOR) { -+ difficultyPredicate = net.minecraft.world.entity.monster.Vindicator.DOOR_BREAKING_PREDICATE; -+ } -+ entitiesDifficultyBreakDoors.put( -+ entityType, -+ getEnumList( -+ "door-breaking-difficulty." + entityType.id, -+ java.util.Arrays.stream(net.minecraft.world.Difficulty.values()) -+ .filter(difficultyPredicate) -+ .collect(Collectors.toList()), -+ net.minecraft.world.Difficulty.class -+ ) -+ ); -+ } -+ } - - public short keepLoadedRange; - private void keepLoadedRange() { diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java @@ -46,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 static class VindicatorBreakDoorGoal extends BreakDoorGoal { public VindicatorBreakDoorGoal(Mob mob) { - super(mob, 6, Vindicator.DOOR_BREAKING_PREDICATE); -+ super(mob, 6, com.google.common.base.Predicates.in(mob.level.paperConfig.entitiesDifficultyBreakDoors.getOrDefault(mob.getType(), mob.level.paperConfig.entitiesDifficultyBreakDoors.get(EntityType.VINDICATOR)))); // Paper ++ super(mob, 6, com.google.common.base.Predicates.in(mob.level.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(mob.getType(), mob.level.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.VINDICATOR)))); // Paper this.setFlags(EnumSet.of(Goal.Flag.MOVE)); } @@ -59,7 +27,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public Zombie(EntityType type, Level world) { super(type, world); - this.breakDoorGoal = new BreakDoorGoal(this, Zombie.DOOR_BREAKING_PREDICATE); -+ this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(world.paperConfig.entitiesDifficultyBreakDoors.getOrDefault(type, world.paperConfig.entitiesDifficultyBreakDoors.get(EntityType.ZOMBIE)))); // Paper ++ this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(world.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(type, world.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper } public Zombie(Level world) { diff --git a/patches/server/Configurable-end-credits.patch b/patches/server/Configurable-end-credits.patch index 5e1a6bda53..91ce344eed 100644 --- a/patches/server/Configurable-end-credits.patch +++ b/patches/server/Configurable-end-credits.patch @@ -4,21 +4,6 @@ Date: Wed, 16 Mar 2016 02:21:39 -0500 Subject: [PATCH] Configurable end credits -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - } - } -+ -+ public boolean disableEndCredits; -+ private void disableEndCredits() { -+ disableEndCredits = getBoolean("game-mechanics.disable-end-credits", false); -+ log("End credits disabled: " + disableEndCredits); -+ } - } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -27,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.unRide(); this.getLevel().removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); if (!this.wonGame) { -+ if (level.paperConfig.disableEndCredits) this.seenCredits = true; // Paper - Toggle to always disable end credits ++ if (level.paperConfig().misc.disableEndCredits) this.seenCredits = true; // Paper - Toggle to always disable end credits this.wonGame = true; this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, this.seenCredits ? 0.0F : 1.0F)); this.seenCredits = true; diff --git a/patches/server/Configurable-feature-seeds.patch b/patches/server/Configurable-feature-seeds.patch index f08b07d5cc..d66e4e488a 100644 --- a/patches/server/Configurable-feature-seeds.patch +++ b/patches/server/Configurable-feature-seeds.patch @@ -18,66 +18,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 continue; } final Object val = config.get(key); -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - return table; - } - -+ public it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap featureSeeds = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); -+ private void featureSeeds() { -+ featureSeeds.defaultReturnValue(-1); -+ final boolean randomise = getBoolean("feature-seeds.generate-random-seeds-for-all", false); -+ final ConfigurationSection defaultSection = config.getConfigurationSection("world-settings.default.feature-seeds"); -+ final ConfigurationSection section = config.getConfigurationSection("world-settings." + worldName + ".feature-seeds"); -+ final net.minecraft.core.Registry> registry -+ = net.minecraft.server.MinecraftServer.getServer().registryAccess().registryOrThrow(net.minecraft.core.Registry.CONFIGURED_FEATURE_REGISTRY); -+ if (section != null) { -+ loadFeatureSeeds(section, registry); -+ } -+ -+ // Also use default set seeds if not already set per world -+ loadFeatureSeeds(defaultSection, registry); -+ -+ if (randomise) { -+ final Map randomisedSeeds = new HashMap<>(); -+ final java.util.Random random = new java.security.SecureRandom(); -+ for (final net.minecraft.resources.ResourceLocation resourceLocation : registry.keySet()) { -+ if (featureSeeds.containsKey(resourceLocation)) { -+ continue; -+ } -+ -+ final long seed = random.nextLong(); -+ randomisedSeeds.put("world-settings." + worldName + ".feature-seeds." + resourceLocation.getPath(), seed); -+ featureSeeds.put(resourceLocation, seed); -+ } -+ if (!randomisedSeeds.isEmpty()) { -+ config.addDefaults(randomisedSeeds); -+ } -+ } -+ } -+ -+ private void loadFeatureSeeds(final ConfigurationSection section, final net.minecraft.core.Registry> registry) { -+ for (final String key : section.getKeys(false)) { -+ if (!(section.get(key) instanceof Number)) { -+ continue; -+ } -+ -+ final net.minecraft.resources.ResourceLocation location = new net.minecraft.resources.ResourceLocation(key); -+ if (!registry.containsKey(location)) { -+ logError("Invalid feature resource location: " + location); -+ continue; -+ } -+ -+ featureSeeds.putIfAbsent(location, section.getLong(key)); -+ } -+ } -+ - public int getBehaviorTickRate(String typeName, String entityType, int def) { - return getIntOrDefault(behaviorTickRates, typeName, entityType, def); - } diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java @@ -99,7 +39,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - change populationSeed used in random + long featurePopulationSeed = i; + final net.minecraft.resources.ResourceLocation location = iregistry1.getKey(placedfeature); -+ final long configFeatureSeed = generatoraccessseed.getMinecraftWorld().paperConfig.featureSeeds.getLong(location); ++ final long configFeatureSeed = generatoraccessseed.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(location); // TODO this wont work + if (configFeatureSeed != -1) { + featurePopulationSeed = seededrandom.setDecorationSeed(configFeatureSeed, blockposition.getX(), blockposition.getZ()); // See seededrandom.setDecorationSeed from above + } diff --git a/patches/server/Configurable-fishing-time-ranges.patch b/patches/server/Configurable-fishing-time-ranges.patch index 8c2eda9f4e..6dfff4a857 100644 --- a/patches/server/Configurable-fishing-time-ranges.patch +++ b/patches/server/Configurable-fishing-time-ranges.patch @@ -4,23 +4,6 @@ Date: Tue, 1 Mar 2016 13:14:11 -0600 Subject: [PATCH] Configurable fishing time ranges -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - - log("Baby zombies will move at the speed of " + babyZombieMovementModifier); - } -+ -+ public int fishingMinTicks; -+ public int fishingMaxTicks; -+ private void fishingTickRange() { -+ fishingMinTicks = getInt("fishing-time-range.MinimumTicks", 100); -+ fishingMaxTicks = getInt("fishing-time-range.MaximumTicks", 600); -+ log("Fishing time ranges are between " + fishingMinTicks +" and " + fishingMaxTicks + " ticks"); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java @@ -30,8 +13,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.luck = Math.max(0, luckOfTheSeaLevel); this.lureSpeed = Math.max(0, lureLevel); + // Paper start -+ minWaitTime = world.paperConfig.fishingMinTicks; -+ maxWaitTime = world.paperConfig.fishingMaxTicks; ++ minWaitTime = world.paperConfig().fishingTimeRange.minimum; ++ maxWaitTime = world.paperConfig().fishingTimeRange.maximum; + // Paper end } diff --git a/patches/server/Configurable-flying-kick-messages.patch b/patches/server/Configurable-flying-kick-messages.patch index 840788ede9..c931058620 100644 --- a/patches/server/Configurable-flying-kick-messages.patch +++ b/patches/server/Configurable-flying-kick-messages.patch @@ -4,22 +4,6 @@ Date: Tue, 20 Sep 2016 00:58:01 +0000 Subject: [PATCH] Configurable flying kick messages -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - } - packetInSpamThreshold = getInt("settings.incoming-packet-spam-threshold", 300); - } -+ -+ public static String flyingKickPlayerMessage = "Flying is not enabled on this server"; -+ public static String flyingKickVehicleMessage = "Flying is not enabled on this server"; -+ private static void flyingKickMessages() { -+ flyingKickPlayerMessage = getString("messages.kick.flying-player", flyingKickPlayerMessage); -+ flyingKickVehicleMessage = getString("messages.kick.flying-vehicle", flyingKickVehicleMessage); -+ } - } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -29,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (++this.aboveGroundTickCount > 80) { ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating too long!", this.player.getName().getString()); - this.disconnect(Component.translatable("multiplayer.disconnect.flying")); -+ this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickPlayerMessage); // Paper - use configurable kick message ++ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer); // Paper - use configurable kick message return; } } else { @@ -38,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (++this.aboveGroundVehicleTickCount > 80) { ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating a vehicle too long!", this.player.getName().getString()); - this.disconnect(Component.translatable("multiplayer.disconnect.flying")); -+ this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickVehicleMessage); // Paper - use configurable kick message ++ this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle); // Paper - use configurable kick message return; } } else { diff --git a/patches/server/Configurable-inter-world-teleportation-safety.patch b/patches/server/Configurable-inter-world-teleportation-safety.patch index 0362fa83ab..01dc8fa960 100644 --- a/patches/server/Configurable-inter-world-teleportation-safety.patch +++ b/patches/server/Configurable-inter-world-teleportation-safety.patch @@ -15,20 +15,6 @@ Example setup to perform the glitch: http://puu.sh/ng3PC/cf072dcbdb.png The wanted destination was on top of the emerald block however the player ended on top of the diamond block. This only is the case if the player is teleporting between worlds. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - portalCreateRadius = getInt("portal-create-radius", 16); - portalSearchVanillaDimensionScaling = getBoolean("portal-search-vanilla-dimension-scaling", true); - } -+ -+ public boolean disableTeleportationSuffocationCheck; -+ private void disableTeleportationSuffocationCheck() { -+ disableTeleportationSuffocationCheck = getBoolean("disable-teleportation-suffocation-check", false); -+ } - } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -38,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 entity.connection.teleport(to); } else { - server.getHandle().respawn(entity, toWorld, true, to, true); -+ server.getHandle().respawn(entity, toWorld, true, to, !toWorld.paperConfig.disableTeleportationSuffocationCheck); // Paper ++ server.getHandle().respawn(entity, toWorld, true, to, !toWorld.paperConfig().environment.disableTeleportationSuffocationCheck); // Paper } return true; } diff --git a/patches/server/Configurable-item-frame-map-cursor-update-interval.patch b/patches/server/Configurable-item-frame-map-cursor-update-interval.patch index f8e205780b..cd96229e06 100644 --- a/patches/server/Configurable-item-frame-map-cursor-update-interval.patch +++ b/patches/server/Configurable-item-frame-map-cursor-update-interval.patch @@ -4,22 +4,6 @@ Date: Fri, 13 Aug 2021 01:14:38 +0200 Subject: [PATCH] Configurable item frame map cursor update interval -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - mapItemFrameCursorLimit = getInt("map-item-frame-cursor-limit", mapItemFrameCursorLimit); - } - -+ public int mapItemFrameCursorUpdateInterval = 10; -+ private void itemFrameCursorUpdateInterval() { -+ mapItemFrameCursorUpdateInterval = getInt("map-item-frame-cursor-update-interval", mapItemFrameCursorUpdateInterval); -+ } -+ - public boolean fixItemsMergingThroughWalls; - private void fixItemsMergingThroughWalls() { - fixItemsMergingThroughWalls = getBoolean("fix-items-merging-through-walls", fixItemsMergingThroughWalls); diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java @@ -29,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ItemStack itemstack = entityitemframe.getItem(); - if (this.tickCount % 10 == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks -+ if (this.level.paperConfig.mapItemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig.mapItemFrameCursorUpdateInterval == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable ++ if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable Integer integer = MapItem.getMapId(itemstack); MapItemSavedData worldmap = MapItem.getSavedData(integer, this.level); diff --git a/patches/server/Configurable-max-block-light-for-monster-spawning.patch b/patches/server/Configurable-max-block-light-for-monster-spawning.patch index 14110defeb..a0f666964d 100644 --- a/patches/server/Configurable-max-block-light-for-monster-spawning.patch +++ b/patches/server/Configurable-max-block-light-for-monster-spawning.patch @@ -4,20 +4,6 @@ Date: Thu, 16 Dec 2021 09:40:39 +0100 Subject: [PATCH] Configurable max block light for monster spawning -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - Integer rate = table.get(columnKey, rowKey); - return rate != null && rate > -1 ? rate : def; - } -+ -+ public int maxBlockLightForMonsterSpawning = -1; -+ private void minBlockLightForMobSpawning() { -+ this.maxBlockLightForMonsterSpawning = getInt("monster-spawn-max-light-level", maxBlockLightForMonsterSpawning); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/monster/Monster.java b/src/main/java/net/minecraft/world/entity/monster/Monster.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Monster.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else { DimensionType dimensionType = world.dimensionType(); - int i = dimensionType.monsterSpawnBlockLightLimit(); -+ int i = world.getLevel().paperConfig.maxBlockLightForMonsterSpawning >= 0 ? world.getLevel().paperConfig.maxBlockLightForMonsterSpawning : dimensionType.monsterSpawnBlockLightLimit(); // Paper ++ int i = world.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel >= 0 ? world.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel : dimensionType.monsterSpawnBlockLightLimit(); // Paper if (i < 15 && world.getBrightness(LightLayer.BLOCK, pos) > i) { return false; } else { diff --git a/patches/server/Configurable-max-leash-distance.patch b/patches/server/Configurable-max-leash-distance.patch index 03706c8646..c7f12f5235 100644 --- a/patches/server/Configurable-max-leash-distance.patch +++ b/patches/server/Configurable-max-leash-distance.patch @@ -4,23 +4,6 @@ Date: Sun, 3 Jan 2021 21:04:03 -0800 Subject: [PATCH] Configurable max leash distance -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - } - -+ public float maxLeashDistance = 10f; -+ private void maxLeashDistance() { -+ maxLeashDistance = getFloat("max-leash-distance", maxLeashDistance); -+ log("Max leash distance: " + maxLeashDistance); -+ } -+ - public boolean disableEndCredits; - private void disableEndCredits() { - disableEndCredits = getBoolean("game-mechanics.disable-end-credits", false); diff --git a/src/main/java/net/minecraft/world/entity/PathfinderMob.java b/src/main/java/net/minecraft/world/entity/PathfinderMob.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/PathfinderMob.java @@ -30,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this instanceof TamableAnimal && ((TamableAnimal) this).isInSittingPose()) { - if (f > 10.0F) { -+ if (f > entity.level.paperConfig.maxLeashDistance) { // Paper ++ if (f > entity.level.paperConfig().misc.maxLeashDistance) { // Paper this.level.getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE)); // CraftBukkit this.dropLeash(true, true); } @@ -39,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.onLeashDistance(f); - if (f > 10.0F) { -+ if (f > entity.level.paperConfig.maxLeashDistance) { // Paper ++ if (f > entity.level.paperConfig().misc.maxLeashDistance) { // Paper this.level.getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE)); // CraftBukkit this.dropLeash(true, true); this.goalSelector.disableControlFlag(Goal.Flag.MOVE); diff --git a/patches/server/Configurable-mob-spawner-tick-rate.patch b/patches/server/Configurable-mob-spawner-tick-rate.patch index dac60c27d0..564b6a656e 100644 --- a/patches/server/Configurable-mob-spawner-tick-rate.patch +++ b/patches/server/Configurable-mob-spawner-tick-rate.patch @@ -4,20 +4,6 @@ Date: Wed, 2 Mar 2016 15:03:53 -0600 Subject: [PATCH] Configurable mob spawner tick rate -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void disableIceAndSnow(){ - disableIceAndSnow = getBoolean("disable-ice-and-snow", false); - } -+ -+ public int mobSpawnerTickRate; -+ private void mobSpawnerTickRate() { -+ mobSpawnerTickRate = getInt("mob-spawner-tick-rate", 1); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/BaseSpawner.java @@ -36,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void serverTick(ServerLevel world, BlockPos pos) { + // Paper start - Configurable mob spawner tick rate + if (spawnDelay > 0 && --tickDelay > 0) return; -+ tickDelay = world.paperConfig.mobSpawnerTickRate; ++ tickDelay = world.paperConfig().tickRates.mobSpawner; + if (tickDelay == -1) { return; } // If disabled + // Paper end if (this.isNearPlayer(world, pos)) { diff --git a/patches/server/Configurable-packet-in-spam-threshold.patch b/patches/server/Configurable-packet-in-spam-threshold.patch index e55dec19fd..76245fdd93 100644 --- a/patches/server/Configurable-packet-in-spam-threshold.patch +++ b/patches/server/Configurable-packet-in-spam-threshold.patch @@ -4,24 +4,6 @@ Date: Sun, 11 Sep 2016 14:30:57 -0500 Subject: [PATCH] Configurable packet in spam threshold -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - public static boolean isProxyOnlineMode() { - return Bukkit.getOnlineMode() || (SpigotConfig.bungee && bungeeOnlineMode); - } -+ -+ public static int packetInSpamThreshold = 300; -+ private static void packetInSpamThreshold() { -+ if (version < 11) { -+ int oldValue = getInt("settings.play-in-use-item-spam-threshold", 300); -+ set("settings.incoming-packet-spam-threshold", oldValue); -+ } -+ packetInSpamThreshold = getInt("settings.incoming-packet-spam-threshold", 300); -+ } - } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -30,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Spigot start - limit place/interactions private int limitedPackets; private long lastLimitedPacket = -1; -+ private static final int THRESHOLD = com.destroystokyo.paper.PaperConfig.packetInSpamThreshold; // Paper - Configurable threshold ++ private static final int THRESHOLD = io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.incomingPacketThreshold; // Paper - Configurable threshold private boolean checkLimit(long timestamp) { - if (this.lastLimitedPacket != -1 && timestamp - this.lastLimitedPacket < 30 && this.limitedPackets++ >= 4) { diff --git a/patches/server/Configurable-projectile-relative-velocity.patch b/patches/server/Configurable-projectile-relative-velocity.patch index 2b3d960cdf..9bfd48c059 100644 --- a/patches/server/Configurable-projectile-relative-velocity.patch +++ b/patches/server/Configurable-projectile-relative-velocity.patch @@ -24,21 +24,6 @@ efficient as just not applying the velocity in the first place. P3) Solutions for 1) and especially 2) might not be future-proof, while this server-internal fix makes this change future-proof. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - log("Using improved mob spawn limits (Only Natural Spawns impact spawn limits for more natural spawns)"); - } - } -+ -+ public boolean disableRelativeProjectileVelocity; -+ private void disableRelativeProjectileVelocity() { -+ disableRelativeProjectileVelocity = getBoolean("game-mechanics.disable-relative-projectile-velocity", false); -+ } - } - diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java @@ -48,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Vec3 vec3d = shooter.getDeltaMovement(); - this.setDeltaMovement(this.getDeltaMovement().add(vec3d.x, shooter.isOnGround() ? 0.0D : vec3d.y, vec3d.z)); -+ if (!shooter.level.paperConfig.disableRelativeProjectileVelocity) this.setDeltaMovement(this.getDeltaMovement().add(vec3d.x, shooter.isOnGround() ? 0.0D : vec3d.y, vec3d.z)); // Paper - allow disabling relative velocity ++ if (!shooter.level.paperConfig().misc.disableRelativeProjectileVelocity) this.setDeltaMovement(this.getDeltaMovement().add(vec3d.x, shooter.isOnGround() ? 0.0D : vec3d.y, vec3d.z)); // Paper - allow disabling relative velocity } // CraftBukkit start - call projectile hit event diff --git a/patches/server/Configurable-spawn-chances-for-skeleton-horses.patch b/patches/server/Configurable-spawn-chances-for-skeleton-horses.patch index 4ccb62ea85..1b6ce66f14 100644 --- a/patches/server/Configurable-spawn-chances-for-skeleton-horses.patch +++ b/patches/server/Configurable-spawn-chances-for-skeleton-horses.patch @@ -4,23 +4,6 @@ Date: Tue, 22 Mar 2016 12:04:28 -0500 Subject: [PATCH] Configurable spawn chances for skeleton horses -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - log("Non Player Arrow Despawn Rate: " + nonPlayerArrowDespawnRate); - log("Creative Arrow Despawn Rate: " + creativeArrowDespawnRate); - } -+ -+ public double skeleHorseSpawnChance; -+ private void skeleHorseSpawnChance() { -+ skeleHorseSpawnChance = getDouble("skeleton-horse-thunder-spawn-chance", 0.01D); -+ if (skeleHorseSpawnChance < 0) { -+ skeleHorseSpawnChance = 0.01D; // Vanilla value -+ } -+ } - } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -30,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.isRainingAt(blockposition)) { DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition); - boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * 0.01D && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); -+ boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * paperConfig.skeleHorseSpawnChance && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper ++ boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper if (flag1) { SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this); diff --git a/patches/server/Configurable-speed-for-water-flowing-over-lava.patch b/patches/server/Configurable-speed-for-water-flowing-over-lava.patch index 375572a65c..4e8bd6dc84 100644 --- a/patches/server/Configurable-speed-for-water-flowing-over-lava.patch +++ b/patches/server/Configurable-speed-for-water-flowing-over-lava.patch @@ -4,33 +4,10 @@ Date: Wed, 8 Aug 2018 16:33:21 -0600 Subject: [PATCH] Configurable speed for water flowing over lava -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - this.armorStandTick = this.getBoolean("armor-stands-tick", this.armorStandTick); - log("ArmorStand ticking is " + (this.armorStandTick ? "enabled" : "disabled") + " by default"); - } -+ -+ public int waterOverLavaFlowSpeed; -+ private void waterOverLavaFlowSpeed() { -+ waterOverLavaFlowSpeed = getInt("water-over-lava-flow-speed", 5); -+ log("Water over lava flow speed: " + waterOverLavaFlowSpeed); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java +++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java -@@ -0,0 +0,0 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; - import net.minecraft.world.level.block.state.properties.IntegerProperty; - import net.minecraft.world.level.material.FlowingFluid; - import net.minecraft.world.level.material.FluidState; -+import net.minecraft.world.level.material.Material; - import net.minecraft.world.level.pathfinder.PathComputationType; - import net.minecraft.world.level.storage.loot.LootContext; - import net.minecraft.world.phys.shapes.CollisionContext; @@ -0,0 +0,0 @@ public class LiquidBlock extends Block implements BucketPickup { @Override public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { @@ -43,14 +20,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - Get flow speed. Throttle if its water and flowing adjacent to lava + public int getFlowSpeed(Level world, BlockPos blockposition) { -+ if (this.material == Material.WATER) { ++ if (this.material == net.minecraft.world.level.material.Material.WATER) { + if ( -+ world.getMaterialIfLoaded(blockposition.north(1)) == Material.LAVA || -+ world.getMaterialIfLoaded(blockposition.south(1)) == Material.LAVA || -+ world.getMaterialIfLoaded(blockposition.west(1)) == Material.LAVA || -+ world.getMaterialIfLoaded(blockposition.east(1)) == Material.LAVA ++ world.getMaterialIfLoaded(blockposition.north(1)) == net.minecraft.world.level.material.Material.LAVA || ++ world.getMaterialIfLoaded(blockposition.south(1)) == net.minecraft.world.level.material.Material.LAVA || ++ world.getMaterialIfLoaded(blockposition.west(1)) == net.minecraft.world.level.material.Material.LAVA || ++ world.getMaterialIfLoaded(blockposition.east(1)) == net.minecraft.world.level.material.Material.LAVA + ) { -+ return world.paperConfig.waterOverLavaFlowSpeed; ++ return world.paperConfig().environment.waterOverLavaFlowSpeed; + } + } + return this.fluid.getTickDelay(world); diff --git a/patches/server/Configurable-sprint-interruption-on-attack.patch b/patches/server/Configurable-sprint-interruption-on-attack.patch index a955e2e5f2..267eb8fe0d 100644 --- a/patches/server/Configurable-sprint-interruption-on-attack.patch +++ b/patches/server/Configurable-sprint-interruption-on-attack.patch @@ -5,20 +5,6 @@ Subject: [PATCH] Configurable sprint interruption on attack If the sprint interruption is disabled players continue sprinting when they attack entities. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - disableCreeperLingeringEffect = getBoolean("disable-creeper-lingering-effect", false); - log("Creeper lingering effect: " + disableCreeperLingeringEffect); - } -+ -+ public boolean disableSprintInterruptionOnAttack; -+ private void disableSprintInterruptionOnAttack() { -+ disableSprintInterruptionOnAttack = getBoolean("game-mechanics.disable-sprint-interruption-on-attack", false); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java @@ -29,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D)); - this.setSprinting(false); + // Paper start - Configuration option to disable automatic sprint interruption -+ if (!level.paperConfig.disableSprintInterruptionOnAttack) { ++ if (!level.paperConfig().misc.disableSprintInterruptionOnAttack) { + this.setSprinting(false); + } + // Paper end diff --git a/patches/server/Configurable-top-of-nether-void-damage.patch b/patches/server/Configurable-top-of-nether-void-damage.patch index 72fdc922f1..72028dd1a2 100644 --- a/patches/server/Configurable-top-of-nether-void-damage.patch +++ b/patches/server/Configurable-top-of-nether-void-damage.patch @@ -4,30 +4,6 @@ Date: Tue, 1 Mar 2016 23:58:50 -0600 Subject: [PATCH] Configurable top of nether void damage -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - if (fallingBlockHeightNerf != 0) log("Falling Block Height Limit set to Y: " + fallingBlockHeightNerf); - if (entityTNTHeightNerf != 0) log("TNT Entity Height Limit set to Y: " + entityTNTHeightNerf); - } -+ -+ public int netherVoidTopDamageHeight; -+ public boolean doNetherTopVoidDamage() { return netherVoidTopDamageHeight > 0; } -+ private void netherVoidTopDamageHeight() { -+ netherVoidTopDamageHeight = getInt("nether-ceiling-void-damage-height", 0); -+ log("Top of the nether void damage height: " + netherVoidTopDamageHeight); -+ -+ if (PaperConfig.version < 18) { -+ boolean legacy = getBoolean("nether-ceiling-void-damage", false); -+ if (legacy) { -+ netherVoidTopDamageHeight = 128; -+ set("nether-ceiling-void-damage-height", netherVoidTopDamageHeight); -+ } -+ } -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java @@ -39,8 +15,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (this.getY() < (double) (this.level.getMinBuildHeight() - 64)) { + // Paper start - Configurable nether ceiling damage + if (this.getY() < (double) (this.level.getMinBuildHeight() - 64) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER -+ && level.paperConfig.doNetherTopVoidDamage() -+ && this.getY() >= this.level.paperConfig.netherVoidTopDamageHeight)) { ++ && level.paperConfig().environment.netherCeilingVoidDamageHeight > 0 ++ && this.getY() >= this.level.paperConfig().environment.netherCeilingVoidDamageHeight)) { + // Paper end this.outOfWorld(); } diff --git a/patches/server/Default-loading-permissions.yml-before-plugins.patch b/patches/server/Default-loading-permissions.yml-before-plugins.patch index ea7996f93d..7c04b35a24 100644 --- a/patches/server/Default-loading-permissions.yml-before-plugins.patch +++ b/patches/server/Default-loading-permissions.yml-before-plugins.patch @@ -15,20 +15,6 @@ modify that. Under the previous logic, plugins were unable (cleanly) override pe A config option has been added for those who depend on the previous behavior, but I don't expect that. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - " - Length: " + timeSummary(Timings.getHistoryLength() / 20) + - " - Server Name: " + timingsServerName); - } -+ -+ public static boolean loadPermsBeforePlugins = true; -+ private static void loadPermsBeforePlugins() { -+ loadPermsBeforePlugins = getBoolean("settings.load-permissions-yml-before-plugins", true); -+ } - } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -37,7 +23,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (type == PluginLoadOrder.STARTUP) { this.helpMap.clear(); this.helpMap.initializeGeneralTopics(); -+ if (com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) loadCustomPermissions(); // Paper ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions(); // Paper } Plugin[] plugins = this.pluginManager.getPlugins(); @@ -46,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 DefaultPermissions.registerCorePermissions(); CraftDefaultPermissions.registerCorePermissions(); - this.loadCustomPermissions(); -+ if (!com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) this.loadCustomPermissions(); // Paper ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) this.loadCustomPermissions(); // Paper this.helpMap.initializeCommands(); this.syncCommands(); } diff --git a/patches/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch b/patches/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch index 87212da8a4..3ee047cff4 100644 --- a/patches/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch +++ b/patches/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch @@ -16,24 +16,6 @@ before it actually unloads, which will be handled by the ticket expiry process. This allows servers with smaller worlds who do less long distance exploring to stop wasting cpu cycles on saving/unloading/reloading chunks repeatedly. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - expMergeMaxValue = getInt("experience-merge-max-value", -1); - log("Experience Merge Max Value: " + expMergeMaxValue); - } -+ -+ public long delayChunkUnloadsBy; -+ private void delayChunkUnloadsBy() { -+ delayChunkUnloadsBy = PaperConfig.getSeconds(getString("delay-chunk-unloads-by", "10s")); -+ if (delayChunkUnloadsBy > 0) { -+ log("Delaying chunk unloads by " + delayChunkUnloadsBy + " seconds"); -+ delayChunkUnloadsBy *= 20; -+ } -+ } - } diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -43,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (arraysetsorted.remove(ticket)) { removed = true; // CraftBukkit + // Paper start - delay chunk unloads for player tickets -+ long delayChunkUnloadsBy = chunkMap.level.paperConfig.delayChunkUnloadsBy; ++ long delayChunkUnloadsBy = chunkMap.level.paperConfig().chunks.delayChunkUnloadsBy.ticks(); + if (ticket.getType() == TicketType.PLAYER && delayChunkUnloadsBy > 0) { + boolean hasPlayer = false; + for (Ticket ticket1 : arraysetsorted) { diff --git a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch index 13416c78b9..0ecd25b1d4 100644 --- a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch +++ b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch @@ -24,15 +24,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end implementation("org.apache.logging.log4j:log4j-iostreams:2.17.1") // Paper implementation("org.ow2.asm:asm:9.3") -@@ -0,0 +0,0 @@ dependencies { - runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.3") - runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.3") - + implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation + implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files + implementation("commons-lang:commons-lang:2.6") + implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation -+ - testImplementation("junit:junit:4.13.2") - testImplementation("org.hamcrest:hamcrest-library:1.3") - } + runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3") + runtimeOnly("mysql:mysql-connector-java:8.0.29") + runtimeOnly("com.lmax:disruptor:3.4.4") // Paper @@ -0,0 +0,0 @@ tasks.shadowJar { } } @@ -79,20 +77,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 tasks.test { exclude("org/bukkit/craftbukkit/inventory/ItemStack*Test.class") } -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - log("Async Chunks: Enabled - Chunks will be loaded much faster, without lag."); - } - } -+ -+ public static boolean deobfuscateStacktraces = true; -+ private static void loggerSettings() { -+ deobfuscateStacktraces = getBoolean("settings.loggers.deobfuscate-stacktraces", deobfuscateStacktraces); -+ } - } diff --git a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java @@ -310,7 +294,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package io.papermc.paper.util; + -+import com.destroystokyo.paper.PaperConfig; ++import io.papermc.paper.configuration.GlobalConfiguration; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import java.io.IOException; @@ -340,7 +324,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + }); + + public void deobfuscateThrowable(final Throwable throwable) { -+ if (!PaperConfig.deobfuscateStacktraces) { ++ if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true + return; + } + @@ -355,7 +339,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public StackTraceElement[] deobfuscateStacktrace(final StackTraceElement[] traceElements) { -+ if (!PaperConfig.deobfuscateStacktraces) { ++ if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true + return traceElements; + } + @@ -556,13 +540,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - } - com.destroystokyo.paper.PaperConfig.registerCommands(); - com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now -+ io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // load mappings for stacktrace deobf and etc. - // Paper end - - this.setPvpAllowed(dedicatedserverproperties.pvp); + org.spigotmc.SpigotConfig.registerCommands(); + // Spigot end + // Paper start ++ io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc. + paperConfigurations.initializeGlobalConfiguration(); + paperConfigurations.initializeWorldDefaultsConfiguration(); + org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java diff --git a/patches/server/Disable-Scoreboards-for-non-players-by-default.patch b/patches/server/Disable-Scoreboards-for-non-players-by-default.patch index 2f905c8165..bd03fe4cb6 100644 --- a/patches/server/Disable-Scoreboards-for-non-players-by-default.patch +++ b/patches/server/Disable-Scoreboards-for-non-players-by-default.patch @@ -10,20 +10,6 @@ this setting. So avoid looking up scoreboards and short circuit to the "not on a team" logic which is most likely to be true. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void disableTeleportationSuffocationCheck() { - disableTeleportationSuffocationCheck = getBoolean("disable-teleportation-suffocation-check", false); - } -+ -+ public boolean nonPlayerEntitiesOnScoreboards = false; -+ private void nonPlayerEntitiesOnScoreboards() { -+ nonPlayerEntitiesOnScoreboards = getBoolean("allow-non-player-entities-on-scoreboards", false); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java @@ -32,7 +18,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable public Team getTeam() { -+ if (!this.level.paperConfig.nonPlayerEntitiesOnScoreboards && !(this instanceof Player)) { return null; } // Paper ++ if (!this.level.paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof Player)) { return null; } // Paper return this.level.getScoreboard().getPlayersTeam(this.getScoreboardName()); } @@ -44,7 +30,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (nbt.contains("Team", 8)) { String s = nbt.getString("Team"); PlayerTeam scoreboardteam = this.level.getScoreboard().getPlayerTeam(s); -+ if (!level.paperConfig.nonPlayerEntitiesOnScoreboards && !(this instanceof net.minecraft.world.entity.player.Player)) { scoreboardteam = null; } // Paper ++ if (!level.paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof net.minecraft.world.entity.player.Player)) { scoreboardteam = null; } // Paper boolean flag = scoreboardteam != null && this.level.getScoreboard().addPlayerToTeam(this.getStringUUID(), scoreboardteam); if (!flag) { diff --git a/patches/server/Disable-component-selector-resolving-in-books-by-def.patch b/patches/server/Disable-component-selector-resolving-in-books-by-def.patch index e32f322fb9..8beea2111a 100644 --- a/patches/server/Disable-component-selector-resolving-in-books-by-def.patch +++ b/patches/server/Disable-component-selector-resolving-in-books-by-def.patch @@ -4,20 +4,6 @@ Date: Thu, 2 Jun 2022 20:35:58 +0200 Subject: [PATCH] Disable component selector resolving in books by default -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void useProxyProtocol() { - useProxyProtocol = getBoolean("settings.proxy-protocol", false); - } -+ -+ public static boolean resolveSelectorsInBooks; -+ private static void resolveSelectorsInBooks() { -+ resolveSelectorsInBooks = getBoolean("settings.resolve-selectors-in-books", false); -+ } - } diff --git a/src/main/java/net/minecraft/world/item/WrittenBookItem.java b/src/main/java/net/minecraft/world/item/WrittenBookItem.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/item/WrittenBookItem.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static boolean resolveBookComponents(ItemStack book, @Nullable CommandSourceStack commandSource, @Nullable Player player) { CompoundTag compoundTag = book.getTag(); - if (compoundTag != null && !compoundTag.getBoolean("resolved")) { -+ if (com.destroystokyo.paper.PaperConfig.resolveSelectorsInBooks && compoundTag != null && !compoundTag.getBoolean("resolved")) { // Paper ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.resolveSelectorsInBooks && compoundTag != null && !compoundTag.getBoolean("resolved")) { // Paper compoundTag.putBoolean("resolved", true); if (!makeSureTagIsValid(compoundTag)) { return false; diff --git a/patches/server/Disable-explosion-knockback.patch b/patches/server/Disable-explosion-knockback.patch index e75dd9d174..cf89f9eeba 100644 --- a/patches/server/Disable-explosion-knockback.patch +++ b/patches/server/Disable-explosion-knockback.patch @@ -4,20 +4,6 @@ Date: Wed, 2 Mar 2016 14:48:03 -0600 Subject: [PATCH] Disable explosion knockback -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - optimizeExplosions = getBoolean("optimize-explosions", false); - log("Optimize explosions: " + optimizeExplosions); - } -+ -+ public boolean disableExplosionKnockback; -+ private void disableExplosionKnockback(){ -+ disableExplosionKnockback = getBoolean("disable-explosion-knockback", false); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -26,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -+ boolean knockbackCancelled = level.paperConfig.disableExplosionKnockback && source.isExplosion() && this instanceof net.minecraft.world.entity.player.Player; // Paper - Disable explosion knockback ++ boolean knockbackCancelled = level.paperConfig().environment.disableExplosionKnockback && source.isExplosion() && this instanceof net.minecraft.world.entity.player.Player; // Paper - Disable explosion knockback if (flag1) { if (flag) { this.level.broadcastEntityEvent(this, (byte) 29); @@ -55,7 +41,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (entity instanceof LivingEntity) { - d14 = ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity) entity, d13); -+ d14 = entity instanceof Player && level.paperConfig.disableExplosionKnockback ? 0 : ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity) entity, d13); // Paper - Disable explosion knockback ++ d14 = entity instanceof Player && level.paperConfig().environment.disableExplosionKnockback ? 0 : ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity) entity, d13); // Paper - Disable explosion knockback } entity.setDeltaMovement(entity.getDeltaMovement().add(d8 * d14, d9 * d14, d10 * d14)); @@ -63,7 +49,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Player entityhuman = (Player) entity; - if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying)) { -+ if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig.disableExplosionKnockback) { // Paper - Disable explosion knockback ++ if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Disable explosion knockback this.hitPlayers.put(entityhuman, new Vec3(d8 * d13, d9 * d13, d10 * d13)); } } diff --git a/patches/server/Disable-ice-and-snow.patch b/patches/server/Disable-ice-and-snow.patch index 9e4b78ca85..bbf2fff37e 100644 --- a/patches/server/Disable-ice-and-snow.patch +++ b/patches/server/Disable-ice-and-snow.patch @@ -4,20 +4,6 @@ Date: Wed, 2 Mar 2016 14:57:24 -0600 Subject: [PATCH] Disable ice and snow -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void disableThunder() { - disableThunder = getBoolean("disable-thunder", false); - } -+ -+ public boolean disableIceAndSnow; -+ private void disableIceAndSnow(){ -+ disableIceAndSnow = getBoolean("disable-ice-and-snow", false); -+ } - } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 gameprofilerfiller.popPush("iceandsnow"); - if (this.random.nextInt(16) == 0) { -+ if (!this.paperConfig.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow ++ if (!this.paperConfig().environment.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow blockposition = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.getBlockRandomPos(j, 0, k, 15)); BlockPos blockposition1 = blockposition.below(); Biome biomebase = (Biome) this.getBiome(blockposition).value(); diff --git a/patches/server/Disable-thunder.patch b/patches/server/Disable-thunder.patch index cad1755f62..dd963c9aa5 100644 --- a/patches/server/Disable-thunder.patch +++ b/patches/server/Disable-thunder.patch @@ -4,20 +4,6 @@ Date: Wed, 2 Mar 2016 14:52:43 -0600 Subject: [PATCH] Disable thunder -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void disableExplosionKnockback(){ - disableExplosionKnockback = getBoolean("disable-explosion-knockback", false); - } -+ -+ public boolean disableThunder; -+ private void disableThunder() { -+ disableThunder = getBoolean("disable-thunder", false); -+ } - } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockPos blockposition; - if (flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot -+ if (!this.paperConfig.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder ++ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15)); if (this.isRainingAt(blockposition)) { DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition); diff --git a/patches/server/Distance-manager-tick-timings.patch b/patches/server/Distance-manager-tick-timings.patch index 4e553437b9..56f081dabc 100644 --- a/patches/server/Distance-manager-tick-timings.patch +++ b/patches/server/Distance-manager-tick-timings.patch @@ -37,4 +37,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } finally { co.aikar.timings.MinecraftTimings.distanceManagerTick.stopTiming(); } // Paper - add timings for distance manager } - // Paper start - helper + // Paper start diff --git a/patches/server/Don-t-apply-cramming-damage-to-players.patch b/patches/server/Don-t-apply-cramming-damage-to-players.patch index f85eedcc51..7d7cfb0c19 100644 --- a/patches/server/Don-t-apply-cramming-damage-to-players.patch +++ b/patches/server/Don-t-apply-cramming-damage-to-players.patch @@ -10,20 +10,6 @@ It does not make a lot of sense to damage players if they get crammed, For those who really want it a config option is provided. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void showSignClickCommandFailureMessagesToPlayer() { - showSignClickCommandFailureMessagesToPlayer = getBoolean("show-sign-click-command-failure-msgs-to-player", showSignClickCommandFailureMessagesToPlayer); - } -+ -+ public boolean allowPlayerCrammingDamage = false; -+ private void playerCrammingDamage() { -+ allowPlayerCrammingDamage = getBoolean("allow-player-cramming-damage", allowPlayerCrammingDamage); -+ } - } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -33,7 +19,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public boolean isInvulnerableTo(DamageSource damageSource) { - return super.isInvulnerableTo(damageSource) || this.isChangingDimension() || this.getAbilities().invulnerable && damageSource == DamageSource.WITHER; -+ return super.isInvulnerableTo(damageSource) || this.isChangingDimension() || this.getAbilities().invulnerable && damageSource == DamageSource.WITHER || !level.paperConfig.allowPlayerCrammingDamage && damageSource == DamageSource.CRAMMING; // Paper - disable player cramming ++ return super.isInvulnerableTo(damageSource) || this.isChangingDimension() || this.getAbilities().invulnerable && damageSource == DamageSource.WITHER || !level.paperConfig().collisions.allowPlayerCrammingDamage && damageSource == DamageSource.CRAMMING; // Paper - disable player cramming } @Override diff --git a/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch b/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch index a32e441ff2..1dceca7154 100644 --- a/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch +++ b/patches/server/Don-t-run-entity-collision-code-if-not-needed.patch @@ -16,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void pushEntities() { + // Paper start - don't run getEntities if we're not going to use its result + int i = this.level.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING); -+ if (i <= 0 && level.paperConfig.maxCollisionsPerEntity <= 0) { ++ if (i <= 0 && level.paperConfig().collisions.maxEntityCollisions <= 0) { + return; + } + // Paper end - don't run getEntities if we're not going to use its result diff --git a/patches/server/Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch b/patches/server/Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch index 8eec3bcfde..a77a2c98ff 100644 --- a/patches/server/Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch +++ b/patches/server/Don-t-save-empty-scoreboard-teams-to-scoreboard.dat.patch @@ -4,20 +4,6 @@ Date: Sat, 7 May 2016 23:33:08 -0400 Subject: [PATCH] Don't save empty scoreboard teams to scoreboard.dat -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void enablePlayerCollisions() { - enablePlayerCollisions = getBoolean("settings.enable-player-collisions", true); - } -+ -+ public static boolean saveEmptyScoreboardTeams = false; -+ private static void saveEmptyScoreboardTeams() { -+ saveEmptyScoreboardTeams = getBoolean("settings.save-empty-scoreboard-teams", false); -+ } - } diff --git a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java b/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java @@ -26,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ListTag listTag = new ListTag(); for(PlayerTeam playerTeam : this.scoreboard.getPlayerTeams()) { -+ if (!com.destroystokyo.paper.PaperConfig.saveEmptyScoreboardTeams && playerTeam.getPlayers().isEmpty()) continue; // Paper ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().scoreboards.saveEmptyScoreboardTeams && playerTeam.getPlayers().isEmpty()) continue; // Paper CompoundTag compoundTag = new CompoundTag(); compoundTag.putString("Name", playerTeam.getName()); compoundTag.putString("DisplayName", Component.Serializer.toJson(playerTeam.getDisplayName())); diff --git a/patches/server/Drop-falling-block-and-tnt-entities-at-the-specified.patch b/patches/server/Drop-falling-block-and-tnt-entities-at-the-specified.patch index f0126547fb..6043636ba6 100644 --- a/patches/server/Drop-falling-block-and-tnt-entities-at-the-specified.patch +++ b/patches/server/Drop-falling-block-and-tnt-entities-at-the-specified.patch @@ -5,25 +5,6 @@ Subject: [PATCH] Drop falling block and tnt entities at the specified height * Dec 2, 2020 Added tnt nerf for tnt minecarts - Machine_Maker -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - keepSpawnInMemory = getBoolean("keep-spawn-loaded", true); - log("Keep spawn chunk loaded: " + keepSpawnInMemory); - } -+ -+ public int fallingBlockHeightNerf; -+ public int entityTNTHeightNerf; -+ private void heightNerfs() { -+ fallingBlockHeightNerf = getInt("falling-block-height-nerf", 0); -+ entityTNTHeightNerf = getInt("tnt-entity-height-nerf", 0); -+ -+ if (fallingBlockHeightNerf != 0) log("Falling Block Height Limit set to Y: " + fallingBlockHeightNerf); -+ if (entityTNTHeightNerf != 0) log("TNT Entity Height Limit set to Y: " + entityTNTHeightNerf); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -34,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.move(MoverType.SELF, this.getDeltaMovement()); + + // Paper start - Configurable EntityFallingBlock height nerf -+ if (this.level.paperConfig.fallingBlockHeightNerf != 0 && this.getY() > this.level.paperConfig.fallingBlockHeightNerf) { ++ if (this.level.paperConfig().fixes.fallingBlockHeightNerf != 0 && this.getY() > this.level.paperConfig().fixes.fallingBlockHeightNerf) { + if (this.dropItem && this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { + this.spawnAtLocation(block); + } @@ -55,7 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.move(MoverType.SELF, this.getDeltaMovement()); + // Paper start - Configurable TNT entity height nerf -+ if (this.level.paperConfig.entityTNTHeightNerf != 0 && this.getY() > this.level.paperConfig.entityTNTHeightNerf) { ++ if (this.level.paperConfig().fixes.tntEntityHeightNerf != 0 && this.getY() > this.level.paperConfig().fixes.tntEntityHeightNerf) { + this.discard(); + return; + } @@ -72,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super.tick(); if (this.fuse > 0) { + // Paper start - Configurable TNT entity height nerf -+ if (this.level.paperConfig.entityTNTHeightNerf != 0 && this.getY() > this.level.paperConfig.entityTNTHeightNerf) { ++ if (this.level.paperConfig().fixes.tntEntityHeightNerf != 0 && this.getY() > this.level.paperConfig().fixes.tntEntityHeightNerf) { + this.discard(); + return; + } diff --git a/patches/server/Duplicate-UUID-Resolve-Option.patch b/patches/server/Duplicate-UUID-Resolve-Option.patch index 8fa578974d..88f4b073cd 100644 --- a/patches/server/Duplicate-UUID-Resolve-Option.patch +++ b/patches/server/Duplicate-UUID-Resolve-Option.patch @@ -32,68 +32,10 @@ But for those who are ok with leaving this inconsistent behavior, you may use WA It is recommended you regenerate the entities, as these were legit entities, and deserve your love. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - preventMovingIntoUnloadedChunks = getBoolean("prevent-moving-into-unloaded-chunks", false); - } - -+ public enum DuplicateUUIDMode { -+ SAFE_REGEN, DELETE, NOTHING, WARN -+ } -+ public DuplicateUUIDMode duplicateUUIDMode = DuplicateUUIDMode.SAFE_REGEN; -+ public int duplicateUUIDDeleteRange = 32; -+ private void repairDuplicateUUID() { -+ String desiredMode = getString("duplicate-uuid-resolver", "saferegen").toLowerCase().trim(); -+ duplicateUUIDDeleteRange = getInt("duplicate-uuid-saferegen-delete-range", duplicateUUIDDeleteRange); -+ switch (desiredMode.toLowerCase()) { -+ case "regen": -+ case "regenerate": -+ case "saferegen": -+ case "saferegenerate": -+ duplicateUUIDMode = DuplicateUUIDMode.SAFE_REGEN; -+ log("Duplicate UUID Resolve: Regenerate New UUID if distant (Delete likely duplicates within " + duplicateUUIDDeleteRange + " blocks)"); -+ break; -+ case "remove": -+ case "delete": -+ duplicateUUIDMode = DuplicateUUIDMode.DELETE; -+ log("Duplicate UUID Resolve: Delete Entity"); -+ break; -+ case "silent": -+ case "nothing": -+ duplicateUUIDMode = DuplicateUUIDMode.NOTHING; -+ logError("Duplicate UUID Resolve: Do Nothing (no logs) - Warning, may lose indication of bad things happening"); -+ break; -+ case "log": -+ case "warn": -+ duplicateUUIDMode = DuplicateUUIDMode.WARN; -+ log("Duplicate UUID Resolve: Warn (do nothing but log it happened, may be spammy)"); -+ break; -+ default: -+ duplicateUUIDMode = DuplicateUUIDMode.WARN; -+ logError("Warning: Invalid duplicate-uuid-resolver config " + desiredMode + " - must be one of: regen, delete, nothing, warn"); -+ log("Duplicate UUID Resolve: Warn (do nothing but log it happened, may be spammy)"); -+ break; -+ } -+ } -+ - public boolean countAllMobsForSpawning = false; - private void countAllMobsForSpawning() { - countAllMobsForSpawning = getBoolean("count-all-mobs-for-spawning", false); diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -0,0 +0,0 @@ - package net.minecraft.server.level; - - import co.aikar.timings.Timing; // Paper -+import com.destroystokyo.paper.PaperWorldConfig; // Paper - import com.google.common.collect.ImmutableList; - import com.google.common.collect.ImmutableList.Builder; - import com.google.common.collect.Iterables; @@ -0,0 +0,0 @@ import java.io.Writer; import java.nio.file.Path; import java.util.ArrayList; @@ -126,17 +68,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + private static void checkDupeUUID(ServerLevel level, Entity entity) { -+ PaperWorldConfig.DuplicateUUIDMode mode = level.paperConfig.duplicateUUIDMode; -+ if (mode != PaperWorldConfig.DuplicateUUIDMode.WARN -+ && mode != PaperWorldConfig.DuplicateUUIDMode.DELETE -+ && mode != PaperWorldConfig.DuplicateUUIDMode.SAFE_REGEN) { ++ io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode mode = level.paperConfig().entities.spawning.duplicateUuid.mode; ++ if (mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.WARN ++ && mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.DELETE ++ && mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.SAFE_REGEN) { + return; + } + Entity other = level.getEntity(entity.getUUID()); + -+ if (mode == PaperWorldConfig.DuplicateUUIDMode.SAFE_REGEN && other != null && !other.isRemoved() ++ if (mode == io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.SAFE_REGEN && other != null && !other.isRemoved() + && Objects.equals(other.getEncodeId(), entity.getEncodeId()) -+ && entity.getBukkitEntity().getLocation().distance(other.getBukkitEntity().getLocation()) < level.paperConfig.duplicateUUIDDeleteRange ++ && entity.getBukkitEntity().getLocation().distance(other.getBukkitEntity().getLocation()) < level.paperConfig().entities.spawning.duplicateUuid.safeRegenDeleteRange + ) { + if (ServerLevel.DEBUG_ENTITIES) LOGGER.warn("[DUPE-UUID] Duplicate UUID found used by " + other + ", deleted entity " + entity + " because it was near the duplicate and likely an actual duplicate. See https://github.com/PaperMC/Paper/issues/1223 for discussion on what this is about."); + entity.discard(); @@ -181,11 +123,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end PersistentEntitySectionManager.LOGGER.warn("UUID of added entity already exists: {}", entity); + // Paper start -+ if (net.minecraft.world.level.Level.DEBUG_ENTITIES && ((Entity) entity).level.paperConfig.duplicateUUIDMode != com.destroystokyo.paper.PaperWorldConfig.DuplicateUUIDMode.NOTHING) { ++ if (net.minecraft.world.level.Level.DEBUG_ENTITIES && ((Entity) entity).level.paperConfig().entities.spawning.duplicateUuid.mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.NOTHING) { + if (((Entity) entity).addedToWorldStack != null) { + ((Entity) entity).addedToWorldStack.printStackTrace(); + } -+ net.minecraft.server.level.ServerLevel.getAddToWorldStackTrace((net.minecraft.world.entity.Entity) entity).printStackTrace(); ++ net.minecraft.server.level.ServerLevel.getAddToWorldStackTrace((Entity) entity).printStackTrace(); + } + // Paper end return false; diff --git a/patches/server/Eigencraft-redstone-implementation.patch b/patches/server/Eigencraft-redstone-implementation.patch index aa3a3120ec..13e9be3331 100644 --- a/patches/server/Eigencraft-redstone-implementation.patch +++ b/patches/server/Eigencraft-redstone-implementation.patch @@ -18,51 +18,6 @@ A lot of this code is self-contained in a helper class. Aside from making the obvious class/function renames and obfhelpers I didn't need to modify much. Just added Bukkit's event system and took a few liberties with dead code and comment misspellings. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - zombiesTargetTurtleEggs = getBoolean("zombies-target-turtle-eggs", zombiesTargetTurtleEggs); - } - -+ public enum RedstoneImplementation { -+ VANILLA, EIGENCRAFT -+ } -+ public RedstoneImplementation redstoneImplementation = RedstoneImplementation.VANILLA; -+ private void redstoneImplementation() { -+ String implementation; -+ if (PaperConfig.version < 27) { -+ implementation = "vanilla"; -+ if (config.contains("world-settings.default.use-faster-eigencraft-redstone")) { -+ implementation = config.getBoolean("world-settings.default.use-faster-eigencraft-redstone") ? "eigencraft" : "vanilla"; -+ config.set("world-settings.default.redstone-implementation", implementation); -+ } -+ if (config.contains("world-settings." + worldName + ".use-faster-eigencraft-redstone")) { -+ implementation = config.getBoolean("world-settings." + worldName + ".use-faster-eigencraft-redstone") ? "eigencraft" : "vanilla"; -+ config.set("world-settings." + worldName + ".redstone-implementation", implementation); -+ } -+ remove("use-faster-eigencraft-redstone"); -+ } else { -+ implementation = this.getString("redstone-implementation", "vanilla").toLowerCase().trim(); -+ } -+ switch (implementation) { -+ default: -+ logError("Invalid redstone-implementation config " + implementation + " - must be one of: vanilla, eigencraft"); -+ case "vanilla": -+ redstoneImplementation = RedstoneImplementation.VANILLA; -+ log("Using the Vanilla redstone implementation."); -+ break; -+ case "eigencraft": -+ redstoneImplementation = RedstoneImplementation.EIGENCRAFT; -+ log("Using Eigencraft's redstone implementation by theosib."); -+ break; -+ } -+ } -+ - public short keepLoadedRange; - private void keepLoadedRange() { - keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); diff --git a/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -1000,7 +955,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * Note: Added 'source' argument so as to help determine direction of information flow + */ + private void updateSurroundingRedstone(Level worldIn, BlockPos pos, BlockState state, BlockPos source) { -+ if (worldIn.paperConfig.redstoneImplementation == com.destroystokyo.paper.PaperWorldConfig.RedstoneImplementation.EIGENCRAFT) { ++ if (worldIn.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) { + turbo.updateSurroundingRedstone(worldIn, pos, state, source); + return; + } @@ -1024,7 +979,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + int k = worldIn.getBestNeighborSignal(pos1); + this.shouldSignal = true; + -+ if (worldIn.paperConfig.redstoneImplementation == com.destroystokyo.paper.PaperWorldConfig.RedstoneImplementation.VANILLA) { ++ if (worldIn.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.VANILLA) { + // This code is totally redundant to if statements just below the loop. + if (k > 0 && k > j - 1) { + j = k; @@ -1038,7 +993,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // redstone wire will be set to 'k'. If 'k' is already 15, then nothing inside the + // following loop can affect the power level of the wire. Therefore, the loop is + // skipped if k is already 15. -+ if (worldIn.paperConfig.redstoneImplementation == com.destroystokyo.paper.PaperWorldConfig.RedstoneImplementation.VANILLA || k < 15) { ++ if (worldIn.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.VANILLA || k < 15) { + for (Direction enumfacing : Direction.Plane.HORIZONTAL) { + BlockPos blockpos = pos1.relative(enumfacing); + boolean flag = blockpos.getX() != pos2.getX() || blockpos.getZ() != pos2.getZ(); @@ -1057,7 +1012,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + -+ if (worldIn.paperConfig.redstoneImplementation == com.destroystokyo.paper.PaperWorldConfig.RedstoneImplementation.VANILLA) { ++ if (worldIn.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.VANILLA) { + // The old code would decrement the wire value only by 1 at a time. + if (l > j) { + j = l - 1; diff --git a/patches/server/Enhance-console-tab-completions-for-brigadier-comman.patch b/patches/server/Enhance-console-tab-completions-for-brigadier-comman.patch index e333fce307..7f22e4b3a1 100644 --- a/patches/server/Enhance-console-tab-completions-for-brigadier-comman.patch +++ b/patches/server/Enhance-console-tab-completions-for-brigadier-comman.patch @@ -4,25 +4,6 @@ Date: Tue, 30 Mar 2021 16:06:08 -0700 Subject: [PATCH] Enhance console tab completions for brigadier commands -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - trackPluginScoreboards = getBoolean("settings.track-plugin-scoreboards", false); - } - -+ -+ public static boolean enableBrigadierConsoleHighlighting = true; -+ public static boolean enableBrigadierConsoleCompletions = true; -+ private static void consoleSettings() { -+ enableBrigadierConsoleHighlighting = getBoolean("settings.console.enable-brigadier-highlighting", enableBrigadierConsoleHighlighting); -+ enableBrigadierConsoleCompletions = getBoolean("settings.console.enable-brigadier-completions", enableBrigadierConsoleCompletions); -+ } -+ - public static void registerCommands() { - for (Map.Entry entry : commands.entrySet()) { - MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Paper", entry.getValue()); diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java @@ -38,7 +19,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 .completer(new ConsoleCommandCompleter(this.server)) - ); + .option(LineReader.Option.COMPLETE_IN_WORD, true); -+ if (com.destroystokyo.paper.PaperConfig.enableBrigadierConsoleHighlighting) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierHighlighting) { + builder.highlighter(new io.papermc.paper.console.BrigadierCommandHighlighter(this.server, this.server.createCommandSourceStack())); + } + return super.buildReader(builder); @@ -83,7 +64,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public void complete(final @NonNull LineReader reader, final @NonNull ParsedLine line, final @NonNull List candidates, final @NonNull List existing) { -+ if (!com.destroystokyo.paper.PaperConfig.enableBrigadierConsoleCompletions) { ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierCompletions) { + this.addCandidates(candidates, Collections.emptyList(), existing); + return; + } @@ -230,13 +211,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) { DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); @@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - DedicatedServer.LOGGER.error("Unable to load server configuration", e); - return false; - } + paperConfigurations.initializeGlobalConfiguration(); + paperConfigurations.initializeWorldDefaultsConfiguration(); + org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); + thread.start(); // Paper - start console thread after MinecraftServer.console & PaperConfig are initialized - com.destroystokyo.paper.PaperConfig.registerCommands(); + io.papermc.paper.configuration.PaperConfigurations.registerCommands(this); com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now - io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // load mappings for stacktrace deobf and etc. + // Paper end diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java diff --git a/patches/server/Entity-Activation-Range-2.0.patch b/patches/server/Entity-Activation-Range-2.0.patch index 50fb084d81..f178b499ce 100644 --- a/patches/server/Entity-Activation-Range-2.0.patch +++ b/patches/server/Entity-Activation-Range-2.0.patch @@ -318,7 +318,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end public boolean populating; public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot - + // Paper start diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java diff --git a/patches/server/Entity-load-save-limit-per-chunk.patch b/patches/server/Entity-load-save-limit-per-chunk.patch index e4b1d9c3a0..ac8331526f 100644 --- a/patches/server/Entity-load-save-limit-per-chunk.patch +++ b/patches/server/Entity-load-save-limit-per-chunk.patch @@ -8,58 +8,6 @@ to a chunk. The default values of -1 disable the limit. Although defaults are only included for certain entites, this allows setting limits for any entity type. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ import it.unimi.dsi.fastutil.objects.Reference2IntMap; - import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; - import net.minecraft.world.entity.MobCategory; - import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray.EngineMode; -+import java.util.HashMap; -+import java.util.Map; - import org.bukkit.Bukkit; - import org.bukkit.configuration.file.YamlConfiguration; - import org.spigotmc.SpigotWorldConfig; -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - } - -+ public Map, Integer> entityPerChunkSaveLimits = new HashMap<>(); -+ private void entityPerChunkSaveLimits() { -+ getInt("entity-per-chunk-save-limit.experience_orb", -1); -+ getInt("entity-per-chunk-save-limit.snowball", -1); -+ getInt("entity-per-chunk-save-limit.ender_pearl", -1); -+ getInt("entity-per-chunk-save-limit.arrow", -1); -+ getInt("entity-per-chunk-save-limit.fireball", -1); -+ getInt("entity-per-chunk-save-limit.small_fireball", -1); -+ -+ addEntityPerChunkSaveLimitsFromSection(config.getConfigurationSection("world-settings.default.entity-per-chunk-save-limit"), entityPerChunkSaveLimits); -+ addEntityPerChunkSaveLimitsFromSection(config.getConfigurationSection("world-settings." + worldName + ".entity-per-chunk-save-limit"), entityPerChunkSaveLimits); -+ } -+ -+ private static void addEntityPerChunkSaveLimitsFromSection(final org.bukkit.configuration.ConfigurationSection section, final Map, Integer> limitMap) { -+ if (section == null) { -+ return; -+ } -+ for (final String key : section.getKeys(false)) { -+ final int value = section.getInt(key); -+ final net.minecraft.world.entity.EntityType type = net.minecraft.world.entity.EntityType.byString(key).orElse(null); -+ if (type == null) { -+ logError("Invalid entity-per-chunk-save-limit config, '" + key+ "' is not a valid entity type. Correct this in paper.yml."); -+ continue; -+ } -+ if (value >= 0) { -+ limitMap.put(type, value); -+ } else { -+ limitMap.remove(type); -+ } -+ } -+ } -+ - public short keepLoadedRange; - private void keepLoadedRange() { - keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/EntityType.java @@ -74,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 EntityType.loadEntityRecursive((CompoundTag) nbtbase, world, (entity) -> { + // Paper start + final EntityType entityType = entity.getType(); -+ final int saveLimit = world.paperConfig.entityPerChunkSaveLimits.getOrDefault(entityType, -1); ++ final int saveLimit = world.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1); + if (saveLimit > -1) { + if (this.loadedEntityCounts.getOrDefault(entityType, 0) >= saveLimit) { + return null; @@ -97,7 +45,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 dataList.getEntities().forEach((entity) -> { + // Paper start + final EntityType entityType = entity.getType(); -+ final int saveLimit = this.level.paperConfig.entityPerChunkSaveLimits.getOrDefault(entityType, -1); ++ final int saveLimit = this.level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1); + if (saveLimit > -1) { + if (savedEntityCounts.getOrDefault(entityType, 0) >= saveLimit) { + return; diff --git a/patches/server/EntityMoveEvent.patch b/patches/server/EntityMoveEvent.patch index 30e1dbaa2b..8bcfd66dd5 100644 --- a/patches/server/EntityMoveEvent.patch +++ b/patches/server/EntityMoveEvent.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ServerLevel worldserver = (ServerLevel) iterator.next(); worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper + worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper + net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper this.profiler.push(() -> { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java diff --git a/patches/server/Filter-bad-data-from-ArmorStand-and-SpawnEgg-items.patch b/patches/server/Filter-bad-data-from-ArmorStand-and-SpawnEgg-items.patch index 45d5c4e6cf..93f07ffb51 100644 --- a/patches/server/Filter-bad-data-from-ArmorStand-and-SpawnEgg-items.patch +++ b/patches/server/Filter-bad-data-from-ArmorStand-and-SpawnEgg-items.patch @@ -4,23 +4,6 @@ Date: Sat, 12 Nov 2016 23:25:22 -0600 Subject: [PATCH] Filter bad data from ArmorStand and SpawnEgg items -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - preventTntFromMovingInWater = getBoolean("prevent-tnt-from-moving-in-water", false); - log("Prevent TNT from moving in water: " + preventTntFromMovingInWater); - } -+ -+ public boolean filterNBTFromSpawnEgg = true; -+ private void fitlerNBTFromSpawnEgg() { -+ filterNBTFromSpawnEgg = getBoolean("filter-nbt-data-from-spawn-eggs-and-related", true); -+ if (!filterNBTFromSpawnEgg) { -+ Bukkit.getLogger().warning("Spawn Egg and Armor Stand NBT filtering disabled, this is a potential security risk"); -+ } -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -31,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.blockState = NbtUtils.readBlockState(nbt.getCompound("BlockState")); + // Paper start - Block FallingBlocks with Command Blocks + final Block b = this.blockState.getBlock(); -+ if (this.level.paperConfig.filterNBTFromSpawnEgg ++ if (this.level.paperConfig().entities.spawning.filterNbtDataFromSpawnEggsAndRelated + && (b == Blocks.COMMAND_BLOCK + || b == Blocks.REPEATING_COMMAND_BLOCK + || b == Blocks.CHAIN_COMMAND_BLOCK diff --git a/patches/server/Fix-Light-Command.patch b/patches/server/Fix-Light-Command.patch index d4ca2d5884..9052ed29c7 100644 --- a/patches/server/Fix-Light-Command.patch +++ b/patches/server/Fix-Light-Command.patch @@ -105,7 +105,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + updateLight(sender, world, lightengine, queue); + return; + } -+ lightengine.setTaskPerBatch(world.paperConfig.lightQueueSize + 16 * 256); // ensure full chunk can fit into queue ++ lightengine.setTaskPerBatch(world.paperConfig().misc.lightQueueSize + 16 * 256); // ensure full chunk can fit into queue + sender.sendMessage("Updating Light " + coord); + int cx = chunk.getPos().x << 4; + int cz = chunk.getPos().z << 4; @@ -129,7 +129,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } else { + updateLight(sender, world, lightengine, queue); + } -+ lightengine.setTaskPerBatch(world.paperConfig.lightQueueSize); ++ lightengine.setTaskPerBatch(world.paperConfig().misc.lightQueueSize); + }, MinecraftServer.getServer()); + } } diff --git a/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch index 15240ec894..9e7011b9a0 100644 --- a/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch +++ b/patches/server/Fix-Per-World-Difficulty-Remembering-Difficulty.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop public -- public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory) { -+ public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, File userCacheFile) { // Paper +- public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, joptsimple.OptionSet optionSet) throws Exception { // Paper ++ public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, File userCacheFile, joptsimple.OptionSet optionSet) throws Exception { // Paper MinecraftSessionService minecraftSessionService = authenticationService.createMinecraftSessionService(); GameProfileRepository gameProfileRepository = authenticationService.createProfileRepository(); - GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, new File(rootDirectory, "usercache.json")); + GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, userCacheFile); // Paper SignatureValidator signatureValidator = SignatureValidator.from(authenticationService.getServicesKey()); - return new Services(minecraftSessionService, signatureValidator, gameProfileRepository, gameProfileCache); - } + // Paper start + io.papermc.paper.configuration.PaperConfigurations paperConfigurations = io.papermc.paper.configuration.PaperConfigurations.setup(((File) optionSet.valueOf("paper-settings")).toPath(), java.nio.file.Path.of("config"), rootDirectory.toPath(), (File) optionSet.valueOf("spigot-settings")); diff --git a/patches/server/Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch b/patches/server/Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch index d585c846b1..5d653e54d1 100644 --- a/patches/server/Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch +++ b/patches/server/Fix-SpawnChangeEvent-not-firing-for-all-use-cases.patch @@ -15,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + new org.bukkit.event.world.SpawnChangeEvent(getWorld(), MCUtil.toLocation(this, prevSpawn)).callEvent(); // Paper if (this.keepSpawnInMemory) { // if this keepSpawnInMemory is false a plugin has already removed our tickets, do not re-add - this.removeTicketsForSpawn(this.paperConfig.keepLoadedRange, prevSpawn); + this.removeTicketsForSpawn(this.paperConfig().spawn.keepSpawnLoadedRange, prevSpawn); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java diff --git a/patches/server/Fix-and-optimise-world-force-upgrading.patch b/patches/server/Fix-and-optimise-world-force-upgrading.patch index 2adfd436f4..117cd42cad 100644 --- a/patches/server/Fix-and-optimise-world-force-upgrading.patch +++ b/patches/server/Fix-and-optimise-world-force-upgrading.patch @@ -256,8 +256,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import joptsimple.OptionParser; import joptsimple.OptionSet; @@ -0,0 +0,0 @@ public class Main { + } - // Paper end + // Paper start - fix and optimise world upgrading + public static void convertWorldButItWorks(net.minecraft.resources.ResourceKey dimensionType, net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess worldSession, diff --git a/patches/server/Fix-commands-from-signs-not-firing-command-events.patch b/patches/server/Fix-commands-from-signs-not-firing-command-events.patch index 59b4a2eb33..4bd198288d 100644 --- a/patches/server/Fix-commands-from-signs-not-firing-command-events.patch +++ b/patches/server/Fix-commands-from-signs-not-firing-command-events.patch @@ -9,20 +9,6 @@ This patch changes sign command logic so that `run_command` click events: - work with double-slash commands like `//wand` - sends failure messages to the player who clicked the sign -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void fixInvulnerableEndCrystalExploit() { - fixInvulnerableEndCrystalExploit = getBoolean("unsupported-settings.fix-invulnerable-end-crystal-exploit", fixInvulnerableEndCrystalExploit); - } -+ -+ public boolean showSignClickCommandFailureMessagesToPlayer = false; -+ private void showSignClickCommandFailureMessagesToPlayer() { -+ showSignClickCommandFailureMessagesToPlayer = getBoolean("show-sign-click-command-failure-msgs-to-player", showSignClickCommandFailureMessagesToPlayer); -+ } - } diff --git a/src/main/java/io/papermc/paper/commands/DelegatingCommandSource.java b/src/main/java/io/papermc/paper/commands/DelegatingCommandSource.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -106,7 +92,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Object object = player == null ? Component.literal("Sign") : player.getDisplayName(); + // Paper start - send messages back to the player -+ CommandSource commandSource = this.level.paperConfig.showSignClickCommandFailureMessagesToPlayer ? new io.papermc.paper.commands.DelegatingCommandSource(this) { ++ CommandSource commandSource = this.level.paperConfig().misc.showSignClickCommandFailureMsgsToPlayer ? new io.papermc.paper.commands.DelegatingCommandSource(this) { + @Override + public void sendSystemMessage(Component message) { + player.sendSystemMessage(message); diff --git a/patches/server/Fix-curing-zombie-villager-discount-exploit.patch b/patches/server/Fix-curing-zombie-villager-discount-exploit.patch index 62d54fdbf6..18ce09278c 100644 --- a/patches/server/Fix-curing-zombie-villager-discount-exploit.patch +++ b/patches/server/Fix-curing-zombie-villager-discount-exploit.patch @@ -7,22 +7,6 @@ This fixes the exploit used to gain absurd trading discounts with infecting and curing a villager on repeat by simply resetting the relevant part of the reputation when it is cured. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - fixClimbingBypassingCrammingRule = getBoolean("fix-climbing-bypassing-cramming-rule", fixClimbingBypassingCrammingRule); - } - -+ public boolean fixCuringZombieVillagerDiscountExploit = true; -+ private void fixCuringExploit() { -+ fixCuringZombieVillagerDiscountExploit = getBoolean("game-mechanics.fix-curing-zombie-villager-discount-exploit", fixCuringZombieVillagerDiscountExploit); -+ } -+ - public short keepLoadedRange; - private void keepLoadedRange() { - keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java @@ -32,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void onReputationEventFrom(ReputationEventType interaction, Entity entity) { if (interaction == ReputationEventType.ZOMBIE_VILLAGER_CURED) { + // Paper start - fix MC-181190 -+ if (level.paperConfig.fixCuringZombieVillagerDiscountExploit) { ++ if (level.paperConfig().fixes.fixCuringZombieVillagerDiscountExploit) { + final GossipContainer.EntityGossips playerReputation = this.getGossips().getReputations().get(entity.getUUID()); + if (playerReputation != null) { + playerReputation.remove(GossipType.MAJOR_POSITIVE); diff --git a/patches/server/Fix-entity-type-tags-suggestions-in-selectors.patch b/patches/server/Fix-entity-type-tags-suggestions-in-selectors.patch index f831960e5b..5491a12c18 100644 --- a/patches/server/Fix-entity-type-tags-suggestions-in-selectors.patch +++ b/patches/server/Fix-entity-type-tags-suggestions-in-selectors.patch @@ -9,22 +9,6 @@ when if this was fixed on the client, that wouldn't be needed. Mojira Issue: https://bugs.mojang.com/browse/MC-235045 -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - itemValidationBookPageLength = getInt("settings.item-validation.book.page", itemValidationBookPageLength); - } - -+ public static boolean fixTargetSelectorTagCompletion = true; -+ private static void fixTargetSelectorTagCompletion() { -+ fixTargetSelectorTagCompletion = getBoolean("settings.fix-target-selector-tag-completion", fixTargetSelectorTagCompletion); -+ } -+ - public static final class PacketLimit { - public final double packetLimitInterval; - public final double maxPacketRate; diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/commands/CommandSourceStack.java @@ -36,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - override getSelectedEntities + @Override + public Collection getSelectedEntities() { -+ if (com.destroystokyo.paper.PaperConfig.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) { + double pickDistance = player.gameMode.getGameModeForPlayer().isCreative() ? 5.0F : 4.5F; + Vec3 min = player.getEyePosition(1.0F); + Vec3 viewVector = player.getViewVector(1.0F); @@ -68,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 requiredargumentbuilder.suggests(SuggestionProviders.safelySwap(requiredargumentbuilder.getSuggestionsProvider())); + // Paper start - tell clients to ask server for suggestions for EntityArguments + registeredAskServerSuggestionsForTree = requiredargumentbuilder.getSuggestionsProvider() == net.minecraft.commands.synchronization.SuggestionProviders.ASK_SERVER; -+ } else if (com.destroystokyo.paper.PaperConfig.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredargumentbuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) { ++ } else if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredargumentbuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) { + requiredargumentbuilder.suggests(requiredargumentbuilder.getType()::listSuggestions); + registeredAskServerSuggestionsForTree = true; // You can only + // Paper end - tell clients to ask server for suggestions for EntityArguments @@ -141,7 +125,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (reader.isTag()) { TagKey> tagKey = TagKey.create(Registry.ENTITY_TYPE_REGISTRY, ResourceLocation.read(reader.getReader())); + // Paper start - throw error if invalid entity tag (only on suggestions to keep cmd success behavior) -+ if (com.destroystokyo.paper.PaperConfig.fixTargetSelectorTagCompletion && reader.parsingEntityArgumentSuggestions && !Registry.ENTITY_TYPE.isKnownTagName(tagKey)) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && reader.parsingEntityArgumentSuggestions && !Registry.ENTITY_TYPE.isKnownTagName(tagKey)) { + reader.getReader().setCursor(i); + throw ERROR_ENTITY_TAG_INVALID.createWithContext(reader.getReader(), tagKey); + } diff --git a/patches/server/Fix-hex-colors-not-working-in-some-kick-messages.patch b/patches/server/Fix-hex-colors-not-working-in-some-kick-messages.patch index db4cbef1de..1501cf4594 100644 --- a/patches/server/Fix-hex-colors-not-working-in-some-kick-messages.patch +++ b/patches/server/Fix-hex-colors-not-working-in-some-kick-messages.patch @@ -12,8 +12,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 synchronized (ServerHandshakePacketListenerImpl.throttleTracker) { if (ServerHandshakePacketListenerImpl.throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - ServerHandshakePacketListenerImpl.throttleTracker.get(address) < connectionThrottle) { ServerHandshakePacketListenerImpl.throttleTracker.put(address, currentTime); -- MutableComponent chatmessage = Component.literal(com.destroystokyo.paper.PaperConfig.connectionThrottleKickMessage); // Paper - Configurable connection throttle kick message -+ Component chatmessage = org.bukkit.craftbukkit.util.CraftChatMessage.fromString(com.destroystokyo.paper.PaperConfig.connectionThrottleKickMessage, true)[0]; // Paper - Configurable connection throttle kick message // Paper - Fix hex colors not working in some kick messages +- MutableComponent chatmessage = Component.literal(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.connectionThrottle); // Paper - Configurable connection throttle kick message ++ Component chatmessage = org.bukkit.craftbukkit.util.CraftChatMessage.fromString(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.connectionThrottle, true)[0]; // Paper - Configurable connection throttle kick message // Paper - Fix hex colors not working in some kick messages this.connection.send(new ClientboundLoginDisconnectPacket(chatmessage)); this.connection.disconnect(chatmessage); return; diff --git a/patches/server/Fix-invulnerable-end-crystals.patch b/patches/server/Fix-invulnerable-end-crystals.patch index f12c9a6682..1b9bae57b8 100644 --- a/patches/server/Fix-invulnerable-end-crystals.patch +++ b/patches/server/Fix-invulnerable-end-crystals.patch @@ -5,20 +5,6 @@ Subject: [PATCH] Fix invulnerable end crystals MC-108513 -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void fixItemsMergingThroughWalls() { - fixItemsMergingThroughWalls = getBoolean("fix-items-merging-through-walls", fixItemsMergingThroughWalls); - } -+ -+ public boolean fixInvulnerableEndCrystalExploit = true; -+ private void fixInvulnerableEndCrystalExploit() { -+ fixInvulnerableEndCrystalExploit = getBoolean("unsupported-settings.fix-invulnerable-end-crystal-exploit", fixInvulnerableEndCrystalExploit); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java @@ -36,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit end } + // Paper start - Fix invulnerable end crystals -+ if (this.level.paperConfig.fixInvulnerableEndCrystalExploit && this.generatedByDragonFight && this.isInvulnerable()) { ++ if (this.level.paperConfig().unsupportedSettings.fixInvulnerableEndCrystalExploit && this.generatedByDragonFight && this.isInvulnerable()) { + if (!java.util.Objects.equals(((ServerLevel) this.level).uuid, this.getOriginWorld()) + || ((ServerLevel) this.level).dragonFight() == null + || ((ServerLevel) this.level).dragonFight().respawnStage == null diff --git a/patches/server/Fix-piston-physics-inconsistency-MC-188840.patch b/patches/server/Fix-piston-physics-inconsistency-MC-188840.patch index 7a5cb43489..40fa67fd50 100644 --- a/patches/server/Fix-piston-physics-inconsistency-MC-188840.patch +++ b/patches/server/Fix-piston-physics-inconsistency-MC-188840.patch @@ -31,23 +31,6 @@ This patch fixes https://bugs.mojang.com/browse/MC-188840 This patch also fixes rail duping and carpet duping. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void consoleHasAllPermissions() { - consoleHasAllPermissions = getBoolean("settings.console-has-all-permissions", consoleHasAllPermissions); - } -+ -+ public static boolean allowPistonDuplication; -+ private static void allowPistonDuplication() { -+ config.set("settings.unsupported-settings.allow-piston-duplication-readme", "This setting controls if player should be able to use TNT duplication, but this also allows duplicating carpet, rails and potentially other items"); -+ allowPistonDuplication = getBoolean("settings.unsupported-settings.allow-piston-duplication", config.getBoolean("settings.unsupported-settings.allow-tnt-duplication", false)); -+ set("settings.unsupported-settings.allow-tnt-duplication", null); -+ } -+ - } diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java @@ -59,7 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - blockposition3 = (BlockPos) list.get(k); - iblockdata1 = world.getBlockState(blockposition3); + // Paper start - fix a variety of piston desync dupes -+ boolean allowDesync = com.destroystokyo.paper.PaperConfig.allowPistonDuplication; ++ boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication; + BlockPos oldPos = blockposition3 = (BlockPos) list.get(k); + iblockdata1 = allowDesync ? world.getBlockState(oldPos) : null; + // Paper end - fix a variety of piston desync dupes @@ -91,7 +74,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockState blockState = Block.updateFromNeighbourShapes(blockEntity.movedState, world, pos); if (blockState.isAir()) { - world.setBlock(pos, blockEntity.movedState, 84); -+ world.setBlock(pos, blockEntity.movedState, com.destroystokyo.paper.PaperConfig.allowPistonDuplication ? 84 : (84 | 2)); // Paper - force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air ++ world.setBlock(pos, blockEntity.movedState, io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 84 : (84 | 2)); // Paper - force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air Block.updateOrDestroy(blockEntity.movedState, blockState, world, pos, 3); } else { if (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED)) { diff --git a/patches/server/Fix-sand-duping.patch b/patches/server/Fix-sand-duping.patch index 8a8245a06d..0a3a7cb42f 100644 --- a/patches/server/Fix-sand-duping.patch +++ b/patches/server/Fix-sand-duping.patch @@ -33,5 +33,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - fix sand duping + // Paper start - Configurable EntityFallingBlock height nerf - if (this.level.paperConfig.fallingBlockHeightNerf != 0 && this.getY() > this.level.paperConfig.fallingBlockHeightNerf) { + if (this.level.paperConfig().fixes.fallingBlockHeightNerf != 0 && this.getY() > this.level.paperConfig().fixes.fallingBlockHeightNerf) { if (this.dropItem && this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { diff --git a/patches/server/Fix-slime-spawners-not-spawning-outside-slime-chunks.patch b/patches/server/Fix-slime-spawners-not-spawning-outside-slime-chunks.patch index f6510f05c0..720246593f 100644 --- a/patches/server/Fix-slime-spawners-not-spawning-outside-slime-chunks.patch +++ b/patches/server/Fix-slime-spawners-not-spawning-outside-slime-chunks.patch @@ -20,5 +20,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end // Paper start - Replace rules for Height in Swamp Biome - final double maxHeightSwamp = world.getMinecraftWorld().paperConfig.slimeMaxSpawnHeightInSwamp; - final double minHeightSwamp = world.getMinecraftWorld().paperConfig.slimeMinSpawnHeightInSwamp; + final double maxHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.swampBiome.maximum; + final double minHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.swampBiome.minimum; diff --git a/patches/server/Fixes-kick-event-leave-message-not-being-sent.patch b/patches/server/Fixes-kick-event-leave-message-not-being-sent.patch index 31651f0a13..fb896486f7 100644 --- a/patches/server/Fixes-kick-event-leave-message-not-being-sent.patch +++ b/patches/server/Fixes-kick-event-leave-message-not-being-sent.patch @@ -67,7 +67,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer) { // Paper - return Component + // Paper start -+ return this.remove(entityplayer, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName()))); ++ return this.remove(entityplayer, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName()))); + } + public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer, net.kyori.adventure.text.Component leaveMessage) { + // Paper end @@ -78,7 +78,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper } -- PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName())), entityplayer.quitReason); // Paper - quit reason +- PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName())), entityplayer.quitReason); // Paper - quit reason + PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), leaveMessage, entityplayer.quitReason); // Paper - quit reason if (entityplayer.didPlayerJoinEvent) this.cserver.getPluginManager().callEvent(playerQuitEvent); // Paper - if we disconnected before join ever fired, don't fire quit entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); diff --git a/patches/server/Flat-bedrock-generator-settings.patch b/patches/server/Flat-bedrock-generator-settings.patch index ba09508a88..96c87eda0e 100644 --- a/patches/server/Flat-bedrock-generator-settings.patch +++ b/patches/server/Flat-bedrock-generator-settings.patch @@ -5,21 +5,6 @@ Subject: [PATCH] Flat bedrock generator settings Co-authored-by: Noah van der Aa -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void pillagerSettings() { - disablePillagerPatrols = getBoolean("game-mechanics.disable-pillager-patrols", disablePillagerPatrols); - } -+ -+ public boolean generateFlatBedrock = false; -+ private void generatorSettings() { -+ generateFlatBedrock = getBoolean("generator-settings.flat-bedrock", this.generateFlatBedrock); -+ } - } - diff --git a/src/main/java/net/minecraft/data/worldgen/SurfaceRuleData.java b/src/main/java/net/minecraft/data/worldgen/SurfaceRuleData.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/data/worldgen/SurfaceRuleData.java @@ -53,7 +38,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Override + public SurfaceRules.Condition apply(SurfaceRules.Context context) { -+ boolean hasFlatBedrock = context.context.getWorld().paperConfig.generateFlatBedrock; ++ boolean hasFlatBedrock = context.context.getWorld().paperConfig().environment.generateFlatBedrock; + int trueAtY = this.trueAtAndBelow().resolveY(context.context); + int falseAtY = this.falseAtAndAbove().resolveY(context.context); + diff --git a/patches/server/Further-improve-server-tick-loop.patch b/patches/server/Further-improve-server-tick-loop.patch index 8e013b114f..eef0ff54d3 100644 --- a/patches/server/Further-improve-server-tick-loop.patch +++ b/patches/server/Further-improve-server-tick-loop.patch @@ -32,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + private static final int SAMPLE_INTERVAL = 20; // Paper public final double[] recentTps = new double[ 3 ]; // Spigot end - public static long currentTickLong = 0L; // Paper + public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop loadTickRates(String type) { - log(" " + type + ":"); - com.google.common.collect.Table table = com.google.common.collect.HashBasedTable.create(); diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java @@ -59,14 +41,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + final ItemStack copy = copyItemStack ? itemStack.copy() : itemStack; -+ if (level.paperConfig.hideDurabilityFromClients) { ++ if (level.paperConfig().anticheat.obfuscation.items.hideDurability) { + // Only show damage values for elytra's, since they show a different texture when broken. + if (!copy.is(Items.ELYTRA) || copy.getDamageValue() < copy.getMaxDamage() - 1) { + copy.setDamageValue(0); + } + } + -+ if (level.paperConfig.hideItemmetaFromClients) { ++ if (level.paperConfig().anticheat.obfuscation.items.hideItemmeta) { + // Some resource packs show different textures when there is more than one item. Since this shouldn't provide a big advantage, + // we'll tell the client if there's one or (more than) two items. + copy.setCount(copy.getCount() > 1 ? 2 : 1); diff --git a/patches/server/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch b/patches/server/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch index 3a3a097825..f2d512c2f5 100644 --- a/patches/server/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch +++ b/patches/server/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch @@ -424,7 +424,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start public void updatePlayerMobTypeMap(Entity entity) { - if (!this.level.paperConfig.perPlayerMobSpawns) { + if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider List list1 = new ArrayList(); int j = centerChunk.x; diff --git a/patches/server/Implement-Mob-Goal-API.patch b/patches/server/Implement-Mob-Goal-API.patch index 7bcdfc0c9a..a25410bed4 100644 --- a/patches/server/Implement-Mob-Goal-API.patch +++ b/patches/server/Implement-Mob-Goal-API.patch @@ -9,8 +9,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -0,0 +0,0 @@ dependencies { - - implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation + runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.3") + runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.3") + testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test testImplementation("junit:junit:4.13.2") diff --git a/patches/server/Implement-Paper-VersionChecker.patch b/patches/server/Implement-Paper-VersionChecker.patch index 66870a8eef..7a130dbaba 100644 --- a/patches/server/Implement-Paper-VersionChecker.patch +++ b/patches/server/Implement-Paper-VersionChecker.patch @@ -145,7 +145,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -0,0 +0,0 @@ public final class CraftMagicNumbers implements UnsafeValues { public String getTimingsServerName() { - return com.destroystokyo.paper.PaperConfig.timingsServerName; + return io.papermc.paper.configuration.GlobalConfiguration.get().timings.serverName; } + + @Override diff --git a/patches/server/Implement-alternative-item-despawn-rate.patch b/patches/server/Implement-alternative-item-despawn-rate.patch index 23296bd695..b674dc1e77 100644 --- a/patches/server/Implement-alternative-item-despawn-rate.patch +++ b/patches/server/Implement-alternative-item-despawn-rate.patch @@ -5,86 +5,6 @@ Subject: [PATCH] Implement alternative item-despawn-rate Co-authored-by: Noah van der Aa -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - Bukkit.getLogger().warning("You have enabled permission-based Anti-Xray checking - depending on your permission plugin, this may cause performance issues"); - } - } --} - -+ public boolean altItemDespawnRateEnabled; -+ public java.util.Map altItemDespawnRateMap = new java.util.HashMap<>(); -+ private void altItemDespawnRate() { -+ String path = "alt-item-despawn-rate"; -+ // Migrate from bukkit material to Mojang item ids -+ if (PaperConfig.version < 26) { -+ String world = worldName; -+ try { -+ org.bukkit.configuration.ConfigurationSection mapSection = config.getConfigurationSection("world-settings." + world + "." + path + ".items"); -+ if (mapSection == null) { -+ world = "default"; -+ mapSection = config.getConfigurationSection("world-settings." + world + "." + path + ".items"); -+ } -+ if (mapSection != null) { -+ for (String key : mapSection.getKeys(false)) { -+ int val = mapSection.getInt(key); -+ try { -+ // Ignore options that are already valid mojang wise, otherwise we might try to migrate the same config twice and fail. -+ boolean isMojangMaterial = net.minecraft.core.Registry.ITEM.getOptional(new net.minecraft.resources.ResourceLocation(key.toLowerCase())).isPresent(); -+ mapSection.set(key, null); -+ String newKey = isMojangMaterial ? key.toLowerCase() : org.bukkit.Material.valueOf(key).getKey().getKey().toLowerCase(); -+ mapSection.set(newKey, val); -+ } catch (Exception e) { -+ logError("Could not add item " + key + " to altItemDespawnRateMap: " + e.getMessage()); -+ } -+ } -+ config.set("world-settings." + world + "." + path + ".items", mapSection); -+ } -+ } catch (Exception e) { -+ logError("alt-item-despawn-rate was malformatted"); -+ return; -+ } -+ } -+ -+ altItemDespawnRateEnabled = getBoolean(path + ".enabled", false); -+ -+ if (config.getConfigurationSection("world-settings.default." + path + ".items") == null) { -+ // Initialize default -+ config.addDefault("world-settings.default." + path + ".items.cobblestone", 300); -+ } -+ -+ if (!altItemDespawnRateEnabled) { -+ return; -+ } -+ -+ org.bukkit.configuration.ConfigurationSection mapSection = config.getConfigurationSection("world-settings." + worldName + "." + path + ".items"); -+ if (mapSection == null) { -+ mapSection = config.getConfigurationSection("world-settings.default." + path + ".items"); -+ } -+ if (mapSection != null) { -+ for (String key : mapSection.getKeys(false)) { -+ try { -+ int val = mapSection.getInt(key); -+ net.minecraft.resources.ResourceLocation keyLocation = new net.minecraft.resources.ResourceLocation(key); -+ if (net.minecraft.core.Registry.ITEM.getOptional(keyLocation).isPresent()) { -+ altItemDespawnRateMap.put(keyLocation, val); -+ } else { -+ logError("Could not add item " + key + " to altItemDespawnRateMap: not a valid item"); -+ } -+ } catch (Exception e) { -+ logError("Could not add item " + key + " to altItemDespawnRateMap: " + e.getMessage()); -+ } -+ } -+ } -+ -+ for (net.minecraft.resources.ResourceLocation key : altItemDespawnRateMap.keySet()) { -+ log("Alternative item despawn rate of " + key.getPath() + ": " + altItemDespawnRateMap.get(key)); -+ } -+ } -+} diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java @@ -128,8 +48,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 com.google.common.base.Preconditions.checkArgument(!stack.isEmpty(), "Cannot drop air"); // CraftBukkit this.getEntityData().set(ItemEntity.DATA_ITEM, stack); this.getEntityData().markDirty(ItemEntity.DATA_ITEM); // CraftBukkit - SPIGOT-4591, must mark dirty -+ net.minecraft.resources.ResourceLocation location = net.minecraft.core.Registry.ITEM.getKey(stack.getItem()); // Paper -+ this.despawnRate = level.paperConfig.altItemDespawnRateMap.getOrDefault(location, level.spigotConfig.itemDespawnRate); // Paper ++ this.despawnRate = level.paperConfig().entities.spawning.altItemDespawnRate.enabled ? level.paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(stack.getItem(), level.spigotConfig.itemDespawnRate) : level.spigotConfig.itemDespawnRate; // Paper } @Override diff --git a/patches/server/Implement-methods-to-convert-between-Component-and-B.patch b/patches/server/Implement-methods-to-convert-between-Component-and-B.patch index 370fd72278..89cca9543f 100644 --- a/patches/server/Implement-methods-to-convert-between-Component-and-B.patch +++ b/patches/server/Implement-methods-to-convert-between-Component-and-B.patch @@ -46,9 +46,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - com.destroystokyo.paper.PaperConfig.registerCommands(); + thread.start(); // Paper - start console thread after MinecraftServer.console & PaperConfig are initialized + io.papermc.paper.configuration.PaperConfigurations.registerCommands(this); com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now - io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // load mappings for stacktrace deobf and etc. + io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider // Paper end diff --git a/patches/server/Improved-Watchdog-Support.patch b/patches/server/Improved-Watchdog-Support.patch index 29f5fecce6..53c628ebbb 100644 --- a/patches/server/Improved-Watchdog-Support.patch +++ b/patches/server/Improved-Watchdog-Support.patch @@ -84,7 +84,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Spigot start public static final int TPS = 20; @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop entry : commands.entrySet()) { - MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Paper", entry.getValue()); diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java @@ -85,7 +69,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 CraftScoreboard scoreboard = new CraftScoreboard(new ServerScoreboard(this.server)); - this.scoreboards.add(scoreboard); + // Paper start -+ if (com.destroystokyo.paper.PaperConfig.trackPluginScoreboards) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().scoreboards.trackPluginScoreboards) { + scoreboard.registeredGlobally = true; + scoreboards.add(scoreboard); + } diff --git a/patches/server/Limit-item-frame-cursors-on-maps.patch b/patches/server/Limit-item-frame-cursors-on-maps.patch index 998b423b14..7e0e567790 100644 --- a/patches/server/Limit-item-frame-cursors-on-maps.patch +++ b/patches/server/Limit-item-frame-cursors-on-maps.patch @@ -4,20 +4,6 @@ Date: Wed, 26 May 2021 15:09:33 -0700 Subject: [PATCH] Limit item frame cursors on maps -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void allowUsingSignsInsideSpawnProtection() { - allowUsingSignsInsideSpawnProtection = getBoolean("allow-using-signs-inside-spawn-protection", allowUsingSignsInsideSpawnProtection); - } -+ -+ public int mapItemFrameCursorLimit = 128; -+ private void mapItemFrameCursorLimit() { -+ mapItemFrameCursorLimit = getInt("map-item-frame-cursor-limit", mapItemFrameCursorLimit); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java @@ -27,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 MapFrame worldmapframe1 = new MapFrame(blockposition, entityitemframe.getDirection().get2DDataValue() * 90, entityitemframe.getId()); + // Paper start -+ if (this.decorations.size() < player.level.paperConfig.mapItemFrameCursorLimit) { ++ if (this.decorations.size() < player.level.paperConfig().maps.itemFrameCursorLimit) { this.addDecoration(MapDecoration.Type.FRAME, player.level, "frame-" + entityitemframe.getId(), (double) blockposition.getX(), (double) blockposition.getZ(), (double) (entityitemframe.getDirection().get2DDataValue() * 90), (Component) null); this.frameMarkers.put(worldmapframe1.getId(), worldmapframe1); + } diff --git a/patches/server/Limit-recipe-packets.patch b/patches/server/Limit-recipe-packets.patch index 6c7d31abce..7258760e82 100644 --- a/patches/server/Limit-recipe-packets.patch +++ b/patches/server/Limit-recipe-packets.patch @@ -4,24 +4,6 @@ Date: Sat, 12 Dec 2020 23:45:28 +0000 Subject: [PATCH] Limit recipe packets -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - tabSpamLimit = getInt("settings.spam-limiter.tab-spam-limit", tabSpamLimit); - } - -+ public static int autoRecipeIncrement = 1; -+ public static int autoRecipeLimit = 20; -+ private static void autoRecipieLimiters() { -+ autoRecipeIncrement = getInt("settings.spam-limiter.recipe-spam-increment", autoRecipeIncrement); -+ autoRecipeLimit = getInt("settings.spam-limiter.recipe-spam-limit", autoRecipeLimit); -+ } -+ - public static boolean velocitySupport; - public static boolean velocityOnlineMode; - public static byte[] velocitySecretKey; diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -48,7 +30,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { + // Paper start + if (!org.bukkit.Bukkit.isPrimaryThread()) { -+ if (recipeSpamPackets.addAndGet(com.destroystokyo.paper.PaperConfig.autoRecipeIncrement) > com.destroystokyo.paper.PaperConfig.autoRecipeLimit) { ++ if (recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) { + server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]))); // Paper + return; + } diff --git a/patches/server/Load-Chunks-for-Login-Asynchronously.patch b/patches/server/Load-Chunks-for-Login-Asynchronously.patch index ed0d031034..4f87527b42 100644 --- a/patches/server/Load-Chunks-for-Login-Asynchronously.patch +++ b/patches/server/Load-Chunks-for-Login-Asynchronously.patch @@ -209,7 +209,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class PlayerList { } - PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName()))); + PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName()))); - this.cserver.getPluginManager().callEvent(playerQuitEvent); + if (entityplayer.didPlayerJoinEvent) this.cserver.getPluginManager().callEvent(playerQuitEvent); // Paper - if we disconnected before join ever fired, don't fire quit entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); diff --git a/patches/server/LootTable-API-Replenishable-Lootables-Feature.patch b/patches/server/LootTable-API-Replenishable-Lootables-Feature.patch index f97664d581..7016c023c1 100644 --- a/patches/server/LootTable-API-Replenishable-Lootables-Feature.patch +++ b/patches/server/LootTable-API-Replenishable-Lootables-Feature.patch @@ -10,37 +10,6 @@ can automatically replenish after a given time. This feature is good for long term worlds so that newer players do not suffer with "Every chest has been looted" -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax); - log("Frosted Ice: " + (this.frostedIceEnabled ? "enabled" : "disabled") + " / delay: min=" + this.frostedIceDelayMin + ", max=" + this.frostedIceDelayMax); - } -+ -+ public boolean autoReplenishLootables; -+ public boolean restrictPlayerReloot; -+ public boolean changeLootTableSeedOnFill; -+ public int maxLootableRefills; -+ public int lootableRegenMin; -+ public int lootableRegenMax; -+ private void enhancedLootables() { -+ autoReplenishLootables = getBoolean("lootables.auto-replenish", false); -+ restrictPlayerReloot = getBoolean("lootables.restrict-player-reloot", true); -+ changeLootTableSeedOnFill = getBoolean("lootables.reset-seed-on-fill", true); -+ maxLootableRefills = getInt("lootables.max-refills", -1); -+ lootableRegenMin = PaperConfig.getSeconds(getString("lootables.refresh-min", "12h")); -+ lootableRegenMax = PaperConfig.getSeconds(getString("lootables.refresh-max", "2d")); -+ if (autoReplenishLootables) { -+ log("Lootables: Replenishing every " + -+ PaperConfig.timeSummary(lootableRegenMin) + " to " + -+ PaperConfig.timeSummary(lootableRegenMax) + -+ (restrictPlayerReloot ? " (restricting reloot)" : "") -+ ); -+ } -+ } - } diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -208,7 +177,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Override + default boolean isRefillEnabled() { -+ return getNMSWorld().paperConfig.autoReplenishLootables; ++ return getNMSWorld().paperConfig().lootables.autoReplenish; + } + + @Override @@ -267,7 +236,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package com.destroystokyo.paper.loottable; + -+import com.destroystokyo.paper.PaperWorldConfig; ++import io.papermc.paper.configuration.WorldConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.loot.LootTable; +import javax.annotation.Nullable; @@ -315,7 +284,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + // ALWAYS process the first fill or if the feature is disabled -+ if (this.lastFill == -1 || !this.lootable.getNMSWorld().paperConfig.autoReplenishLootables) { ++ if (this.lastFill == -1 || !this.lootable.getNMSWorld().paperConfig().lootables.autoReplenish) { + return true; + } + @@ -329,10 +298,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return false; + } + -+ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig; ++ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig(); + + // Check if max refills has been hit -+ if (paperConfig.maxLootableRefills != -1 && this.numRefills >= paperConfig.maxLootableRefills) { ++ if (paperConfig.lootables.maxRefills != -1 && this.numRefills >= paperConfig.lootables.maxRefills) { + return false; + } + @@ -344,20 +313,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + final Player bukkitPlayer = (Player) player.getBukkitEntity(); + LootableInventoryReplenishEvent event = new LootableInventoryReplenishEvent(bukkitPlayer, lootable.getAPILootableInventory()); -+ if (paperConfig.restrictPlayerReloot && hasPlayerLooted(player.getUUID())) { ++ if (paperConfig.lootables.restrictPlayerReloot && hasPlayerLooted(player.getUUID())) { + event.setCancelled(true); + } + return event.callEvent(); + } + public void processRefill(@Nullable net.minecraft.world.entity.player.Player player) { + this.lastFill = System.currentTimeMillis(); -+ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig; -+ if (paperConfig.autoReplenishLootables) { -+ int min = paperConfig.lootableRegenMin; -+ int max = paperConfig.lootableRegenMax; -+ this.nextRefill = this.lastFill + (min + RANDOM.nextInt(max - min + 1)) * 1000L; ++ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig(); ++ if (paperConfig.lootables.autoReplenish) { ++ long min = paperConfig.lootables.refreshMin.seconds(); ++ long max = paperConfig.lootables.refreshMax.seconds(); ++ this.nextRefill = this.lastFill + (min + RANDOM.nextLong(max - min + 1)) * 1000L; + this.numRefills++; -+ if (paperConfig.changeLootTableSeedOnFill) { ++ if (paperConfig.lootables.resetSeedOnFill) { + this.lootable.setSeed(0); + } + if (player != null) { // This means that numRefills can be incremented without a player being in the lootedPlayers list - Seems to be EntityMinecartChest specific diff --git a/patches/server/MC-145656-Fix-Follow-Range-Initial-Target.patch b/patches/server/MC-145656-Fix-Follow-Range-Initial-Target.patch index b5f9c448d5..8014be04e6 100644 --- a/patches/server/MC-145656-Fix-Follow-Range-Initial-Target.patch +++ b/patches/server/MC-145656-Fix-Follow-Range-Initial-Target.patch @@ -4,21 +4,6 @@ Date: Wed, 18 Dec 2019 22:21:35 -0600 Subject: [PATCH] MC-145656 Fix Follow Range Initial Target -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void generatorSettings() { - generateFlatBedrock = getBoolean("generator-settings.flat-bedrock", this.generateFlatBedrock); - } -+ -+ public boolean entitiesTargetWithFollowRange = false; -+ private void entitiesTargetWithFollowRange() { -+ entitiesTargetWithFollowRange = getBoolean("entities-target-with-follow-range", entitiesTargetWithFollowRange); -+ } - } - diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java @@ -27,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.randomInterval = reducedTickDelay(reciprocalChance); this.setFlags(EnumSet.of(Goal.Flag.TARGET)); this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(targetPredicate); -+ if (mob.level.paperConfig.entitiesTargetWithFollowRange) this.targetConditions.useFollowRange(); // Paper ++ if (mob.level.paperConfig().entities.entitiesTargetWithFollowRange) this.targetConditions.useFollowRange(); // Paper } @Override diff --git a/patches/server/MC-Utils.patch b/patches/server/MC-Utils.patch index 635c1534d2..d3300864e9 100644 --- a/patches/server/MC-Utils.patch +++ b/patches/server/MC-Utils.patch @@ -5020,9 +5020,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { @@ -5900,6 +5900,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable @Override public ChunkAccess getChunk(int x, int z, ChunkStatus leastStatus, boolean create) { +@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { + } + } + ++ // Paper start ++ public boolean isPositionTicking(Entity entity) { ++ return this.isPositionTicking(ChunkPos.asLong(net.minecraft.util.Mth.floor(entity.getX()) >> 4, net.minecraft.util.Mth.floor(entity.getZ()) >> 4)); ++ } ++ // Paper end ++ + public boolean isPositionTicking(long pos) { + ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); + diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java diff --git a/patches/server/Make-EntityUnleashEvent-cancellable.patch b/patches/server/Make-EntityUnleashEvent-cancellable.patch index ed5ee63d37..8e11c44bf1 100644 --- a/patches/server/Make-EntityUnleashEvent-cancellable.patch +++ b/patches/server/Make-EntityUnleashEvent-cancellable.patch @@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/entity/PathfinderMob.java +++ b/src/main/java/net/minecraft/world/entity/PathfinderMob.java @@ -0,0 +0,0 @@ public abstract class PathfinderMob extends Mob { - if (f > entity.level.paperConfig.maxLeashDistance) { // Paper + if (f > entity.level.paperConfig().misc.maxLeashDistance) { // Paper // Paper start - drop leash variable EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE, true); - this.level.getCraftServer().getPluginManager().callEvent(event); // CraftBukkit @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end } @@ -0,0 +0,0 @@ public abstract class PathfinderMob extends Mob { - if (f > entity.level.paperConfig.maxLeashDistance) { // Paper + if (f > entity.level.paperConfig().misc.maxLeashDistance) { // Paper // Paper start - drop leash variable EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE, true); - this.level.getCraftServer().getPluginManager().callEvent(event); // CraftBukkit diff --git a/patches/server/Make-item-validations-configurable.patch b/patches/server/Make-item-validations-configurable.patch index ea9b4d0284..ba1ebd9762 100644 --- a/patches/server/Make-item-validations-configurable.patch +++ b/patches/server/Make-item-validations-configurable.patch @@ -4,30 +4,6 @@ Date: Fri, 4 Jun 2021 12:12:35 -0700 Subject: [PATCH] Make item validations configurable -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - config.set("settings.unsupported-settings.allow-headless-pistons-readme", "This setting controls if players should be able to create headless pistons."); - allowHeadlessPistons = getBoolean("settings.unsupported-settings.allow-headless-pistons", false); - } -+ -+ public static int itemValidationDisplayNameLength = 8192; -+ public static int itemValidationLocNameLength = 8192; -+ public static int itemValidationLoreLineLength = 8192; -+ public static int itemValidationBookTitleLength = 8192; -+ public static int itemValidationBookAuthorLength = 8192; -+ public static int itemValidationBookPageLength = 16384; -+ private static void itemValidationSettings() { -+ itemValidationDisplayNameLength = getInt("settings.item-validation.display-name", itemValidationDisplayNameLength); -+ itemValidationLocNameLength = getInt("settings.item-validation.loc-name", itemValidationLocNameLength); -+ itemValidationLoreLineLength = getInt("settings.item-validation.lore-line", itemValidationLoreLineLength); -+ itemValidationBookTitleLength = getInt("settings.item-validation.book.title", itemValidationBookTitleLength); -+ itemValidationBookAuthorLength = getInt("settings.item-validation.book.author", itemValidationBookAuthorLength); -+ itemValidationBookPageLength = getInt("settings.item-validation.book.page", itemValidationBookPageLength); -+ } - } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java @@ -37,12 +13,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (tag.contains(BOOK_TITLE.NBT)) { - this.title = limit( tag.getString(BOOK_TITLE.NBT), 8192 ); // Spigot -+ this.title = limit( tag.getString(BOOK_TITLE.NBT), com.destroystokyo.paper.PaperConfig.itemValidationBookTitleLength); // Spigot // Paper - make configurable ++ this.title = limit( tag.getString(BOOK_TITLE.NBT), io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.book.title); // Spigot // Paper - make configurable } if (tag.contains(BOOK_AUTHOR.NBT)) { - this.author = limit( tag.getString(BOOK_AUTHOR.NBT), 8192 ); // Spigot -+ this.author = limit( tag.getString(BOOK_AUTHOR.NBT), com.destroystokyo.paper.PaperConfig.itemValidationBookAuthorLength ); // Spigot // Paper - make configurable ++ this.author = limit( tag.getString(BOOK_AUTHOR.NBT), io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.book.author ); // Spigot // Paper - make configurable } if (tag.contains(RESOLVED.NBT)) { @@ -51,7 +27,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 page = this.validatePage(page); } - this.pages.add( limit( page, 16384 ) ); // Spigot -+ this.pages.add( limit( page, com.destroystokyo.paper.PaperConfig.itemValidationBookPageLength ) ); // Spigot // Paper - make configurable ++ this.pages.add( limit( page, io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.book.page ) ); // Spigot // Paper - make configurable } } } @@ -64,12 +40,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (display.contains(NAME.NBT)) { - this.displayName = limit( display.getString(NAME.NBT), 8192 ); // Spigot -+ this.displayName = limit( display.getString(NAME.NBT), com.destroystokyo.paper.PaperConfig.itemValidationDisplayNameLength ); // Spigot // Paper - make configurable ++ this.displayName = limit( display.getString(NAME.NBT), io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.displayName ); // Spigot // Paper - make configurable } if (display.contains(LOCNAME.NBT)) { - this.locName = limit( display.getString(LOCNAME.NBT), 8192 ); // Spigot -+ this.locName = limit( display.getString(LOCNAME.NBT), com.destroystokyo.paper.PaperConfig.itemValidationLocNameLength ); // Spigot // Paper - make configurable ++ this.locName = limit( display.getString(LOCNAME.NBT), io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.locName ); // Spigot // Paper - make configurable } if (display.contains(LORE.NBT)) { @@ -77,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.lore = new ArrayList(list.size()); for (int index = 0; index < list.size(); index++) { - String line = limit( list.getString(index), 8192 ); // Spigot -+ String line = limit( list.getString(index), com.destroystokyo.paper.PaperConfig.itemValidationLoreLineLength ); // Spigot // Paper - make configurable ++ String line = limit( list.getString(index), io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.loreLine ); // Spigot // Paper - make configurable this.lore.add(line); } } diff --git a/patches/server/Make-shield-blocking-delay-configurable.patch b/patches/server/Make-shield-blocking-delay-configurable.patch index 8e28491bb0..ca6ee08753 100644 --- a/patches/server/Make-shield-blocking-delay-configurable.patch +++ b/patches/server/Make-shield-blocking-delay-configurable.patch @@ -4,20 +4,6 @@ Date: Sat, 16 Jun 2018 01:18:16 -0500 Subject: [PATCH] Make shield blocking delay configurable -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - disableEnderpearlExploit = getBoolean("game-mechanics.disable-unloaded-chunk-enderpearl-exploit", disableEnderpearlExploit); - log("Disable Unloaded Chunk Enderpearl Exploit: " + (disableEnderpearlExploit ? "enabled" : "disabled")); - } -+ -+ public int shieldBlockingDelay = 5; -+ private void shieldBlockingDelay() { -+ shieldBlockingDelay = getInt("game-mechanics.shield-blocking-delay", 5); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -34,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // Paper start -+ public int shieldBlockingDelay = level.paperConfig.shieldBlockingDelay; ++ public int shieldBlockingDelay = level.paperConfig().misc.shieldBlockingDelay; + + public int getShieldBlockingDelay() { + return shieldBlockingDelay; diff --git a/patches/server/Make-the-default-permission-message-configurable.patch b/patches/server/Make-the-default-permission-message-configurable.patch index d7417a11e9..61a1e43448 100644 --- a/patches/server/Make-the-default-permission-message-configurable.patch +++ b/patches/server/Make-the-default-permission-message-configurable.patch @@ -17,41 +17,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return false; } -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ import java.util.regex.Pattern; - import com.google.common.collect.Lists; - import net.minecraft.server.MinecraftServer; - import org.bukkit.Bukkit; -+import org.bukkit.ChatColor; - import org.bukkit.command.Command; - import org.bukkit.configuration.ConfigurationSection; - import org.bukkit.configuration.InvalidConfigurationException; -@@ -0,0 +0,0 @@ public class PaperConfig { - connectionThrottleKickMessage = getString("messages.kick.connection-throttle", connectionThrottleKickMessage); - } - -+ public static String noPermissionMessage = "&cI'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error."; -+ private static void noPermissionMessage() { -+ noPermissionMessage = ChatColor.translateAlternateColorCodes('&', getString("messages.no-permission", noPermissionMessage)); -+ } -+ - private static void savePlayerData() { - Object val = config.get("settings.save-player-data"); - if (val instanceof Boolean) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -0,0 +0,0 @@ public final class CraftServer implements Server { - return com.destroystokyo.paper.PaperConfig.suggestPlayersWhenNullTabCompletions; + return io.papermc.paper.configuration.GlobalConfiguration.get().commands.suggestPlayerNamesWhenNullTabCompletions; } + @Override + public String getPermissionMessage() { -+ return com.destroystokyo.paper.PaperConfig.noPermissionMessage; ++ return io.papermc.paper.configuration.GlobalConfiguration.get().messages.noPermission; + } + @Override diff --git a/patches/server/Make-water-animal-spawn-height-configurable.patch b/patches/server/Make-water-animal-spawn-height-configurable.patch index 4119dbd4ca..6319944084 100644 --- a/patches/server/Make-water-animal-spawn-height-configurable.patch +++ b/patches/server/Make-water-animal-spawn-height-configurable.patch @@ -4,35 +4,6 @@ Date: Sat, 18 Dec 2021 08:26:55 +0100 Subject: [PATCH] Make water animal spawn height configurable -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - mobSpawnerTickRate = getInt("mob-spawner-tick-rate", 1); - } - -+ public Integer waterAnimalMaxSpawnHeight; -+ private void waterAnimalMaxSpawnHeight() { -+ String v = getString("wateranimal-spawn-height.maximum", "default"); -+ try { -+ waterAnimalMaxSpawnHeight = Integer.parseInt(v); -+ } catch (NumberFormatException ignored) { -+ } -+ } -+ -+ public Integer waterAnimalMinSpawnHeight; -+ private void waterAnimalMinSpawnHeight() { -+ String v = getString("wateranimal-spawn-height.minimum", "default"); -+ try { -+ waterAnimalMinSpawnHeight = Integer.parseInt(v); -+ } catch (NumberFormatException ignored) { -+ } -+ } -+ - public int containerUpdateTickRate; - private void containerUpdateTickRate() { - containerUpdateTickRate = getInt("container-update-tick-rate", 1); diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java @@ -42,8 +13,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int i = world.getSeaLevel(); int j = i - 13; + // Paper start -+ i = world.getMinecraftWorld().paperConfig.waterAnimalMaxSpawnHeight != null ? world.getMinecraftWorld().paperConfig.waterAnimalMaxSpawnHeight : i; -+ j = world.getMinecraftWorld().paperConfig.waterAnimalMinSpawnHeight != null ? world.getMinecraftWorld().paperConfig.waterAnimalMinSpawnHeight : j; ++ i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i); ++ j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j); + // Paper end return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER); } diff --git a/patches/server/Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch b/patches/server/Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch index 058d0dbd43..50284e53a7 100644 --- a/patches/server/Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch +++ b/patches/server/Only-count-Natural-Spawned-mobs-towards-natural-spaw.patch @@ -16,26 +16,6 @@ worse than vanilla. This should fully solve all of the issues around it so that only natural influences natural spawns. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void preventMovingIntoUnloadedChunks() { - preventMovingIntoUnloadedChunks = getBoolean("prevent-moving-into-unloaded-chunks", false); - } -+ -+ public boolean countAllMobsForSpawning = false; -+ private void countAllMobsForSpawning() { -+ countAllMobsForSpawning = getBoolean("count-all-mobs-for-spawning", false); -+ if (countAllMobsForSpawning) { -+ log("Counting all mobs for spawning. Mob farms may reduce natural spawns elsewhere in world."); -+ } else { -+ log("Using improved mob spawn limits (Only Natural Spawns impact spawn limits for more natural spawns)"); -+ } -+ } - } -+ diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java @@ -45,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (enumcreaturetype != MobCategory.MISC) { + // Paper start - Only count natural spawns -+ if (!entity.level.paperConfig.countAllMobsForSpawning && ++ if (!entity.level.paperConfig().entities.spawning.countAllMobsForSpawning && + !(entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL || + entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) { + continue; diff --git a/patches/server/Optimise-WorldServer-notify.patch b/patches/server/Optimise-WorldServer-notify.patch index d02c2d06f4..76714eeb4b 100644 --- a/patches/server/Optimise-WorldServer-notify.patch +++ b/patches/server/Optimise-WorldServer-notify.patch @@ -180,7 +180,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ServerLevel.this.entityTickList.remove(entity); + ServerLevel.this.entityManager.removeNavigatorsFromData(entity); // Paper - optimise notify // Paper start - Reset pearls when they stop being ticked - if (paperConfig.disableEnderpearlExploit && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) { + if (paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) { pearl.cachedOwner = null; diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/Optimise-chunk-tick-iteration.patch b/patches/server/Optimise-chunk-tick-iteration.patch index ab0297f5a6..c7327f4d53 100644 --- a/patches/server/Optimise-chunk-tick-iteration.patch +++ b/patches/server/Optimise-chunk-tick-iteration.patch @@ -121,7 +121,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - Iterator iterator1 = list.iterator(); + // Paper start - optimise chunk tick iteration + Iterator iterator1; -+ if (this.level.paperConfig.perPlayerMobSpawns) { ++ if (this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { + iterator1 = this.entityTickingChunks.iterator(); + } else { + iterator1 = this.entityTickingChunks.unsafeIterator(); diff --git a/patches/server/Optimise-nearby-player-lookups.patch b/patches/server/Optimise-nearby-player-lookups.patch index 0a0f45b37a..efd7581d63 100644 --- a/patches/server/Optimise-nearby-player-lookups.patch +++ b/patches/server/Optimise-nearby-player-lookups.patch @@ -217,7 +217,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) { - Player entityhuman = this.level.findNearbyPlayer(this, -1.0D, EntitySelector.affectsSpawning); // Paper + // Paper start - optimise checkDespawn -+ Player entityhuman = this.level.findNearbyPlayer(this, level.paperConfig.hardDespawnDistances.getInt(this.getType().getCategory()) + 1, EntitySelector.affectsSpawning); // Paper ++ Player entityhuman = this.level.findNearbyPlayer(this, level.paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()).hard() + 1, EntitySelector.affectsSpawning); // Paper + if (entityhuman == null) { + entityhuman = ((ServerLevel)this.level).playersAffectingSpawning.isEmpty() ? null : ((ServerLevel)this.level).playersAffectingSpawning.get(0); + } diff --git a/patches/server/Optimise-random-block-ticking.patch b/patches/server/Optimise-random-block-ticking.patch index 31795e1abb..9c611727de 100644 --- a/patches/server/Optimise-random-block-ticking.patch +++ b/patches/server/Optimise-random-block-ticking.patch @@ -141,16 +141,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - BlockPos blockposition; + final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change - if (!this.paperConfig.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder + if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder - blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15)); + blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper if (this.isRainingAt(blockposition)) { DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition); - boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * paperConfig.skeleHorseSpawnChance && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper + boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { gameprofilerfiller.popPush("iceandsnow"); - if (!this.paperConfig.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow + if (!this.paperConfig().environment.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow - blockposition = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.getBlockRandomPos(j, 0, k, 15)); - BlockPos blockposition1 = blockposition.below(); + // Paper start - optimise chunk ticking diff --git a/patches/server/Optimize-Collision-to-not-load-chunks.patch b/patches/server/Optimize-Collision-to-not-load-chunks.patch index 42ec604393..2f6b252d65 100644 --- a/patches/server/Optimize-Collision-to-not-load-chunks.patch +++ b/patches/server/Optimize-Collision-to-not-load-chunks.patch @@ -76,7 +76,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + if (blockState == null) { -+ if (!(source instanceof net.minecraft.server.level.ServerPlayer) || source.level.paperConfig.preventMovingIntoUnloadedChunks) { ++ if (!(source instanceof net.minecraft.server.level.ServerPlayer) || source.level.paperConfig().chunks.preventMovingIntoUnloadedChunks) { + return Shapes.create(far ? source.getBoundingBox() : new AABB(new BlockPos(x, y, z))); + } + // Paper end diff --git a/patches/server/Optimize-Hoppers.patch b/patches/server/Optimize-Hoppers.patch index 14e92774c9..2cf8dde471 100644 --- a/patches/server/Optimize-Hoppers.patch +++ b/patches/server/Optimize-Hoppers.patch @@ -12,28 +12,6 @@ Subject: [PATCH] Optimize Hoppers * Don't check for Entities with Inventories if the block above us is also occluding (not just Inventoried) * Remove Streams from Item Suck In and restore restore 1.12 AABB checks which is simpler and no voxel allocations (was doing TWO Item Suck ins) -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void entitiesTargetWithFollowRange() { - entitiesTargetWithFollowRange = getBoolean("entities-target-with-follow-range", entitiesTargetWithFollowRange); - } -+ -+ public boolean cooldownHopperWhenFull = true; -+ public boolean disableHopperMoveEvents = false; -+ public boolean hoppersIgnoreOccludingBlocks = false; -+ private void hopperOptimizations() { -+ cooldownHopperWhenFull = getBoolean("hopper.cooldown-when-full", cooldownHopperWhenFull); -+ log("Cooldown Hoppers when Full: " + (cooldownHopperWhenFull ? "enabled" : "disabled")); -+ disableHopperMoveEvents = getBoolean("hopper.disable-move-event", disableHopperMoveEvents); -+ log("Hopper Move Item Events: " + (disableHopperMoveEvents ? "disabled" : "enabled")); -+ hoppersIgnoreOccludingBlocks = getBoolean("hopper.ignore-occluding-blocks", hoppersIgnoreOccludingBlocks); -+ log("Hopper Ignore Container Entities inside Occluding Blocks: " + (hoppersIgnoreOccludingBlocks ? "enabled" : "disabled")); -+ } - } - diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java @@ -42,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 while (iterator.hasNext()) { ServerLevel worldserver = (ServerLevel) iterator.next(); worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper -+ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper ++ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper this.profiler.push(() -> { return worldserver + " " + worldserver.dimension().location(); @@ -166,7 +144,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + origItemStack.setCount(origCount); + } + } -+ if (foundItem && level.paperConfig.cooldownHopperWhenFull) { // Inventory was full - cooldown ++ if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown + hopper.setCooldown(level.spigotConfig.hopperTransfer); + } + return false; @@ -205,7 +183,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + origItemStack.setCount(origCount); + -+ if (level.paperConfig.cooldownHopperWhenFull) { ++ if (level.paperConfig().hopper.cooldownWhenFull) { + cooldownHopper(ihopper); + } + @@ -450,7 +428,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - if (object == null) { -+ if (object == null && (!optimizeEntities || !world.paperConfig.hoppersIgnoreOccludingBlocks || !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding())) { // Paper ++ if (object == null && (!optimizeEntities || !world.paperConfig().hopper.ignoreOccludingBlocks || !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding())) { // Paper List list = world.getEntities((Entity) null, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR); if (!list.isEmpty()) { diff --git a/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch b/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch index 3fd3f2e17c..fc174734ca 100644 --- a/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch +++ b/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch @@ -91,7 +91,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.regionManagers.add(this.dataRegionManager); // Paper end - this.playerMobDistanceMap = this.level.paperConfig.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper + this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper + // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning + this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, + (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, diff --git a/patches/server/Optimize-explosions.patch b/patches/server/Optimize-explosions.patch index 395ba7eb16..37cdca7919 100644 --- a/patches/server/Optimize-explosions.patch +++ b/patches/server/Optimize-explosions.patch @@ -9,21 +9,6 @@ expensive when there are hundreds or more entities in range. This patch adds a per-tick cache that is used for storing and retrieving an entity's exposure during an explosion. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - disableEndCredits = getBoolean("game-mechanics.disable-end-credits", false); - log("End credits disabled: " + disableEndCredits); - } -+ -+ public boolean optimizeExplosions; -+ private void optimizeExplosions() { -+ optimizeExplosions = getBoolean("optimize-explosions", false); -+ log("Optimize explosions: " + optimizeExplosions); -+ } - } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java @@ -55,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // Paper start - Optimize explosions + private float getBlockDensity(Vec3 vec3d, Entity entity) { -+ if (!this.level.paperConfig.optimizeExplosions) { ++ if (!this.level.paperConfig().environment.optimizeExplosions) { + return getSeenPercent(vec3d, entity); + } + CacheKey key = new CacheKey(this, entity.getBoundingBox()); diff --git a/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch index 5f4f3be4b3..bf254fd6e7 100644 --- a/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch +++ b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch @@ -4,21 +4,6 @@ Date: Fri, 10 Nov 2017 23:03:12 -0500 Subject: [PATCH] Option for maximum exp value when merging orbs -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - phantomIgnoreCreative = getBoolean("phantoms-do-not-spawn-on-creative-players", phantomIgnoreCreative); - phantomOnlyAttackInsomniacs = getBoolean("phantoms-only-attack-insomniacs", phantomOnlyAttackInsomniacs); - } -+ -+ public int expMergeMaxValue; -+ private void expMergeMaxValue() { -+ expMergeMaxValue = getInt("experience-merge-max-value", -1); -+ log("Experience Merge Max Value: " + expMergeMaxValue); -+ } - } diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -28,8 +13,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 double radius = world.spigotConfig.expMerge; if (radius > 0) { + // Paper start - Maximum exp value when merging - Whole section has been tweaked, see comments for specifics -+ final int maxValue = world.paperConfig.expMergeMaxValue; -+ final boolean mergeUnconditionally = world.paperConfig.expMergeMaxValue <= 0; ++ final int maxValue = world.paperConfig().entities.behavior.experienceMergeMaxValue; ++ final boolean mergeUnconditionally = world.paperConfig().entities.behavior.experienceMergeMaxValue <= 0; + if (mergeUnconditionally || xp.value < maxValue) { // Paper - Skip iteration if unnecessary + List entities = world.getEntities(entity, entity.getBoundingBox().inflate(radius, radius, radius)); diff --git a/patches/server/Option-to-have-default-CustomSpawners-in-custom-worl.patch b/patches/server/Option-to-have-default-CustomSpawners-in-custom-worl.patch index ce6eb3bf3e..38855b27bf 100644 --- a/patches/server/Option-to-have-default-CustomSpawners-in-custom-worl.patch +++ b/patches/server/Option-to-have-default-CustomSpawners-in-custom-worl.patch @@ -9,20 +9,6 @@ phantoms, wandering traders, etc.). This adds an option to instead of just looking at the LevelStem key, look at the DimensionType key which is one level below that. Defaults to off to keep vanilla behavior. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void timeCommandAffectsAllWorlds() { - timeCommandAffectsAllWorlds = getBoolean("settings.time-command-affects-all-worlds", timeCommandAffectsAllWorlds); - } -+ -+ public static boolean useDimensionTypeForCustomSpawners; -+ private static void useDimensionTypeForCustomSpawners() { -+ useDimensionTypeForCustomSpawners = getBoolean("settings.use-dimension-type-for-custom-spawners", false); -+ } - } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java @@ -34,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - world = new ServerLevel(this, this.executor, worldSession, iworlddataserver, worldKey, worlddimension, worldloadlistener, flag, j, ImmutableList.of(), true, org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider); + // Paper start - option to use the dimension_type to check if spawners should be added. I imagine mojang will add some datapack-y way of managing this in the future. + final List spawners; -+ if (com.destroystokyo.paper.PaperConfig.useDimensionTypeForCustomSpawners && this.registryHolder.registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY).getResourceKey(worlddimension.typeHolder().value()).orElseThrow() == net.minecraft.world.level.dimension.BuiltinDimensionTypes.OVERWORLD) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.useDimensionTypeForCustomSpawners && this.registryHolder.registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY).getResourceKey(worlddimension.typeHolder().value()).orElseThrow() == net.minecraft.world.level.dimension.BuiltinDimensionTypes.OVERWORLD) { + spawners = list; + } else { + spawners = Collections.emptyList(); diff --git a/patches/server/Option-to-prevent-armor-stands-from-doing-entity-loo.patch b/patches/server/Option-to-prevent-armor-stands-from-doing-entity-loo.patch index b3eb434ee5..338c04f357 100644 --- a/patches/server/Option-to-prevent-armor-stands-from-doing-entity-loo.patch +++ b/patches/server/Option-to-prevent-armor-stands-from-doing-entity-loo.patch @@ -4,20 +4,6 @@ Date: Mon, 23 Jul 2018 12:57:39 +0200 Subject: [PATCH] Option to prevent armor stands from doing entity lookups -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void scanForLegacyEnderDragon() { - scanForLegacyEnderDragon = getBoolean("game-mechanics.scan-for-legacy-ender-dragon", true); - } -+ -+ public boolean armorStandEntityLookups = true; -+ private void armorStandEntityLookups() { -+ armorStandEntityLookups = getBoolean("armor-stands-do-collision-entity-lookups", true); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java @@ -26,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override protected void pushEntities() { -+ if (!level.paperConfig.armorStandEntityLookups) return; // Paper ++ if (!level.paperConfig().entities.armorStands.doCollisionEntityLookups) return; // Paper List list = this.level.getEntities((Entity) this, this.getBoundingBox(), ArmorStand.RIDABLE_MINECARTS); for (int i = 0; i < list.size(); ++i) { @@ -41,7 +27,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - Prevent armor stands from doing entity lookups + @Override + public boolean noCollision(@Nullable Entity entity, AABB box) { -+ if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level.paperConfig.armorStandEntityLookups) return false; ++ if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level.paperConfig().entities.armorStands.doCollisionEntityLookups) return false; + return LevelAccessor.super.noCollision(entity, box); + } + // Paper end diff --git a/patches/server/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch b/patches/server/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch index 1dec6f482b..882e35ba34 100644 --- a/patches/server/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch +++ b/patches/server/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch @@ -11,20 +11,6 @@ bukkit's concept of a display name would be preferable. There was a PR for this on CB at one point but I can't find it. We may need to do this ourselves at some point in the future. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - grassUpdateRate = Math.max(0, getInt("grass-spread-tick-rate", grassUpdateRate)); - log("Grass Spread Tick Rate: " + grassUpdateRate); - } -+ -+ public boolean useVanillaScoreboardColoring; -+ private void useVanillaScoreboardColoring() { -+ useVanillaScoreboardColoring = getBoolean("use-vanilla-world-scoreboard-name-coloring", false); -+ } - } diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java @@ -42,14 +28,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } private static String legacyDisplayName(final CraftPlayer player) { -+ if (((CraftWorld) player.getWorld()).getHandle().paperConfig.useVanillaScoreboardColoring) { ++ if (((org.bukkit.craftbukkit.CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) { + return LegacyComponentSerializer.legacySection().serialize(player.teamDisplayName()) + ChatColor.RESET; + } return player.getDisplayName(); } private static Component displayName(final CraftPlayer player) { -+ if (((CraftWorld) player.getWorld()).getHandle().paperConfig.useVanillaScoreboardColoring) { ++ if (((CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) { + return player.teamDisplayName(); + } return player.displayName(); diff --git a/patches/server/Optional-TNT-doesn-t-move-in-water.patch b/patches/server/Optional-TNT-doesn-t-move-in-water.patch index c5764db659..66ed47708b 100644 --- a/patches/server/Optional-TNT-doesn-t-move-in-water.patch +++ b/patches/server/Optional-TNT-doesn-t-move-in-water.patch @@ -4,25 +4,6 @@ Date: Sun, 22 May 2016 20:20:55 -0500 Subject: [PATCH] Optional TNT doesn't move in water -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - ); - } - } -+ -+ public boolean preventTntFromMovingInWater; -+ private void preventTntFromMovingInWater() { -+ if (PaperConfig.version < 13) { -+ boolean oldVal = getBoolean("enable-old-tnt-cannon-behaviors", false); -+ set("prevent-tnt-from-moving-in-water", oldVal); -+ } -+ preventTntFromMovingInWater = getBoolean("prevent-tnt-from-moving-in-water", false); -+ log("Prevent TNT from moving in water: " + preventTntFromMovingInWater); -+ } - } diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java @@ -45,7 +26,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // Paper start - Optional prevent TNT from moving in water -+ if (!this.isRemoved() && this.wasTouchingWater && this.level.paperConfig.preventTntFromMovingInWater) { ++ if (!this.isRemoved() && this.wasTouchingWater && this.level.paperConfig().fixes.preventTntFromMovingInWater) { + /* + * Author: Jedediah Smith + */ @@ -76,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - Optional prevent TNT from moving in water + @Override + public boolean isPushedByFluid() { -+ return !level.paperConfig.preventTntFromMovingInWater && super.isPushedByFluid(); ++ return !level.paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid(); + } + // Paper end } diff --git a/patches/server/Paper-Metrics.patch b/patches/server/Paper-Metrics.patch index fbf853967f..4d82a9f267 100644 --- a/patches/server/Paper-Metrics.patch +++ b/patches/server/Paper-Metrics.patch @@ -576,8 +576,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + } + -+ static class PaperMetrics { -+ static void startMetrics() { ++ public static class PaperMetrics { ++ public static void startMetrics() { + // Get the config file + File configFile = new File(new File((File) MinecraftServer.getServer().options.valueOf("plugins"), "bStats"), "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); @@ -689,22 +689,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } +} -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java +diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static boolean verbose; - private static boolean fatalError; - /*========================================================================*/ -+ private static boolean metricsStarted; +--- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java ++++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +@@ -0,0 +0,0 @@ + package io.papermc.paper.configuration; - public static void init(File configFile) { - CONFIG_FILE = configFile; -@@ -0,0 +0,0 @@ public class PaperConfig { - for (Map.Entry entry : commands.entrySet()) { - MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Paper", entry.getValue()); - } ++import com.destroystokyo.paper.Metrics; + import com.destroystokyo.paper.PaperCommand; + import com.google.common.collect.Table; + import com.mojang.logging.LogUtils; +@@ -0,0 +0,0 @@ public class PaperConfigurations extends Configurations COMMANDS = new HashMap<>(); ++ private static boolean metricsStarted = false; + static { + COMMANDS.put("paper", new PaperCommand("paper")); + } +@@ -0,0 +0,0 @@ public class PaperConfigurations extends Configurations { + server.server.getCommandMap().register(s, "Paper", command); + }); + + if (!metricsStarted) { + Metrics.PaperMetrics.startMetrics(); @@ -712,7 +719,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } } - static void readConfig(Class clazz, Object instance) { + @Deprecated diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/SpigotConfig.java @@ -732,4 +739,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ // Paper end } - static void readConfig(Class clazz, Object instance) + public static void readConfig(Class clazz, Object instance) // Paper - package-private -> public diff --git a/patches/server/Paper-command.patch b/patches/server/Paper-command.patch index 9cdf876520..2a87608140 100644 --- a/patches/server/Paper-command.patch +++ b/patches/server/Paper-command.patch @@ -83,7 +83,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (args.length == 2) + return getListMatchingLast(sender, args, "help", "list"); + if (args.length == 3) -+ return getListMatchingLast(sender, args, EntityType.getEntityNameList().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new)); ++ return getListMatchingLast(sender, args, Registry.ENTITY_TYPE.keySet().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new)); + break; + } + return Collections.emptyList(); @@ -188,7 +188,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + filter = args[2]; + } + final String cleanfilter = filter.replace("?", ".?").replace("*", ".*?"); -+ Set names = EntityType.getEntityNameList().stream() ++ Set names = Registry.ENTITY_TYPE.keySet().stream() + .filter(n -> n.toString().matches(cleanfilter)) + .collect(Collectors.toSet()); + @@ -289,13 +289,68 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + Command.broadcastCommandMessage(sender, text("Please note that this command is not supported and may cause issues.", RED)); + Command.broadcastCommandMessage(sender, text("If you encounter any issues please use the /stop command to restart your server.", RED)); + -+ MinecraftServer console = MinecraftServer.getServer(); -+ com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); -+ for (ServerLevel world : console.getAllLevels()) { -+ world.paperConfig.init(); -+ } -+ console.server.reloadCount++; ++ MinecraftServer server = ((CraftServer) sender.getServer()).getServer(); ++ server.paperConfigurations.reloadConfigs(server); ++ server.server.reloadCount++; + + Command.broadcastCommandMessage(sender, text("Paper config reload complete.", GREEN)); + } +} +diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java ++++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +@@ -0,0 +0,0 @@ + package io.papermc.paper.configuration; + ++import com.destroystokyo.paper.PaperCommand; + import com.google.common.collect.Table; + import com.mojang.logging.LogUtils; + import io.leangen.geantyref.TypeToken; +@@ -0,0 +0,0 @@ public class PaperConfigurations extends Configurations COMMANDS = new HashMap<>(); + static { ++ COMMANDS.put("paper", new PaperCommand("paper")); + } + + public static void registerCommands(final MinecraftServer server) { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -0,0 +0,0 @@ public final class CraftServer implements Server { + // Spigot end + + // Paper start ++ @SuppressWarnings({"rawtypes", "unchecked"}) ++ public static java.nio.file.Path dumpHeap(java.nio.file.Path dir, String name) { ++ try { ++ java.nio.file.Files.createDirectories(dir); ++ ++ javax.management.MBeanServer server = java.lang.management.ManagementFactory.getPlatformMBeanServer(); ++ java.nio.file.Path file; ++ ++ try { ++ Class clazz = Class.forName("openj9.lang.management.OpenJ9DiagnosticsMXBean"); ++ Object openj9Mbean = java.lang.management.ManagementFactory.newPlatformMXBeanProxy(server, "openj9.lang.management:type=OpenJ9Diagnostics", clazz); ++ java.lang.reflect.Method m = clazz.getMethod("triggerDumpToFile", String.class, String.class); ++ file = dir.resolve(name + ".phd"); ++ m.invoke(openj9Mbean, "heap", file.toString()); ++ } catch (ClassNotFoundException e) { ++ Class clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean"); ++ Object hotspotMBean = java.lang.management.ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", clazz); ++ java.lang.reflect.Method m = clazz.getMethod("dumpHeap", String.class, boolean.class); ++ file = dir.resolve(name + ".hprof"); ++ m.invoke(hotspotMBean, file.toString(), true); ++ } ++ ++ return file; ++ } catch (Throwable t) { ++ Bukkit.getLogger().log(Level.SEVERE, "Could not write heap", t); ++ return null; ++ } ++ } + private Iterable adventure$audiences; + @Override + public Iterable audiences() { diff --git a/patches/server/Paper-config-files.patch b/patches/server/Paper-config-files.patch index 8bbc52c951..b118340b43 100644 --- a/patches/server/Paper-config-files.patch +++ b/patches/server/Paper-config-files.patch @@ -1,133 +1,3026 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown <1254957+zachbr@users.noreply.github.com> -Date: Mon, 29 Feb 2016 21:02:09 -0600 +From: Jake Potrebic +Date: Wed, 8 Jun 2022 22:20:16 -0700 Subject: [PATCH] Paper config files -Loads each yml file for early init too so it can be used for early options -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java +diff --git a/build.gradle.kts b/build.gradle.kts +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -0,0 +0,0 @@ dependencies { + implementation("org.apache.logging.log4j:log4j-iostreams:2.17.1") // Paper + implementation("org.ow2.asm:asm:9.3") + implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation ++ implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files + implementation("commons-lang:commons-lang:2.6") + runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3") + runtimeOnly("mysql:mysql-connector-java:8.0.29") +diff --git a/src/main/java/io/papermc/paper/configuration/Configuration.java b/src/main/java/io/papermc/paper/configuration/Configuration.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 --- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java ++++ b/src/main/java/io/papermc/paper/configuration/Configuration.java @@ -0,0 +0,0 @@ -+package com.destroystokyo.paper; ++package io.papermc.paper.configuration; + -+import com.google.common.base.Throwables; ++public final class Configuration { ++ public static final String VERSION_FIELD = "_version"; ++ @Deprecated ++ public static final String LEGACY_CONFIG_VERSION_FIELD = "config-version"; ++ ++ @Deprecated ++ public static final int FINAL_LEGACY_VERSION = 27; ++ ++ private Configuration() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/ConfigurationLoaders.java b/src/main/java/io/papermc/paper/configuration/ConfigurationLoaders.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/ConfigurationLoaders.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration; ++ ++import java.nio.file.Path; ++import org.spongepowered.configurate.loader.HeaderMode; ++import org.spongepowered.configurate.util.MapFactories; ++import org.spongepowered.configurate.yaml.NodeStyle; ++import org.spongepowered.configurate.yaml.YamlConfigurationLoader; ++ ++public final class ConfigurationLoaders { ++ private ConfigurationLoaders() { ++ } ++ ++ public static YamlConfigurationLoader.Builder naturallySorted() { ++ return YamlConfigurationLoader.builder() ++ .indent(2) ++ .nodeStyle(NodeStyle.BLOCK) ++ .defaultOptions(options -> options.mapFactory(MapFactories.sortedNatural())); ++ } ++ ++ public static YamlConfigurationLoader naturallySortedWithoutHeader(final Path path) { ++ return naturallySorted() ++ .headerMode(HeaderMode.NONE) ++ .path(path) ++ .build(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/ConfigurationPart.java b/src/main/java/io/papermc/paper/configuration/ConfigurationPart.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/ConfigurationPart.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration; ++ ++abstract class ConfigurationPart { ++ ++ public static abstract class Post extends ConfigurationPart { ++ ++ public abstract void postProcess(); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/configuration/Configurations.java b/src/main/java/io/papermc/paper/configuration/Configurations.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/Configurations.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration; ++ ++import com.google.common.base.Suppliers; ++import io.papermc.paper.configuration.constraint.Constraint; ++import io.papermc.paper.configuration.constraint.Constraints; ++import net.minecraft.server.level.ServerLevel; ++import org.apache.commons.lang3.RandomStringUtils; ++import org.jetbrains.annotations.MustBeInvokedByOverriders; ++import org.spigotmc.SpigotConfig; ++import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.CommentedConfigurationNode; ++import org.spongepowered.configurate.ConfigurateException; ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.ConfigurationOptions; ++import org.spongepowered.configurate.objectmapping.ObjectMapper; ++import org.spongepowered.configurate.serialize.SerializationException; ++import org.spongepowered.configurate.util.CheckedFunction; ++import org.spongepowered.configurate.yaml.YamlConfigurationLoader; ++ ++import java.io.IOException; ++import java.lang.reflect.Type; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.util.Objects; ++import java.util.function.Supplier; ++import java.util.function.UnaryOperator; ++ ++public abstract class Configurations { ++ ++ public static final String WORLD_DEFAULTS = "__world_defaults__"; ++ private static final Supplier SPIGOT_WORLD_DEFAULTS = Suppliers.memoize(() -> new SpigotWorldConfig(RandomStringUtils.randomAlphabetic(255)) { ++ @Override // override to ensure "verbose" is false ++ public void init() { ++ SpigotConfig.readConfig(SpigotWorldConfig.class, this); ++ } ++ }); ++ protected final Path globalFolder; ++ protected final Class globalConfigClass; ++ protected final Class worldConfigClass; ++ protected final String globalConfigFileName; ++ protected final String defaultWorldConfigFileName; ++ protected final String worldConfigFileName; ++ ++ public Configurations( ++ final Path globalFolder, ++ final Class globalConfigType, ++ final Class worldConfigClass, ++ final String globalConfigFileName, ++ final String defaultWorldConfigFileName, ++ final String worldConfigFileName ++ ) { ++ this.globalFolder = globalFolder; ++ this.globalConfigClass = globalConfigType; ++ this.worldConfigClass = worldConfigClass; ++ this.globalConfigFileName = globalConfigFileName; ++ this.defaultWorldConfigFileName = defaultWorldConfigFileName; ++ this.worldConfigFileName = worldConfigFileName; ++ } ++ ++ protected ObjectMapper.Factory.Builder createObjectMapper() { ++ return ObjectMapper.factoryBuilder() ++ .addConstraint(Constraint.class, new Constraint.Factory()) ++ .addConstraint(Constraints.Min.class, Number.class, new Constraints.Min.Factory()); ++ } ++ ++ protected YamlConfigurationLoader.Builder createLoaderBuilder() { ++ return ConfigurationLoaders.naturallySorted(); ++ } ++ ++ protected abstract boolean isConfigType(final Type type); ++ ++ protected ObjectMapper.Factory.Builder createGlobalObjectMapperFactoryBuilder() { ++ return this.createObjectMapper(); ++ } ++ ++ @MustBeInvokedByOverriders ++ protected YamlConfigurationLoader.Builder createGlobalLoaderBuilder() { ++ return this.createLoaderBuilder(); ++ } ++ ++ static CheckedFunction creator(Class type, boolean refreshNode) { ++ return node -> { ++ 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() throws ConfigurateException { ++ return this.initializeGlobalConfiguration(creator(this.globalConfigClass, true)); ++ } ++ ++ protected G initializeGlobalConfiguration(final CheckedFunction creator) throws ConfigurateException { ++ final Path configFile = this.globalFolder.resolve(this.globalConfigFileName); ++ final YamlConfigurationLoader loader = this.createGlobalLoaderBuilder() ++ .defaultOptions(this.applyObjectMapperFactory(this.createGlobalObjectMapperFactoryBuilder().build())) ++ .path(configFile) ++ .build(); ++ final ConfigurationNode node; ++ if (Files.exists(configFile)) { ++ node = loader.load(); ++ } else { ++ node = CommentedConfigurationNode.root(loader.defaultOptions()); ++ } ++ this.applyGlobalConfigTransformations(node); ++ final G instance = creator.apply(node); ++ loader.save(node); ++ return instance; ++ } ++ ++ protected void applyGlobalConfigTransformations(final ConfigurationNode node) throws ConfigurateException { ++ } ++ ++ public void initializeWorldDefaultsConfiguration() throws ConfigurateException { ++ final YamlConfigurationLoader loader = this.createDefaultWorldLoader(false); ++ final ConfigurationNode node = loader.load(); ++ this.applyWorldConfigTransformations(WORLD_DEFAULTS, node); ++ final W instance = node.require(this.worldConfigClass); ++ node.set(this.worldConfigClass, instance); ++ loader.save(node); ++ } ++ ++ private YamlConfigurationLoader createDefaultWorldLoader(final boolean requireFile) { ++ final Path configFile = this.globalFolder.resolve(this.defaultWorldConfigFileName); ++ if (requireFile && !Files.exists(configFile)) { ++ throw new IllegalStateException("World defaults configuration file '" + configFile + "' doesn't exist"); ++ } ++ return this.createWorldConfigLoaderBuilder(WORLD_DEFAULTS, SPIGOT_WORLD_DEFAULTS.get()) ++ .defaultOptions(this.applyObjectMapperFactory(this.createWorldObjectMapperFactoryBuilder(WORLD_DEFAULTS, SPIGOT_WORLD_DEFAULTS.get()).build())) ++ .path(configFile) ++ .build(); ++ } ++ ++ protected ObjectMapper.Factory.Builder createWorldObjectMapperFactoryBuilder(final String levelName, final SpigotWorldConfig spigotConfig) { ++ return this.createObjectMapper(); ++ } ++ ++ @MustBeInvokedByOverriders ++ protected YamlConfigurationLoader.Builder createWorldConfigLoaderBuilder(final String levelName, final SpigotWorldConfig spigotConfig) { ++ return this.createLoaderBuilder(); ++ } ++ ++ // Make sure to run version transforms on the default world config first via #setupWorldDefaultsConfig ++ public W createWorldConfig(final Path dir, final String levelName, final SpigotWorldConfig spigotConfig) throws IOException { ++ return this.createWorldConfig(dir, levelName, spigotConfig, creator(this.worldConfigClass, false)); ++ } ++ ++ protected W createWorldConfig(final Path dir, final String levelName, final SpigotWorldConfig spigotConfig, final CheckedFunction creator) throws IOException { ++ final YamlConfigurationLoader defaultsLoader = this.createDefaultWorldLoader(true); ++ final ConfigurationNode defaultsNode = defaultsLoader.load(); ++ ++ boolean newFile = false; ++ final Path worldConfigFile = dir.resolve(this.worldConfigFileName); ++ if (Files.notExists(worldConfigFile)) { ++ Files.createDirectories(dir); ++ Files.createFile(worldConfigFile); // create empty file as template ++ newFile = true; ++ } ++ ++ final YamlConfigurationLoader worldLoader = this.createWorldConfigLoaderBuilder(levelName, spigotConfig) ++ .defaultOptions(this.applyObjectMapperFactory(this.createWorldObjectMapperFactoryBuilder(levelName, spigotConfig).build())) ++ .path(worldConfigFile) ++ .build(); ++ final ConfigurationNode worldNode = worldLoader.load(); ++ if (newFile) { ++ worldNode.node(Configuration.VERSION_FIELD).set(WorldConfiguration.CURRENT_VERSION); ++ } ++ this.applyWorldConfigTransformations(levelName, worldNode); ++ worldLoader.save(worldNode); // save before loading node NOTE: don't save the backing node after loading it, or you'll fill up the world-specific config ++ worldNode.mergeFrom(defaultsNode); ++ final W worldConfig = creator.apply(worldNode); ++ return worldConfig; ++ } ++ ++ protected void applyWorldConfigTransformations(final String world, final ConfigurationNode node) throws ConfigurateException { ++ } ++ ++ private UnaryOperator applyObjectMapperFactory(final ObjectMapper.Factory factory) { ++ return options -> options.serializers(builder -> builder ++ .register(this::isConfigType, factory.asTypeSerializer()) ++ .registerAnnotatedObjects(factory)); ++ } ++ ++ public Path getWorldConfigFile(ServerLevel level) { ++ return level.convertable.levelDirectory.path().resolve(this.worldConfigFileName); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration; ++ ++import co.aikar.timings.MinecraftTimings; ++import co.aikar.timings.TimingsManager; ++import com.destroystokyo.paper.io.chunk.ChunkTaskManager; ++import io.papermc.paper.configuration.constraint.Constraint; ++import io.papermc.paper.configuration.constraint.Constraints; ++import net.minecraft.network.protocol.Packet; ++import net.minecraft.network.protocol.game.ServerboundPlaceRecipePacket; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.objectmapping.ConfigSerializable; ++import org.spongepowered.configurate.objectmapping.meta.Comment; ++import org.spongepowered.configurate.objectmapping.meta.Required; ++import org.spongepowered.configurate.objectmapping.meta.Setting; ++ ++import java.util.List; ++import java.util.Map; ++import java.util.Objects; ++ ++@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic"}) ++public class GlobalConfiguration extends ConfigurationPart { ++ static final int CURRENT_VERSION = 28; ++ private static GlobalConfiguration instance; ++ public static GlobalConfiguration get() { ++ return instance; ++ } ++ static void set(GlobalConfiguration instance) { ++ GlobalConfiguration.instance = instance; ++ } ++ ++ @Setting(Configuration.VERSION_FIELD) ++ public int version = CURRENT_VERSION; ++ ++ public Messages messages; ++ ++ public class Messages extends ConfigurationPart { ++ public Kick kick; ++ ++ public class Kick extends ConfigurationPart { ++ public String authenticationServersDown = ""; // TODO empty is fallback to translatable msg ++ public String connectionThrottle = "Connection throttled! Please wait before reconnecting."; ++ public String flyingPlayer = "Flying is not enabled on this server"; ++ public String flyingVehicle = "Flying is not enabled on this server"; ++ } ++ ++ public String noPermission = "&cI'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error."; ++ public boolean useDisplayNameInQuitMessage = false; ++ } ++ ++ public Timings timings; ++ ++ public class Timings extends ConfigurationPart.Post { ++ public boolean enabled = true; ++ public boolean verbose = true; ++ public String url = "https://timings.aikar.co/"; ++ public boolean serverNamePrivacy = false; ++ public List hiddenConfigEntries = List.of( ++ "database", ++ "proxies.velocity.secret" ++ ); ++ public int historyInterval = 300; ++ public int historyLength = 3600; ++ public String serverName = "Unknown Server"; ++ ++ @Override ++ public void postProcess() { ++ MinecraftTimings.processConfig(this); ++ } ++ } ++ ++ public Proxies proxies; ++ ++ public class Proxies extends ConfigurationPart { ++ public BungeeCord bungeeCord; ++ ++ public class BungeeCord extends ConfigurationPart { ++ public boolean onlineMode = true; ++ } ++ ++ @Constraint(Constraints.Velocity.class) ++ public Velocity velocity; ++ ++ public class Velocity extends ConfigurationPart { ++ public boolean enabled = false; ++ public boolean onlineMode = false; ++ public String secret = ""; ++ } ++ public boolean proxyProtocol = false; ++ public boolean isProxyOnlineMode() { ++ return org.bukkit.Bukkit.getOnlineMode() || (org.spigotmc.SpigotConfig.bungee && this.bungeeCord.onlineMode) || (this.velocity.enabled && this.velocity.onlineMode); ++ } ++ } ++ ++ public Console console; ++ ++ public class Console extends ConfigurationPart { ++ public boolean enableBrigadierHighlighting = true; ++ public boolean enableBrigadierCompletions = true; ++ public boolean hasAllPermissions = false; ++ } ++ ++ public Watchdog watchdog; ++ ++ public class Watchdog extends ConfigurationPart { ++ public int earlyWarningEvery = 5000; ++ public int earlyWarningDelay = 10000; ++ } ++ ++ public SpamLimiter spamLimiter; ++ ++ public class SpamLimiter extends ConfigurationPart { ++ public int tabSpamIncrement = 1; ++ public int tabSpamLimit = 500; ++ public int recipeSpamIncrement = 1; ++ public int recipeSpamLimit = 20; ++ public int incomingPacketThreshold = 300; ++ } ++ ++ public ChunkLoading chunkLoading; ++ ++ public class ChunkLoading extends ConfigurationPart { ++ public int minLoadRadius = 2; ++ public int maxConcurrentSends = 2; ++ public boolean autoconfigSendDistance = true; ++ public double targetPlayerChunkSendRate = 100.0; ++ public double globalMaxChunkSendRate = -1.0; ++ public boolean enableFrustumPriority = false; ++ public double globalMaxChunkLoadRate = -1.0; ++ public double playerMaxConcurrentLoads = 20.0; ++ public double globalMaxConcurrentLoads = 500.0; ++ public double playerMaxChunkLoadRate = -1.0; ++ } ++ ++ public UnsupportedSettings unsupportedSettings; ++ ++ public class UnsupportedSettings extends ConfigurationPart { ++ @Comment("This setting controls if players should be able to break bedrock, end portals and other intended to be permanent blocks.") ++ public boolean allowPermanentBlockBreakExploits = false; ++ @Comment("This setting controls if player should be able to use TNT duplication, but this also allows duplicating carpet, rails and potentially other items") ++ public boolean allowPistonDuplication = false; ++ public boolean performUsernameValidation = true; ++ @Comment("This setting controls if players should be able to create headless pistons.") ++ public boolean allowHeadlessPistons = false; ++ } ++ ++ public Commands commands; ++ ++ public class Commands extends ConfigurationPart { ++ public boolean suggestPlayerNamesWhenNullTabCompletions = true; ++ public boolean fixTargetSelectorTagCompletion = true; ++ public boolean timeCommandAffectsAllWorlds = false; ++ } ++ ++ public Logging logging; ++ ++ public class Logging extends ConfigurationPart { ++ public boolean logPlayerIpAddresses = true; ++ public boolean deobfuscateStacktraces = true; ++ public boolean useRgbForNamedTextColors = true; ++ } ++ ++ public Scoreboards scoreboards; ++ ++ public class Scoreboards extends ConfigurationPart { ++ public boolean trackPluginScoreboards = false; ++ public boolean saveEmptyScoreboardTeams = false; ++ } ++ ++ public AsyncChunks asyncChunks; ++ ++ public class AsyncChunks extends ConfigurationPart.Post { ++ public int threads = -1; ++ public transient boolean asyncChunks = false; ++ ++ @Override ++ public void postProcess() { ++ ChunkTaskManager.processConfiguration(this); ++ } ++ } ++ ++ public ItemValidation itemValidation; ++ ++ public class ItemValidation extends ConfigurationPart { ++ public int displayName = 8192; ++ public int locName = 8192; // TODO not used anymore, can we remove? ++ public int loreLine = 8192; ++ public Book book; ++ ++ public class Book extends ConfigurationPart { ++ public int title = 8192; ++ public int author = 8192; ++ public int page = 16384; ++ } ++ ++ public BookSize bookSize; ++ ++ public class BookSize extends ConfigurationPart { ++ public int pageMax = 2560; // TODO this appears to be a duplicate setting with one above ++ public double totalMultiplier = 0.98D; // TODO this should probably be merged into the above inner class ++ } ++ public boolean resolveSelectorsInBooks = false; ++ } ++ ++ public PacketLimiter packetLimiter; ++ ++ public class PacketLimiter extends ConfigurationPart { ++ public String kickMessage = "&cSent too many packets"; // todo: minimessage ++ public PacketLimit allPackets = new PacketLimit(7.0, 500.0, PacketLimit.ViolateAction.KICK); ++ public Map>, PacketLimit> overrides = Map.of(ServerboundPlaceRecipePacket.class, new PacketLimit(4.0, 5.0, PacketLimit.ViolateAction.DROP)); ++ ++ @ConfigSerializable ++ public record PacketLimit(@Constraint(Constraints.Positive.class) @Required double interval, @Constraint(Constraints.Positive.class) @Required double maxPacketRate, ViolateAction action) { ++ public PacketLimit(final double interval, final double maxPacketRate, final @Nullable ViolateAction action) { ++ this.interval = interval; ++ this.maxPacketRate = maxPacketRate; ++ this.action = Objects.requireNonNullElse(action, ViolateAction.KICK); ++ } ++ ++ public boolean isEnabled() { ++ return this.interval > 0.0 && this.maxPacketRate > 0.0; ++ } ++ ++ public enum ViolateAction { ++ KICK, ++ DROP; ++ } ++ } ++ } ++ ++ public Collisions collisions; ++ ++ public class Collisions extends ConfigurationPart { ++ public boolean enablePlayerCollisions = true; ++ public boolean sendFullPosForHardCollidingEntities = true; ++ } ++ ++ public PlayerAutoSave playerAutoSave; ++ ++ ++ public class PlayerAutoSave extends ConfigurationPart { ++ public int rate = -1; ++ private int maxPerTick = -1; ++ public int maxPerTick() { ++ if (this.maxPerTick < 0) { ++ return (this.rate == 1 || this.rate > 100) ? 10 : 20; ++ } ++ return this.maxPerTick; ++ } ++ } ++ ++ public Misc misc; ++ ++ public class Misc extends ConfigurationPart { ++ public int maxJoinsPerTick = 3; ++ public boolean fixEntityPositionDesync = true; ++ public boolean loadPermissionsYmlBeforePlugins = true; ++ @Constraints.Min(4) ++ public int regionFileCacheSize = 256; ++ @Comment("See https://luckformula.emc.gs") ++ public boolean useAlternativeLuckFormula = false; ++ public boolean lagCompensateBlockBreaking = true; ++ public boolean useDimensionTypeForCustomSpawners = false; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/InnerClassFieldDiscoverer.java b/src/main/java/io/papermc/paper/configuration/InnerClassFieldDiscoverer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/InnerClassFieldDiscoverer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration; ++ ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.objectmapping.FieldDiscoverer; ++import org.spongepowered.configurate.serialize.SerializationException; ++import org.spongepowered.configurate.util.CheckedSupplier; ++ ++import java.lang.reflect.AnnotatedType; ++import java.lang.reflect.Constructor; ++import java.lang.reflect.Field; ++import java.lang.reflect.Modifier; ++import java.util.Collections; ++import java.util.HashMap; ++import java.util.Map; ++ ++import static io.leangen.geantyref.GenericTypeReflector.erase; ++ ++final class InnerClassFieldDiscoverer implements FieldDiscoverer> { ++ ++ private final Map, Object> instanceMap = new HashMap<>(); ++ private final Map, Object> overrides; ++ @SuppressWarnings("unchecked") ++ private final FieldDiscoverer> delegate = (FieldDiscoverer>) FieldDiscoverer.object(target -> { ++ final Class type = erase(target.getType()); ++ if (this.overrides().containsKey(type)) { ++ this.instanceMap.put(type, this.overrides().get(type)); ++ return () -> this.overrides().get(type); ++ } ++ if (ConfigurationPart.class.isAssignableFrom(type) && !this.instanceMap.containsKey(type)) { ++ try { ++ final Constructor constructor; ++ final CheckedSupplier instanceSupplier; ++ if (type.getEnclosingClass() != null && !Modifier.isStatic(type.getModifiers())) { ++ final @Nullable Object instance = this.instanceMap.get(type.getEnclosingClass()); ++ if (instance == null) { ++ throw new SerializationException("Cannot create a new instance of an inner class " + type.getName() + " without an instance of its enclosing class " + type.getEnclosingClass().getName()); ++ } ++ constructor = type.getDeclaredConstructor(type.getEnclosingClass()); ++ instanceSupplier = () -> constructor.newInstance(instance); ++ } else { ++ constructor = type.getDeclaredConstructor(); ++ instanceSupplier = constructor::newInstance; ++ } ++ constructor.setAccessible(true); ++ final Object instance = instanceSupplier.get(); ++ this.instanceMap.put(type, instance); ++ return () -> instance; ++ } catch (ReflectiveOperationException e) { ++ throw new SerializationException(ConfigurationPart.class, target + " must be a valid ConfigurationPart", e); ++ } ++ } else { ++ throw new SerializationException(target + " must be a valid ConfigurationPart"); ++ } ++ }, "Object must be a unique ConfigurationPart"); ++ ++ InnerClassFieldDiscoverer(Map, Object> overrides) { ++ this.overrides = overrides; ++ } ++ ++ @Override ++ public @Nullable InstanceFactory> discover(AnnotatedType target, FieldCollector, V> collector) throws SerializationException { ++ final Class clazz = erase(target.getType()); ++ if (ConfigurationPart.class.isAssignableFrom(clazz)) { ++ final FieldDiscoverer.@Nullable InstanceFactory> instanceFactoryDelegate = this.delegate.discover(target, (name, type, annotations, deserializer, serializer) -> { ++ if (!erase(type.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes ++ collector.accept(name, type, annotations, deserializer, serializer); ++ } ++ }); ++ if (instanceFactoryDelegate instanceof FieldDiscoverer.MutableInstanceFactory> mutableInstanceFactoryDelegate) { ++ return new MutableInstanceFactory<>() { ++ @Override ++ public Map begin() { ++ return mutableInstanceFactoryDelegate.begin(); ++ } ++ ++ @Override ++ public void complete(Object instance, Map intermediate) throws SerializationException { ++ mutableInstanceFactoryDelegate.complete(instance, intermediate); ++ } ++ ++ @Override ++ public Object complete(Map intermediate) throws SerializationException { ++ Object value = mutableInstanceFactoryDelegate.complete(intermediate); ++ if (value instanceof ConfigurationPart.Post post) { ++ post.postProcess(); ++ } ++ return value; ++ } ++ ++ @Override ++ public boolean canCreateInstances() { ++ return mutableInstanceFactoryDelegate.canCreateInstances(); ++ } ++ }; ++ } ++ } ++ return null; ++ } ++ ++ private Map, Object> overrides() { ++ return this.overrides; ++ } ++ ++ static FieldDiscoverer worldConfig(SpigotWorldConfig spigotConfig) { ++ return new InnerClassFieldDiscoverer(Map.of(WorldConfiguration.class, new WorldConfiguration(spigotConfig))); ++ } ++ ++ static FieldDiscoverer globalConfig() { ++ return new InnerClassFieldDiscoverer(Collections.emptyMap()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/NestedSetting.java b/src/main/java/io/papermc/paper/configuration/NestedSetting.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/NestedSetting.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration; ++ ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.objectmapping.meta.NodeResolver; ++ ++import java.lang.annotation.Documented; ++import java.lang.annotation.ElementType; ++import java.lang.annotation.Retention; ++import java.lang.annotation.RetentionPolicy; ++import java.lang.annotation.Target; ++import java.lang.reflect.AnnotatedElement; ++ ++@Documented ++@Retention(RetentionPolicy.RUNTIME) ++@Target(ElementType.FIELD) ++public @interface NestedSetting { ++ ++ String[] value(); ++ ++ class Factory implements NodeResolver.Factory { ++ @Override ++ public @Nullable NodeResolver make(String name, AnnotatedElement element) { ++ if (element.isAnnotationPresent(NestedSetting.class)) { ++ Object[] path = element.getAnnotation(NestedSetting.class).value(); ++ if (path.length > 0) { ++ return node -> node.node(path); ++ } ++ } ++ return null; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration; ++ ++import com.google.common.collect.Table; ++import com.mojang.logging.LogUtils; ++import io.leangen.geantyref.TypeToken; ++import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization; ++import io.papermc.paper.configuration.serializer.FastutilMapSerializer; ++import io.papermc.paper.configuration.serializer.PacketClassSerializer; ++import io.papermc.paper.configuration.serializer.StringRepresentableSerializer; ++import io.papermc.paper.configuration.serializer.TableSerializer; ++import io.papermc.paper.configuration.serializer.collections.MapSerializer; ++import io.papermc.paper.configuration.serializer.registry.RegistryHolderSerializer; ++import io.papermc.paper.configuration.serializer.registry.RegistryValueSerializer; ++import io.papermc.paper.configuration.transformation.global.LegacyPaperConfig; ++import io.papermc.paper.configuration.transformation.world.LegacyPaperWorldConfig; ++import io.papermc.paper.configuration.type.BooleanOrDefault; ++import io.papermc.paper.configuration.type.DoubleOrDefault; ++import io.papermc.paper.configuration.type.Duration; ++import io.papermc.paper.configuration.type.IntOrDefault; ++import io.papermc.paper.configuration.type.fallback.FallbackValueSerializer; ++import it.unimi.dsi.fastutil.objects.Reference2IntMap; ++import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; ++import it.unimi.dsi.fastutil.objects.Reference2LongMap; ++import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap; ++import net.minecraft.core.Registry; ++import net.minecraft.data.BuiltinRegistries; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.world.entity.EntityType; ++import net.minecraft.world.item.Item; ++import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; ++import org.bukkit.command.Command; ++import org.bukkit.configuration.ConfigurationSection; ++import org.bukkit.configuration.file.YamlConfiguration; ++import org.jetbrains.annotations.VisibleForTesting; ++import org.slf4j.Logger; ++import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.BasicConfigurationNode; ++import org.spongepowered.configurate.ConfigurateException; ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.ConfigurationOptions; ++import org.spongepowered.configurate.objectmapping.ObjectMapper; ++import org.spongepowered.configurate.yaml.YamlConfigurationLoader; + +import java.io.File; +import java.io.IOException; -+import java.lang.reflect.InvocationTargetException; -+import java.lang.reflect.Method; -+import java.lang.reflect.Modifier; ++import java.lang.reflect.Type; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.StandardCopyOption; +import java.util.HashMap; ++import java.util.Map; ++import java.util.function.UnaryOperator; ++ ++import static com.google.common.base.Preconditions.checkState; ++import static io.leangen.geantyref.GenericTypeReflector.erase; ++ ++@SuppressWarnings("Convert2Diamond") ++public class PaperConfigurations extends Configurations { ++ ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ 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"; ++ private static final Path BACKUP_DIR = Path.of("legacy-backup"); ++ ++ private static final String GLOBAL_HEADER = """ ++ This is the global configuration file for Paper. ++ As you can see, there's tons 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 IRC channel. ++ ++ The world configuration options have been moved to their own files. ++ ++ Discord: https://discord.gg/papermc ++ IRC: #paper @ irc.esper.net ( https://webchat.esper.net/?channels=paper ) ++ Website: https://papermc.io/ ++ Docs: https://docs.papermc.io/"""; ++ ++ private static final String WORLD_DEFAULTS_HEADER = """ ++ This is the world defaults configuration file for Paper. ++ As you can see, there's tons 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 IRC channel. ++ ++ Configuration options here apply to all worlds, unless you specify overrides inside ++ the world-specific config file inside each world folder. ++ ++ Discord: https://discord.gg/papermc ++ IRC: #paper @ irc.esper.net ( https://webchat.esper.net/?channels=paper ) ++ Website: https://papermc.io/ ++ Docs: https://docs.papermc.io/"""; ++ ++ private static final String WORLD_HEADER = """ ++ This is a world configuration file for Paper. ++ This file may start empty but can be filled with settings to override ones in the config/world-defaults.yml"""; ++ ++ ++ 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 YamlConfigurationLoader.Builder createLoaderBuilder() { ++ return super.createLoaderBuilder() ++ .defaultOptions(PaperConfigurations::defaultOptions); ++ } ++ ++ private static ConfigurationOptions defaultOptions(ConfigurationOptions options) { ++ return options.serializers(builder -> builder.register(MapSerializer.TYPE, new MapSerializer())); ++ } ++ ++ @Override ++ protected ObjectMapper.Factory.Builder createGlobalObjectMapperFactoryBuilder() { ++ return defaultGlobalFactoryBuilder(super.createGlobalObjectMapperFactoryBuilder()); ++ } ++ ++ private static ObjectMapper.Factory.Builder defaultGlobalFactoryBuilder(ObjectMapper.Factory.Builder builder) { ++ return builder.addDiscoverer(InnerClassFieldDiscoverer.globalConfig()); ++ } ++ ++ @Override ++ protected YamlConfigurationLoader.Builder createGlobalLoaderBuilder() { ++ return super.createGlobalLoaderBuilder() ++ .defaultOptions(PaperConfigurations::defaultGlobalOptions); ++ } ++ ++ private static ConfigurationOptions defaultGlobalOptions(ConfigurationOptions options) { ++ return options ++ .header(GLOBAL_HEADER) ++ .serializers(builder -> builder.register(new PacketClassSerializer())); ++ } ++ ++ @Override ++ public GlobalConfiguration initializeGlobalConfiguration() throws ConfigurateException { ++ GlobalConfiguration configuration = super.initializeGlobalConfiguration(); ++ GlobalConfiguration.set(configuration); ++ return configuration; ++ } ++ ++ @Override ++ protected void applyGlobalConfigTransformations(org.spongepowered.configurate.ConfigurationNode node) throws org.spongepowered.configurate.ConfigurateException { ++ super.applyGlobalConfigTransformations(node); ++ } ++ ++ @Override ++ protected ObjectMapper.Factory.Builder createWorldObjectMapperFactoryBuilder(final String levelName, final SpigotWorldConfig spigotConfig) { ++ return super.createWorldObjectMapperFactoryBuilder(levelName, spigotConfig) ++ .addNodeResolver(new RequiresSpigotInitialization.Factory(spigotConfig)) ++ .addNodeResolver(new NestedSetting.Factory()) ++ .addDiscoverer(InnerClassFieldDiscoverer.worldConfig(spigotConfig)); ++ } ++ ++ @Override ++ protected YamlConfigurationLoader.Builder createWorldConfigLoaderBuilder(final String levelName, final SpigotWorldConfig spigotConfig) { ++ return super.createWorldConfigLoaderBuilder(levelName, spigotConfig) ++ .defaultOptions(options -> options ++ .header(levelName.equals(WORLD_DEFAULTS) ? WORLD_DEFAULTS_HEADER : WORLD_HEADER) ++ .serializers(serializers -> serializers ++ .register(new TypeToken>() {}, new FastutilMapSerializer.SomethingToPrimitive>(Reference2IntOpenHashMap::new, Integer.TYPE)) ++ .register(new TypeToken>() {}, new FastutilMapSerializer.SomethingToPrimitive>(Reference2LongOpenHashMap::new, Long.TYPE)) ++ .register(new TypeToken>() {}, new TableSerializer()) ++ .register(new StringRepresentableSerializer()) ++ .register(IntOrDefault.SERIALIZER) ++ .register(DoubleOrDefault.SERIALIZER) ++ .register(BooleanOrDefault.SERIALIZER) ++ .register(Duration.SERIALIZER) ++ .register(FallbackValueSerializer.create(spigotConfig, MinecraftServer::getServer)) ++ .register(new RegistryValueSerializer<>(new TypeToken>() {}, Registry.ENTITY_TYPE, true)) ++ .register(new RegistryValueSerializer<>(Item.class, Registry.ITEM, true)) ++ .register(new RegistryHolderSerializer<>(new TypeToken>() {}, BuiltinRegistries.CONFIGURED_FEATURE, false)) ++ .register(new RegistryHolderSerializer<>(Item.class, Registry.ITEM, true)) ++ ) ++ ); ++ } ++ ++ @Override ++ protected void applyWorldConfigTransformations(final String world, final ConfigurationNode node) throws ConfigurateException { ++ final ConfigurationNode version = node.node(Configuration.VERSION_FIELD); ++ if (version.virtual()) { ++ LOGGER.warn("The world config file for " + world + " didn't have a version set, assuming latest"); ++ version.raw(WorldConfiguration.CURRENT_VERSION); ++ } ++ // ADD FUTURE TRANSFORMS HERE ++ } ++ ++ @Override ++ public WorldConfiguration createWorldConfig(final Path dir, final String levelName, final SpigotWorldConfig spigotConfig) { ++ try { ++ return super.createWorldConfig(dir, levelName, spigotConfig); ++ } 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(reloader(this.globalConfigClass, GlobalConfiguration.get())); ++ this.initializeWorldDefaultsConfiguration(); ++ for (ServerLevel level : server.getAllLevels()) { ++ this.createWorldConfig(level.convertable.levelDirectory.path(), level.serverLevelData.getLevelName(), level.spigotConfig, reloader(this.worldConfigClass, level.paperConfig())); ++ } ++ } catch (Exception ex) { ++ throw new RuntimeException("Could not reload paper configuration files", ex); ++ } ++ } ++ ++ public static PaperConfigurations setup(final Path legacyConfig, final Path configDir, final Path worldFolder, final File spigotConfig) throws Exception { ++ if (needsConverting(legacyConfig)) { ++ try { ++ Files.createDirectories(configDir.resolve(BACKUP_DIR)); ++ final Path legacyConfigBackup = configDir.resolve(BACKUP_DIR).resolve(legacyConfig.getFileName().toString() + ".old"); ++ Files.move(legacyConfig, legacyConfigBackup, StandardCopyOption.REPLACE_EXISTING); // make backup ++ convert(legacyConfigBackup, configDir, worldFolder, spigotConfig); ++ } catch (final IOException ex) { ++ throw new RuntimeException("Could not convert paper.yml to the new configuration format", ex); ++ } ++ } ++ try { ++ Files.createDirectories(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 { ++ Files.createDirectories(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); ++ } ++ ++ private static final Map COMMANDS = new HashMap<>(); ++ static { ++ } ++ ++ public static void registerCommands(final MinecraftServer server) { ++ COMMANDS.forEach((s, command) -> { ++ server.server.getCommandMap().register(s, "Paper", command); ++ }); ++ } ++ ++ @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; ++ } ++ ++ @Deprecated ++ public static YamlConfiguration loadLegacyConfigFile(File configFile) throws Exception { ++ YamlConfiguration config = new YamlConfiguration(); ++ if (configFile.exists()) { ++ try { ++ config.load(configFile); ++ } catch (Exception ex) { ++ throw new Exception("Failed to load configuration file: " + configFile.getName(), ex); ++ } ++ } ++ return config; ++ } ++ ++ @VisibleForTesting ++ static ConfigurationNode createForTesting() { ++ ObjectMapper.Factory factory = defaultGlobalFactoryBuilder(ObjectMapper.factoryBuilder()).build(); ++ ConfigurationOptions options = defaultGlobalOptions(defaultOptions(ConfigurationOptions.defaults())) ++ .serializers(builder -> builder.register(type -> ConfigurationPart.class.isAssignableFrom(erase(type)), factory.asTypeSerializer())); ++ return BasicConfigurationNode.root(options); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration; ++ ++import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray; ++import com.google.common.collect.HashBasedTable; ++import com.google.common.collect.Table; ++import io.papermc.paper.configuration.constraint.Constraint; ++import io.papermc.paper.configuration.constraint.Constraints; ++import io.papermc.paper.configuration.legacy.MaxEntityCollisionsInitializer; ++import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization; ++import io.papermc.paper.configuration.legacy.SpawnLoadedRangeInitializer; ++import io.papermc.paper.configuration.type.BooleanOrDefault; ++import io.papermc.paper.configuration.type.DoubleOrDefault; ++import io.papermc.paper.configuration.type.Duration; ++import io.papermc.paper.configuration.type.IntOrDefault; ++import io.papermc.paper.configuration.type.fallback.ArrowDespawnRate; ++import io.papermc.paper.configuration.type.fallback.AutosavePeriod; ++import it.unimi.dsi.fastutil.objects.Reference2IntMap; ++import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; ++import it.unimi.dsi.fastutil.objects.Reference2LongMap; ++import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap; ++import net.minecraft.Util; ++import net.minecraft.core.Holder; ++import net.minecraft.core.Registry; ++import net.minecraft.world.Difficulty; ++import net.minecraft.world.entity.EntityType; ++import net.minecraft.world.entity.MobCategory; ++import net.minecraft.world.entity.monster.Vindicator; ++import net.minecraft.world.entity.monster.Zombie; ++import net.minecraft.world.item.Item; ++import net.minecraft.world.item.Items; ++import net.minecraft.world.level.NaturalSpawner; ++import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; ++import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.objectmapping.ConfigSerializable; ++import org.spongepowered.configurate.objectmapping.meta.Required; ++import org.spongepowered.configurate.objectmapping.meta.Setting; ++ ++import java.util.Arrays; +import java.util.List; +import java.util.Map; -+import java.util.concurrent.TimeUnit; -+import java.util.logging.Level; -+import java.util.regex.Pattern; ++import java.util.function.Function; ++import java.util.stream.Collectors; + -+import net.minecraft.server.MinecraftServer; -+import org.bukkit.Bukkit; -+import org.bukkit.command.Command; -+import org.bukkit.configuration.ConfigurationSection; -+import org.bukkit.configuration.InvalidConfigurationException; -+import org.bukkit.configuration.file.YamlConfiguration; ++@SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic"}) ++public class WorldConfiguration extends ConfigurationPart { ++ static final int CURRENT_VERSION = 28; + -+public class PaperConfig { ++ private transient final SpigotWorldConfig spigotConfig; ++ WorldConfiguration(SpigotWorldConfig spigotConfig) { ++ this.spigotConfig = spigotConfig; ++ } + -+ private static File CONFIG_FILE; -+ private static final String HEADER = "This is the main configuration file for Paper.\n" -+ + "As you can see, there's tons to configure. Some options may impact gameplay, so use\n" -+ + "with caution, and make sure you know what each option does before configuring.\n" -+ + "\n" -+ + "If you need help with the configuration or have any questions related to Paper,\n" -+ + "join us in our Discord or IRC channel.\n" -+ + "\n" -+ + "Discord: https://discord.gg/papermc\n" -+ + "IRC: #paper @ irc.esper.net ( https://webchat.esper.net/?channels=paper ) \n" -+ + "Website: https://papermc.io/ \n" -+ + "Docs: https://docs.papermc.io/ \n"; -+ /*========================================================================*/ -+ public static YamlConfiguration config; -+ static int version; -+ static Map commands; -+ private static boolean verbose; -+ private static boolean fatalError; -+ /*========================================================================*/ ++ @Setting(Configuration.VERSION_FIELD) ++ public int version = CURRENT_VERSION; + -+ public static void init(File configFile) { -+ CONFIG_FILE = configFile; -+ config = new YamlConfiguration(); -+ try { -+ config.load(CONFIG_FILE); -+ } catch (IOException ex) { -+ } catch (InvalidConfigurationException ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Could not load paper.yml, please correct your syntax errors", ex); -+ throw Throwables.propagate(ex); ++ public AntiCheat anticheat; ++ ++ public class AntiCheat extends ConfigurationPart { ++ ++ public Obfuscation obfuscation; ++ ++ public class Obfuscation extends ConfigurationPart { ++ public Items items = new Items(); ++ public class Items extends ConfigurationPart { ++ public boolean hideItemmeta = false; ++ public boolean hideDurability = false; ++ } + } -+ config.options().header(HEADER); -+ config.options().copyDefaults(true); -+ verbose = getBoolean("verbose", false); + -+ commands = new HashMap(); -+ commands.put("paper", new PaperCommand("paper")); ++ public AntiXRay antiXray; + -+ version = getInt("config-version", 27); -+ set("config-version", 27); -+ readConfig(PaperConfig.class, null); -+ } -+ -+ protected static void logError(String s) { -+ Bukkit.getLogger().severe(s); -+ } -+ -+ protected static void fatal(String s) { -+ fatalError = true; -+ throw new RuntimeException("Fatal paper.yml config error: " + s); -+ } -+ -+ protected static void log(String s) { -+ if (verbose) { -+ Bukkit.getLogger().info(s); ++ public class AntiXRay extends ConfigurationPart { ++ public boolean enabled = false; ++ public ChunkPacketBlockControllerAntiXray.EngineMode engineMode = ChunkPacketBlockControllerAntiXray.EngineMode.HIDE; ++ public int maxBlockHeight = 64; ++ public int updateRadius = 2; ++ public boolean lavaObscures = false; ++ public boolean usePermission = false; ++ public List hiddenBlocks = List.of("copper_ore", "deepslate_copper_ore", "gold_ore", "deepslate_gold_ore", "iron_ore", "deepslate_iron_ore", ++ "coal_ore", "deepslate_coal_ore", "lapis_ore", "deepslate_lapis_ore", "mossy_cobblestone", "obsidian", "chest", "diamond_ore", "deepslate_diamond_ore", ++ "redstone_ore", "deepslate_redstone_ore", "clay", "emerald_ore", "deepslate_emerald_ore", "ender_chest"); // TODO update type to List ++ public List replacementBlocks = List.of("stone", "oak_planks", "deepslate"); // TODO update type to List + } + } + -+ public static void registerCommands() { -+ for (Map.Entry entry : commands.entrySet()) { -+ MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Paper", entry.getValue()); -+ } -+ } ++ public Entities entities; + -+ static void readConfig(Class clazz, Object instance) { -+ for (Method method : clazz.getDeclaredMethods()) { -+ if (Modifier.isPrivate(method.getModifiers())) { -+ if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { -+ try { -+ method.setAccessible(true); -+ method.invoke(instance); -+ } catch (InvocationTargetException ex) { -+ throw Throwables.propagate(ex.getCause()); -+ } catch (Exception ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex); ++ public class Entities extends ConfigurationPart { ++ public boolean entitiesTargetWithFollowRange = false; ++ public MobEffects mobEffects; ++ ++ public class MobEffects extends ConfigurationPart { ++ public boolean undeadImmuneToCertainEffects = true; ++ public boolean spidersImmuneToPoisonEffect = true; ++ public ImmuneToWitherEffect immuneToWitherEffect; ++ ++ public class ImmuneToWitherEffect extends ConfigurationPart { ++ public boolean wither = true; ++ public boolean witherSkeleton = true; ++ } ++ } ++ ++ public ArmorStands armorStands; ++ ++ public class ArmorStands extends ConfigurationPart { ++ public boolean doCollisionEntityLookups = true; ++ public boolean tick = true; ++ } ++ ++ public Spawning spawning; ++ ++ public class Spawning extends ConfigurationPart { ++ public ArrowDespawnRate nonPlayerArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); ++ public ArrowDespawnRate creativeArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); ++ public boolean filterNbtDataFromSpawnEggsAndRelated = true; ++ public boolean disableMobSpawnerSpawnEggTransformation = false; ++ public boolean perPlayerMobSpawns = true; ++ public boolean scanForLegacyEnderDragon = true; ++ public Reference2IntMap spawnLimits = Util.make(new Reference2IntOpenHashMap<>(NaturalSpawner.SPAWNING_CATEGORIES.length), map -> Arrays.stream(NaturalSpawner.SPAWNING_CATEGORIES).forEach(mobCategory -> map.put(mobCategory, -1))); ++ public Map despawnRanges = Arrays.stream(MobCategory.values()).collect(Collectors.toMap(Function.identity(), category -> new DespawnRange(category.getNoDespawnDistance(), category.getDespawnDistance()))); ++ ++ @ConfigSerializable ++ public record DespawnRange(@Required int soft, @Required int hard) { ++ } ++ ++ public WaterAnimalSpawnHeight wateranimalSpawnHeight; ++ ++ public class WaterAnimalSpawnHeight extends ConfigurationPart { ++ public IntOrDefault maximum = IntOrDefault.USE_DEFAULT; ++ public IntOrDefault minimum = IntOrDefault.USE_DEFAULT; ++ } ++ ++ public SlimeSpawnHeight slimeSpawnHeight; ++ ++ public class SlimeSpawnHeight extends ConfigurationPart { ++ ++ public SwampBiome swampBiome; ++ ++ public class SwampBiome extends ConfigurationPart { ++ public double maximum = 70; ++ public double minimum = 50; ++ } ++ ++ public SlimeChunk slimeChunk; ++ ++ public class SlimeChunk extends ConfigurationPart { ++ public double maximum = 40; ++ } ++ } ++ ++ public WanderingTrader wanderingTrader; ++ ++ public class WanderingTrader extends ConfigurationPart { ++ public int spawnMinuteLength = 1200; ++ public int spawnDayLength = 24000; ++ public int spawnChanceFailureIncrement = 25; ++ public int spawnChanceMin = 25; ++ public int spawnChanceMax = 75; ++ } ++ ++ public boolean allChunksAreSlimeChunks = false; ++ @Constraint(Constraints.BelowZeroDoubleToDefault.class) ++ public DoubleOrDefault skeletonHorseThunderSpawnChance = DoubleOrDefault.USE_DEFAULT; ++ public boolean ironGolemsCanSpawnInAir = false; ++ public boolean countAllMobsForSpawning = false; ++ public int monsterSpawnMaxLightLevel = -1; ++ public DuplicateUUID duplicateUuid; ++ ++ public class DuplicateUUID extends ConfigurationPart { ++ public DuplicateUUIDMode mode = DuplicateUUIDMode.SAFE_REGEN; ++ public int safeRegenDeleteRange = 32; ++ ++ public enum DuplicateUUIDMode { ++ SAFE_REGEN, DELETE, NOTHING, WARN; ++ } ++ } ++ public AltItemDespawnRate altItemDespawnRate; ++ ++ public class AltItemDespawnRate extends ConfigurationPart { ++ public boolean enabled = false; ++ public Reference2IntMap items = new Reference2IntOpenHashMap<>(Map.of(Items.COBBLESTONE, 300)); ++ } ++ } ++ ++ public Behavior behavior; ++ ++ public class Behavior extends ConfigurationPart { ++ public boolean disableChestCatDetection = false; ++ public boolean spawnerNerfedMobsShouldJump = false; ++ public int experienceMergeMaxValue = -1; ++ public boolean shouldRemoveDragon = false; ++ public boolean zombiesTargetTurtleEggs = true; ++ public boolean piglinsGuardChests = true; ++ public double babyZombieMovementModifier = 0.5; ++ public DoorBreakingDifficulty doorBreakingDifficulty; ++ ++ public class DoorBreakingDifficulty extends ConfigurationPart { // TODO convert to map at some point ++ public List zombie = Arrays.stream(Difficulty.values()).filter(Zombie.DOOR_BREAKING_PREDICATE).toList(); ++ public List husk = Arrays.stream(Difficulty.values()).filter(Zombie.DOOR_BREAKING_PREDICATE).toList(); ++ @Setting("zombie_villager") ++ public List zombieVillager = Arrays.stream(Difficulty.values()).filter(Zombie.DOOR_BREAKING_PREDICATE).toList(); ++ @Setting("zombified_piglin") ++ public List zombified_piglin = Arrays.stream(Difficulty.values()).filter(Zombie.DOOR_BREAKING_PREDICATE).toList(); ++ public List vindicator = Arrays.stream(Difficulty.values()).filter(Vindicator.DOOR_BREAKING_PREDICATE).toList(); ++ ++ // TODO remove when this becomes a proper map ++ public List get(EntityType type) { ++ return this.getOrDefault(type, null); ++ } ++ ++ public List getOrDefault(EntityType type, List fallback) { ++ if (type == EntityType.ZOMBIE) { ++ return this.zombie; ++ } else if (type == EntityType.HUSK) { ++ return this.husk; ++ } else if (type == EntityType.ZOMBIE_VILLAGER) { ++ return this.zombieVillager; ++ } else if (type == EntityType.ZOMBIFIED_PIGLIN) { ++ return this.zombified_piglin; ++ } else if (type == EntityType.VINDICATOR) { ++ return this.vindicator; ++ } else { ++ return fallback; + } + } + } ++ ++ public boolean disableCreeperLingeringEffect = false; ++ public boolean enderDragonsDeathAlwaysPlacesDragonEgg = false; ++ public boolean phantomsDoNotSpawnOnCreativePlayers = true; ++ public boolean phantomsOnlyAttackInsomniacs = true; ++ public boolean parrotsAreUnaffectedByPlayerMovement = false; ++ public double zombieVillagerInfectionChance = -1.0; ++ public MobsCanAlwaysPickUpLoot mobsCanAlwaysPickUpLoot; ++ ++ public class MobsCanAlwaysPickUpLoot extends ConfigurationPart { ++ public boolean zombies = false; ++ public boolean skeletons = false; ++ } ++ ++ public boolean disablePlayerCrits = false; ++ public boolean nerfPigmenFromNetherPortals = false; ++ public PillagerPatrols pillagerPatrols; ++ ++ public class PillagerPatrols extends ConfigurationPart { ++ public boolean disable = false; ++ public double spawnChance = 0.2; ++ public SpawnDelay spawnDelay; ++ public Start start; ++ ++ public class SpawnDelay extends ConfigurationPart { ++ public boolean perPlayer = false; ++ public int ticks = 12000; ++ } ++ ++ public class Start extends ConfigurationPart { ++ public boolean perPlayer = false; ++ public int day = 5; ++ } ++ } + } -+ saveConfig(); + } + -+ static void saveConfig() { -+ try { -+ config.save(CONFIG_FILE); -+ } catch (IOException ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Could not save " + CONFIG_FILE, ex); ++ public Lootables lootables; ++ ++ public class Lootables extends ConfigurationPart { ++ public boolean autoReplenish = false; ++ public boolean restrictPlayerReloot = true; ++ public boolean resetSeedOnFill = true; ++ public int maxRefills = -1; ++ public Duration refreshMin = Duration.of("12h"); ++ public Duration refreshMax = Duration.of("2d"); ++ } ++ ++ public MaxGrowthHeight maxGrowthHeight; ++ ++ public class MaxGrowthHeight extends ConfigurationPart { ++ public int cactus = 3; ++ public int reeds = 3; ++ public Bamboo bamboo; ++ ++ public class Bamboo extends ConfigurationPart { ++ public int max = 16; ++ public int min = 11; + } + } + ++ public Scoreboards scoreboards; ++ ++ public class Scoreboards extends ConfigurationPart { ++ public boolean allowNonPlayerEntitiesOnScoreboards = false; ++ public boolean useVanillaWorldScoreboardNameColoring = false; ++ } ++ ++ public Environment environment; ++ ++ public class Environment extends ConfigurationPart { ++ public boolean disableThunder = false; ++ public boolean disableIceAndSnow = false; ++ public boolean optimizeExplosions = false; ++ public boolean disableExplosionKnockback = false; ++ public boolean generateFlatBedrock = false; ++ public FrostedIce frostedIce; ++ ++ public class FrostedIce extends ConfigurationPart { ++ public boolean enabled = true; ++ public Delay delay; ++ ++ public class Delay extends ConfigurationPart { ++ public int min = 20; ++ public int max = 40; ++ } ++ } ++ ++ public TreasureMaps treasureMaps; ++ public class TreasureMaps extends ConfigurationPart { ++ public boolean enabled = true; ++ @NestedSetting({"find-already-discovered", "villager-trade"}) ++ public boolean findAlreadyDiscoveredVillager = false; ++ @NestedSetting({"find-already-discovered", "loot-tables"}) ++ public BooleanOrDefault findAlreadyDiscoveredLootTable = BooleanOrDefault.USE_DEFAULT; ++ } ++ ++ public int waterOverLavaFlowSpeed = 5; ++ public int portalSearchRadius = 128; ++ public int portalCreateRadius = 16; ++ public boolean portalSearchVanillaDimensionScaling = true; ++ public boolean disableTeleportationSuffocationCheck = false; ++ public int netherCeilingVoidDamageHeight = 0; ++ } ++ ++ public Spawn spawn; ++ ++ public class Spawn extends ConfigurationPart { ++ @RequiresSpigotInitialization(SpawnLoadedRangeInitializer.class) ++ public short keepSpawnLoadedRange = 10; ++ public boolean keepSpawnLoaded = true; ++ public boolean allowUsingSignsInsideSpawnProtection = false; ++ } ++ ++ public Maps maps; ++ ++ public class Maps extends ConfigurationPart { ++ public int itemFrameCursorLimit = 128; ++ public int itemFrameCursorUpdateInterval = 10; ++ } ++ ++ public Fixes fixes; ++ ++ public class Fixes extends ConfigurationPart { ++ public boolean fixItemsMergingThroughWalls = false; ++ public boolean disableUnloadedChunkEnderpearlExploit = true; ++ public boolean preventTntFromMovingInWater = false; ++ public boolean splitOverstackedLoot = true; ++ public boolean fixCuringZombieVillagerDiscountExploit = true; ++ public int fallingBlockHeightNerf = 0; ++ public int tntEntityHeightNerf = 0; ++ } ++ ++ public UnsupportedSettings unsupportedSettings; ++ ++ public class UnsupportedSettings extends ConfigurationPart { ++ public boolean fixInvulnerableEndCrystalExploit = true; ++ } ++ ++ public Hopper hopper; ++ ++ public class Hopper extends ConfigurationPart { ++ public boolean cooldownWhenFull = true; ++ public boolean disableMoveEvent = false; ++ public boolean ignoreOccludingBlocks = false; ++ } ++ ++ public Collisions collisions; ++ ++ public class Collisions extends ConfigurationPart { ++ public boolean onlyPlayersCollide = false; ++ public boolean allowVehicleCollisions = true; ++ public boolean fixClimbingBypassingCrammingRule = false; ++ @RequiresSpigotInitialization(MaxEntityCollisionsInitializer.class) ++ public int maxEntityCollisions = 8; ++ public boolean allowPlayerCrammingDamage = false; ++ } ++ ++ public Chunks chunks; ++ ++ public class Chunks extends ConfigurationPart { ++ public AutosavePeriod autoSaveInterval = AutosavePeriod.def(); ++ public int maxAutoSaveChunksPerTick = 24; ++ public int fixedChunkInhabitedTime = -1; ++ public boolean preventMovingIntoUnloadedChunks = false; ++ public Duration delayChunkUnloadsBy = Duration.of("10s"); ++ public Reference2IntMap> entityPerChunkSaveLimit = Util.make(new Reference2IntOpenHashMap<>(Registry.ENTITY_TYPE.size()), map -> { ++ map.defaultReturnValue(-1); ++ map.put(EntityType.EXPERIENCE_ORB, -1); ++ map.put(EntityType.SNOWBALL, -1); ++ map.put(EntityType.ENDER_PEARL, -1); ++ map.put(EntityType.ARROW, -1); ++ map.put(EntityType.FIREBALL, -1); ++ map.put(EntityType.SMALL_FIREBALL, -1); ++ }); ++ } ++ ++ public FishingTimeRange fishingTimeRange; ++ ++ public class FishingTimeRange extends ConfigurationPart { ++ public int minimum = 100; ++ public int maximum = 600; ++ } ++ ++ public TickRates tickRates; ++ ++ public class TickRates extends ConfigurationPart { ++ public int grassSpread = 1; ++ public int containerUpdate = 1; ++ public int mobSpawner = 1; ++ public Table, String, Integer> sensor = Util.make(HashBasedTable.create(), table -> table.put(EntityType.VILLAGER, "secondarypoisensor", 40)); ++ public Table, String, Integer> behavior = Util.make(HashBasedTable.create(), table -> table.put(EntityType.VILLAGER, "validatenearbypoi", -1)); ++ } ++ ++ public FeatureSeeds featureSeeds; ++ ++ public class FeatureSeeds extends ConfigurationPart { ++ public boolean generateRandomSeedsForAll = false; ++ public Reference2LongMap>> features = new Reference2LongOpenHashMap<>(); ++ // TODO post processing to generate random seeds if generateRandomSeedsForAll == true ++ } ++ ++ public Misc misc; ++ ++ public class Misc extends ConfigurationPart { ++ public int lightQueueSize = 20; ++ public boolean updatePathfindingOnBlockUpdate = true; ++ public boolean showSignClickCommandFailureMsgsToPlayer = false; ++ public RedstoneImplementation redstoneImplementation = RedstoneImplementation.VANILLA; ++ public boolean disableEndCredits = false; ++ public float maxLeashDistance = 10f; ++ public boolean disableSprintInterruptionOnAttack = false; ++ public int shieldBlockingDelay = 5; ++ public boolean disableRelativeProjectileVelocity = false; ++ ++ public enum RedstoneImplementation { ++ VANILLA, EIGENCRAFT, ALTERNATE_CURRENT ++ } ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/configuration/constraint/Constraint.java b/src/main/java/io/papermc/paper/configuration/constraint/Constraint.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/constraint/Constraint.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.constraint; ++ ++import java.lang.annotation.Documented; ++import java.lang.annotation.ElementType; ++import java.lang.annotation.Retention; ++import java.lang.annotation.RetentionPolicy; ++import java.lang.annotation.Target; ++import java.lang.reflect.Constructor; ++import java.lang.reflect.Type; ++ ++@Documented ++@Retention(RetentionPolicy.RUNTIME) ++@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER}) ++public @interface Constraint { ++ Class> value(); ++ ++ class Factory implements org.spongepowered.configurate.objectmapping.meta.Constraint.Factory { ++ @SuppressWarnings("unchecked") ++ @Override ++ public org.spongepowered.configurate.objectmapping.meta.Constraint make(final Constraint data, final Type type) { ++ try { ++ final Constructor> constructor = data.value().getDeclaredConstructor(); ++ constructor.trySetAccessible(); ++ return (org.spongepowered.configurate.objectmapping.meta.Constraint) constructor.newInstance(); ++ } catch (final ReflectiveOperationException e) { ++ throw new RuntimeException("Could not create constraint", e); ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/constraint/Constraints.java b/src/main/java/io/papermc/paper/configuration/constraint/Constraints.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/constraint/Constraints.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.constraint; ++ ++import io.papermc.paper.configuration.GlobalConfiguration; ++import io.papermc.paper.configuration.type.DoubleOrDefault; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.objectmapping.meta.Constraint; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.lang.annotation.Documented; ++import java.lang.annotation.ElementType; ++import java.lang.annotation.Retention; ++import java.lang.annotation.RetentionPolicy; ++import java.lang.annotation.Target; ++import java.lang.reflect.Type; ++import java.util.OptionalDouble; ++ ++public final class Constraints { ++ private Constraints() { ++ } ++ ++ public static final class Velocity implements Constraint { ++ @Override ++ public void validate(final GlobalConfiguration.Proxies.@Nullable Velocity value) throws SerializationException { ++ if (value != null && value.enabled && value.secret.isEmpty()) { ++ throw new SerializationException("Velocity is enabled, but no secret key was specified. A secret key is required!"); ++ } ++ } ++ } ++ ++ public static final class Positive implements Constraint { ++ @Override ++ public void validate(@Nullable Number value) throws SerializationException { ++ if (value != null && value.doubleValue() <= 0) { ++ throw new SerializationException(value + " should be positive"); ++ } ++ } ++ } ++ ++ public static final class BelowZeroDoubleToDefault implements Constraint { ++ @Override ++ public void validate(final @Nullable DoubleOrDefault container) { ++ if (container != null) { ++ final OptionalDouble value = container.value(); ++ if (value.isPresent() && value.getAsDouble() < 0) { ++ container.value(OptionalDouble.empty()); ++ } ++ } ++ } ++ } ++ ++ @Documented ++ @Retention(RetentionPolicy.RUNTIME) ++ @Target(ElementType.FIELD) ++ public @interface Min { ++ int value(); ++ ++ final class Factory implements Constraint.Factory { ++ @Override ++ public Constraint make(Min data, Type type) { ++ return value -> { ++ if (value != null && value.intValue() < data.value()) { ++ throw new SerializationException(value + " is less than the min " + data.value()); ++ } ++ }; ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/legacy/MaxEntityCollisionsInitializer.java b/src/main/java/io/papermc/paper/configuration/legacy/MaxEntityCollisionsInitializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/legacy/MaxEntityCollisionsInitializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.legacy; ++ ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.objectmapping.meta.NodeResolver; ++import org.spongepowered.configurate.util.NamingSchemes; ++ ++public class MaxEntityCollisionsInitializer implements NodeResolver { ++ ++ private final String name; ++ private final SpigotWorldConfig spigotConfig; ++ ++ public MaxEntityCollisionsInitializer(String name, SpigotWorldConfig spigotConfig) { ++ this.name = name; ++ this.spigotConfig = spigotConfig; ++ } ++ ++ @Override ++ public @Nullable ConfigurationNode resolve(ConfigurationNode parent) { ++ final String key = NamingSchemes.LOWER_CASE_DASHED.coerce(this.name); ++ final ConfigurationNode node = parent.node(key); ++ final int old = this.spigotConfig.getInt("max-entity-collisions", -1, false); ++ if (node.virtual() && old > -1) { ++ node.raw(old); ++ } ++ return node; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/legacy/RequiresSpigotInitialization.java b/src/main/java/io/papermc/paper/configuration/legacy/RequiresSpigotInitialization.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/legacy/RequiresSpigotInitialization.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.legacy; ++ ++import com.google.common.collect.HashBasedTable; ++import com.google.common.collect.Table; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.objectmapping.meta.NodeResolver; ++ ++import java.lang.annotation.Documented; ++import java.lang.annotation.ElementType; ++import java.lang.annotation.Retention; ++import java.lang.annotation.RetentionPolicy; ++import java.lang.annotation.Target; ++import java.lang.reflect.AnnotatedElement; ++import java.lang.reflect.Constructor; ++import java.util.Map; ++import java.util.concurrent.ConcurrentHashMap; ++ ++@Documented ++@Retention(RetentionPolicy.RUNTIME) ++@Target(ElementType.FIELD) ++public @interface RequiresSpigotInitialization { ++ ++ Class value(); ++ ++ final class Factory implements NodeResolver.Factory { ++ ++ private final SpigotWorldConfig spigotWorldConfig; ++ private final Table, String, NodeResolver> cache = HashBasedTable.create(); ++ ++ public Factory(SpigotWorldConfig spigotWorldConfig) { ++ this.spigotWorldConfig = spigotWorldConfig; ++ } ++ ++ @Override ++ public @Nullable NodeResolver make(String name, AnnotatedElement element) { ++ if (element.isAnnotationPresent(RequiresSpigotInitialization.class)) { ++ return this.cache.row(element.getAnnotation(RequiresSpigotInitialization.class).value()).computeIfAbsent(name, key -> { ++ try { ++ final Constructor constructor = element.getAnnotation(RequiresSpigotInitialization.class).value().getDeclaredConstructor(String.class, SpigotWorldConfig.class); ++ constructor.trySetAccessible(); ++ return constructor.newInstance(key, this.spigotWorldConfig); ++ } catch (final ReflectiveOperationException e) { ++ throw new RuntimeException("Could not create constraint", e); ++ } ++ }); ++ } ++ return null; ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/legacy/SpawnLoadedRangeInitializer.java b/src/main/java/io/papermc/paper/configuration/legacy/SpawnLoadedRangeInitializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/legacy/SpawnLoadedRangeInitializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.legacy; ++ ++import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.objectmapping.meta.NodeResolver; ++import org.spongepowered.configurate.util.NamingSchemes; ++ ++public final class SpawnLoadedRangeInitializer implements NodeResolver { ++ ++ private final String name; ++ private final SpigotWorldConfig spigotConfig; ++ ++ public SpawnLoadedRangeInitializer(String name, SpigotWorldConfig spigotConfig) { ++ this.name = name; ++ this.spigotConfig = spigotConfig; ++ } ++ ++ @Override ++ public ConfigurationNode resolve(ConfigurationNode parent) { ++ final String key = NamingSchemes.LOWER_CASE_DASHED.coerce(this.name); ++ final ConfigurationNode node = parent.node(key); ++ if (node.virtual()) { ++ node.raw(Math.min(spigotConfig.viewDistance, 10)); ++ } ++ return node; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/package-info.java b/src/main/java/io/papermc/paper/configuration/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/package-info.java +@@ -0,0 +0,0 @@ ++@DefaultQualifier(NonNull.class) ++package io.papermc.paper.configuration; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; +\ No newline at end of file +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/FastutilMapSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/FastutilMapSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/serializer/FastutilMapSerializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.serializer; ++ ++import io.leangen.geantyref.GenericTypeReflector; ++import io.leangen.geantyref.TypeFactory; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.serialize.SerializationException; ++import org.spongepowered.configurate.serialize.TypeSerializer; ++ ++import java.lang.reflect.ParameterizedType; ++import java.lang.reflect.Type; ++import java.util.Collections; ++import java.util.Map; ++import java.util.function.Function; ++ ++@SuppressWarnings("rawtypes") ++public abstract class FastutilMapSerializer> implements TypeSerializer { ++ private final Function factory; ++ ++ protected FastutilMapSerializer(final Function factory) { ++ this.factory = factory; ++ } ++ ++ @Override ++ public M deserialize(final Type type, final ConfigurationNode node) throws SerializationException { ++ @Nullable final Map map = (Map) node.get(this.createBaseMapType((ParameterizedType) type)); ++ return this.factory.apply(map == null ? Collections.emptyMap() : map); ++ } ++ ++ @Override ++ public void serialize(final Type type, @Nullable final M obj, final ConfigurationNode node) throws SerializationException { ++ if (obj == null || obj.isEmpty()) { ++ node.raw(null); ++ } else { ++ final Type baseMapType = this.createBaseMapType((ParameterizedType) type); ++ node.set(baseMapType, obj); ++ } ++ } ++ ++ protected abstract Type createBaseMapType(final ParameterizedType type); ++ ++ public static final class SomethingToPrimitive> extends FastutilMapSerializer { ++ private final Type primitiveType; ++ ++ public SomethingToPrimitive(final Function factory, final Type primitiveType) { ++ super(factory); ++ this.primitiveType = primitiveType; ++ } ++ ++ @Override ++ protected Type createBaseMapType(final ParameterizedType type) { ++ return TypeFactory.parameterizedClass(Map.class, type.getActualTypeArguments()[0], GenericTypeReflector.box(this.primitiveType)); ++ } ++ } ++ ++ public static final class PrimitiveToSomething> extends FastutilMapSerializer { ++ private final Type primitiveType; ++ ++ public PrimitiveToSomething(final Function factory, final Type primitiveType) { ++ super(factory); ++ this.primitiveType = primitiveType; ++ } ++ ++ @Override ++ protected Type createBaseMapType(final ParameterizedType type) { ++ return TypeFactory.parameterizedClass(Map.class, GenericTypeReflector.box(this.primitiveType), type.getActualTypeArguments()[0]); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.serializer; ++ ++import io.leangen.geantyref.TypeToken; ++import io.papermc.paper.util.ObfHelper; ++import java.lang.reflect.Type; ++import java.util.Collection; ++import java.util.Collections; ++import java.util.List; ++import java.util.Map; ++import java.util.Optional; ++import java.util.function.Predicate; ++import java.util.stream.Collectors; ++import net.minecraft.network.protocol.Packet; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++@SuppressWarnings("Convert2Diamond") ++public final class PacketClassSerializer extends ScalarSerializer>> { ++ private static final TypeToken>> TYPE = new TypeToken>>() {}; ++ private static final List SUBPACKAGES = List.of("game", "handshake", "login", "status"); ++ private static final Map MOJANG_TO_OBF = Optional.ofNullable(ObfHelper.INSTANCE.mappingsByObfName()) ++ .map(Map::entrySet) ++ .map(Collection::stream) ++ .map(stream -> stream.collect(Collectors.toMap(entry -> entry.getValue().mojangName(), entry -> entry.getValue().obfName()))) ++ .orElseGet(Collections::emptyMap); ++ ++ public PacketClassSerializer() { ++ super(TYPE); ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Override ++ public Class> deserialize(final Type type, final Object obj) throws SerializationException { ++ @Nullable Class packetClass = null; ++ for (final String subpackage : SUBPACKAGES) { ++ final String fullClassName = "net.minecraft.network.protocol." + subpackage + "." + obj; ++ try { ++ packetClass = Class.forName(fullClassName); ++ } catch (final ClassNotFoundException ex) { ++ final @Nullable String spigotClassName = MOJANG_TO_OBF.get(fullClassName); ++ if (spigotClassName != null) { ++ try { ++ packetClass = Class.forName(spigotClassName); ++ } catch (final ClassNotFoundException ignore) {} ++ } ++ } ++ } ++ if (packetClass == null || !Packet.class.isAssignableFrom(packetClass)) { ++ throw new SerializationException("Could not deserialize a packet from " + obj); ++ } ++ return (Class>) packetClass; ++ } ++ ++ @Override ++ protected Object serialize(final Class> item, final Predicate> typeSupported) { ++ return item.getSimpleName(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/StringRepresentableSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/StringRepresentableSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/serializer/StringRepresentableSerializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.serializer; ++ ++import net.minecraft.util.StringRepresentable; ++import net.minecraft.world.entity.MobCategory; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.lang.reflect.Type; ++import java.util.Collections; ++import java.util.Map; ++import java.util.function.Function; ++import java.util.function.Predicate; ++ ++public final class StringRepresentableSerializer extends ScalarSerializer { ++ private static final Map> TYPES = Collections.synchronizedMap(Map.ofEntries( ++ Map.entry(MobCategory.class, s -> { ++ for (MobCategory value : MobCategory.values()) { ++ if (value.getSerializedName().equals(s)) { ++ return value; ++ } ++ } ++ return null; ++ }) ++ )); ++ ++ public StringRepresentableSerializer() { ++ super(StringRepresentable.class); ++ } ++ ++ @Override ++ public StringRepresentable deserialize(Type type, Object obj) throws SerializationException { ++ Function function = TYPES.get(type); ++ if (function == null) { ++ throw new SerializationException(type + " isn't registered"); ++ } ++ return function.apply(obj.toString()); ++ } ++ ++ @Override ++ protected Object serialize(StringRepresentable item, Predicate> typeSupported) { ++ return item.getSerializedName(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/TableSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/TableSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/serializer/TableSerializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.serializer; ++ ++import com.google.common.collect.HashBasedTable; ++import com.google.common.collect.ImmutableTable; ++import com.google.common.collect.Table; ++import io.leangen.geantyref.TypeFactory; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.BasicConfigurationNode; ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.ConfigurationOptions; ++import org.spongepowered.configurate.serialize.SerializationException; ++import org.spongepowered.configurate.serialize.TypeSerializer; ++ ++import java.lang.reflect.ParameterizedType; ++import java.lang.reflect.Type; ++import java.util.Map; ++import java.util.Objects; ++ ++public class TableSerializer implements TypeSerializer> { ++ private static final int ROW_TYPE_ARGUMENT_INDEX = 0; ++ private static final int COLUMN_TYPE_ARGUMENT_INDEX = 1; ++ private static final int VALUE_TYPE_ARGUMENT_INDEX = 2; ++ ++ @Override ++ public Table deserialize(final Type type, final ConfigurationNode node) throws SerializationException { ++ final Table table = HashBasedTable.create(); ++ if (!node.empty() && node.isMap()) { ++ this.deserialize0(table, (ParameterizedType) type, node); ++ } ++ return table; ++ } ++ ++ @SuppressWarnings("unchecked") ++ private void deserialize0(final Table table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException { ++ final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX]; ++ final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; ++ final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; ++ ++ final @Nullable TypeSerializer rowKeySerializer = (TypeSerializer) node.options().serializers().get(rowType); ++ if (rowKeySerializer == null) { ++ throw new SerializationException("Could not find serializer for table row type " + rowType); ++ } ++ ++ final Type mapType = TypeFactory.parameterizedClass(Map.class, columnType, valueType); ++ final @Nullable TypeSerializer> columnValueSerializer = (TypeSerializer>) node.options().serializers().get(mapType); ++ if (columnValueSerializer == null) { ++ throw new SerializationException("Could not find serializer for table column-value map " + type); ++ } ++ ++ final BasicConfigurationNode rowKeyNode = BasicConfigurationNode.root(node.options()); ++ ++ for (final Object key : node.childrenMap().keySet()) { ++ rowKeySerializer.deserialize(rowType, rowKeyNode.set(key)); ++ final Map map = columnValueSerializer.deserialize(mapType, node.node(rowKeyNode.raw())); ++ map.forEach((column, value) -> table.put((R) rowKeyNode.raw(), column, value)); ++ } ++ } ++ ++ @Override ++ public void serialize(final Type type, @Nullable final Table table, final ConfigurationNode node) throws SerializationException { ++ if (table != null) { ++ this.serialize0(table, (ParameterizedType) type, node); ++ } ++ } ++ ++ @SuppressWarnings({"rawtypes", "unchecked"}) ++ private void serialize0(final Table table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException { ++ final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX]; ++ final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; ++ final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; ++ ++ final @Nullable TypeSerializer rowKeySerializer = node.options().serializers().get(rowType); ++ if (rowKeySerializer == null) { ++ throw new SerializationException("Could not find a serializer for table row type " + rowType); ++ } ++ ++ final BasicConfigurationNode rowKeyNode = BasicConfigurationNode.root(node.options()); ++ for (final R key : table.rowKeySet()) { ++ rowKeySerializer.serialize(rowType, key, rowKeyNode.set(key)); ++ final Object keyObj = Objects.requireNonNull(rowKeyNode.raw()); ++ node.node(keyObj).set(TypeFactory.parameterizedClass(Map.class, columnType, valueType), table.row(key)); ++ } ++ } ++ ++ @Override ++ public @Nullable Table emptyValue(Type specificType, ConfigurationOptions options) { ++ return ImmutableTable.of(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.serializer.collections; ++ ++import com.mojang.logging.LogUtils; ++import io.leangen.geantyref.TypeToken; ++import io.papermc.paper.configuration.Configuration; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.slf4j.Logger; ++import org.spongepowered.configurate.BasicConfigurationNode; ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.ConfigurationOptions; ++import org.spongepowered.configurate.NodePath; ++import org.spongepowered.configurate.serialize.SerializationException; ++import org.spongepowered.configurate.serialize.TypeSerializer; ++ ++import java.lang.reflect.ParameterizedType; ++import java.lang.reflect.Type; ++import java.util.Collections; ++import java.util.HashSet; ++import java.util.LinkedHashMap; ++import java.util.Map; ++import java.util.Set; ++ ++import static java.util.Objects.requireNonNull; ++ ++/** ++ * Map serializer that does not throw errors on individual entry serialization failures. ++ */ ++public class MapSerializer implements TypeSerializer> { ++ ++ public static final TypeToken> TYPE = new TypeToken>() {}; ++ ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ ++ @Override ++ public Map deserialize(Type type, ConfigurationNode node) throws SerializationException { ++ final Map map = new LinkedHashMap<>(); ++ if (node.isMap()) { ++ if (!(type instanceof ParameterizedType parameterizedType)) { ++ throw new SerializationException(type, "Raw types are not supported for collections"); ++ } ++ if (parameterizedType.getActualTypeArguments().length != 2) { ++ throw new SerializationException(type, "Map expected two type arguments!"); ++ } ++ final Type key = parameterizedType.getActualTypeArguments()[0]; ++ final Type value = parameterizedType.getActualTypeArguments()[1]; ++ final @Nullable TypeSerializer keySerializer = node.options().serializers().get(key); ++ final @Nullable TypeSerializer valueSerializer = node.options().serializers().get(value); ++ if (keySerializer == null) { ++ throw new SerializationException(type, "No type serializer available for key type " + key); ++ } ++ if (valueSerializer == null) { ++ throw new SerializationException(type, "No type serializer available for value type " + value); ++ } ++ ++ final BasicConfigurationNode keyNode = BasicConfigurationNode.root(node.options()); ++ for (Map.Entry ent : node.childrenMap().entrySet()) { ++ final @Nullable Object keyValue = deserialize(key, keySerializer, "key", keyNode.set(ent.getKey()), node.path()); ++ final @Nullable Object valueValue = deserialize(value, valueSerializer, "value", ent.getValue(), ent.getValue().path()); ++ if (keyValue == null || valueValue == null) { ++ continue; ++ } ++ map.put(keyValue, valueValue); ++ } ++ } ++ return map; ++ } ++ ++ private @Nullable Object deserialize(Type type, TypeSerializer serializer, String mapPart, ConfigurationNode node, NodePath path) { ++ try { ++ return serializer.deserialize(type, node); ++ } catch (SerializationException exception) { ++ LOGGER.error("Could not deserialize {} {} into {} at {}", mapPart, node.raw(), type, path, exception); ++ } ++ return null; ++ } ++ ++ @Override ++ public void serialize(Type type, @Nullable Map obj, ConfigurationNode node) throws SerializationException { ++ if (!(type instanceof ParameterizedType parameterizedType)) { ++ throw new SerializationException(type, "Raw types are not supported for collections"); ++ } ++ if (parameterizedType.getActualTypeArguments().length != 2) { ++ throw new SerializationException(type, "Map expected two type arguments!"); ++ } ++ final Type key = parameterizedType.getActualTypeArguments()[0]; ++ final Type value = parameterizedType.getActualTypeArguments()[1]; ++ final @Nullable TypeSerializer keySerializer = node.options().serializers().get(key); ++ final @Nullable TypeSerializer valueSerializer = node.options().serializers().get(value); ++ ++ if (keySerializer == null) { ++ throw new SerializationException(type, "No type serializer available for key type " + key); ++ } ++ ++ if (valueSerializer == null) { ++ throw new SerializationException(type, "No type serializer available for value type " + value); ++ } ++ ++ if (obj == null || obj.isEmpty()) { ++ node.set(Collections.emptyMap()); ++ } else { ++ final BasicConfigurationNode keyNode = BasicConfigurationNode.root(node.options()); ++ for (Map.Entry ent : obj.entrySet()) { ++ if (!serialize(key, keySerializer, ent.getKey(), "key", keyNode, node.path())) { ++ continue; ++ } ++ final Object keyObj = requireNonNull(keyNode.raw(), "Key must not be null!"); ++ final ConfigurationNode child = node.node(keyObj); ++ serialize(value, valueSerializer, ent.getValue(), "value", child, child.path()); ++ } ++ } ++ } ++ ++ @SuppressWarnings({"rawtypes", "unchecked"}) ++ private boolean serialize(Type type, TypeSerializer serializer, Object object, String mapPart, ConfigurationNode node, NodePath path) { ++ try { ++ serializer.serialize(type, object, node); ++ return true; ++ } catch (SerializationException ex) { ++ ex.initPath(node::path); ++ LOGGER.error("Could not serialize {} {} from {} at {}", mapPart, object, type, path, ex); ++ } ++ return false; ++ } ++ ++ @Override ++ public @Nullable Map emptyValue(Type specificType, ConfigurationOptions options) { ++ return new LinkedHashMap<>(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.serializer.registry; ++ ++import io.leangen.geantyref.TypeToken; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.resources.ResourceLocation; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.lang.reflect.Type; ++import java.util.function.Predicate; ++ ++abstract class RegistryEntrySerializer extends ScalarSerializer { ++ ++ private final Registry registry; ++ private final boolean omitMinecraftNamespace; ++ ++ protected RegistryEntrySerializer(TypeToken type, Registry registry, boolean omitMinecraftNamespace) { ++ super(type); ++ this.registry = registry; ++ this.omitMinecraftNamespace = omitMinecraftNamespace; ++ } ++ ++ protected RegistryEntrySerializer(Class type, Registry registry, boolean omitMinecraftNamespace) { ++ super(type); ++ this.registry = registry; ++ this.omitMinecraftNamespace = omitMinecraftNamespace; ++ } ++ ++ protected final Registry registry() { ++ return this.registry; ++ } ++ ++ protected abstract T convertFromResourceKey(ResourceKey key) throws SerializationException; ++ ++ @Override ++ public final T deserialize(Type type, Object obj) throws SerializationException { ++ return this.convertFromResourceKey(this.deserializeKey(obj)); ++ } ++ ++ protected abstract ResourceKey convertToResourceKey(T value); ++ ++ @Override ++ protected final Object serialize(T item, Predicate> typeSupported) { ++ final ResourceKey key = this.convertToResourceKey(item); ++ if (this.omitMinecraftNamespace && key.location().getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) { ++ return key.location().getPath(); ++ } else { ++ return key.location().toString(); ++ } ++ } ++ ++ private ResourceKey deserializeKey(final Object input) throws SerializationException { ++ final @Nullable ResourceLocation key = ResourceLocation.tryParse(input.toString()); ++ if (key == null) { ++ throw new SerializationException("Could not create a key from " + input); ++ } ++ return ResourceKey.create(this.registry.key(), key); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryHolderSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryHolderSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryHolderSerializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.serializer.registry; ++ ++import com.google.common.base.Preconditions; ++import io.leangen.geantyref.TypeFactory; ++import io.leangen.geantyref.TypeToken; ++import net.minecraft.core.Holder; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.util.function.Function; ++ ++public final class RegistryHolderSerializer extends RegistryEntrySerializer, T> { ++ ++ @SuppressWarnings("unchecked") ++ public RegistryHolderSerializer(TypeToken typeToken, Registry registry, boolean omitMinecraftNamespace) { ++ super((TypeToken>) TypeToken.get(TypeFactory.parameterizedClass(Holder.class, typeToken.getType())), registry, omitMinecraftNamespace); ++ } ++ ++ public RegistryHolderSerializer(Class type, Registry registry, boolean omitMinecraftNamespace) { ++ this(TypeToken.get(type), registry, omitMinecraftNamespace); ++ Preconditions.checkArgument(type.getTypeParameters().length == 0, "%s must have 0 type parameters", type); ++ } ++ ++ @Override ++ protected Holder convertFromResourceKey(ResourceKey key) throws SerializationException { ++ return this.registry().getHolder(key).orElseThrow(() -> new SerializationException("Missing holder in " + this.registry().key() + " with key " + key)); ++ } ++ ++ @Override ++ protected ResourceKey convertToResourceKey(Holder value) { ++ return value.unwrap().map(Function.identity(), r -> this.registry().getResourceKey(r).orElseThrow()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryValueSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryValueSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryValueSerializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.serializer.registry; ++ ++import io.leangen.geantyref.TypeToken; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++/** ++ * Use {@link RegistryHolderSerializer} for datapack-configurable things. ++ */ ++public final class RegistryValueSerializer extends RegistryEntrySerializer { ++ ++ public RegistryValueSerializer(TypeToken type, Registry registry, boolean omitMinecraftNamespace) { ++ super(type, registry, omitMinecraftNamespace); ++ } ++ ++ public RegistryValueSerializer(Class type, Registry registry, boolean omitMinecraftNamespace) { ++ super(type, registry, omitMinecraftNamespace); ++ } ++ ++ @Override ++ protected T convertFromResourceKey(ResourceKey key) throws SerializationException { ++ final T value = this.registry().get(key); ++ if (value == null) { ++ throw new SerializationException("Missing value in " + this.registry() + " with key " + key.location()); ++ } ++ return value; ++ } ++ ++ @Override ++ protected ResourceKey convertToResourceKey(T value) { ++ return this.registry().getResourceKey(value).orElseThrow(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/transformation/Transformations.java b/src/main/java/io/papermc/paper/configuration/transformation/Transformations.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/transformation/Transformations.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.transformation; ++ ++import org.spongepowered.configurate.NodePath; ++import org.spongepowered.configurate.transformation.ConfigurationTransformation; ++ ++import static org.spongepowered.configurate.NodePath.path; ++ ++public final class Transformations { ++ private Transformations() { ++ } ++ ++ public static void moveFromRoot(final ConfigurationTransformation.Builder builder, final String key, final String... parents) { ++ moveFromRootAndRename(builder, key, key, parents); ++ } ++ ++ public static void moveFromRootAndRename(final ConfigurationTransformation.Builder builder, final String oldKey, final String newKey, final String... parents) { ++ moveFromRootAndRename(builder, path(oldKey), newKey, parents); ++ } ++ ++ public static void moveFromRootAndRename(final ConfigurationTransformation.Builder builder, final NodePath oldKey, final String newKey, final String... parents) { ++ builder.addAction(oldKey, (path, value) -> { ++ final Object[] newPath = new Object[parents.length + 1]; ++ newPath[parents.length] = newKey; ++ System.arraycopy(parents, 0, newPath, 0, parents.length); ++ return newPath; ++ }); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/transformation/global/LegacyPaperConfig.java b/src/main/java/io/papermc/paper/configuration/transformation/global/LegacyPaperConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/transformation/global/LegacyPaperConfig.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.transformation.global; ++ ++import com.mojang.logging.LogUtils; ++import io.papermc.paper.configuration.Configuration; ++import io.papermc.paper.configuration.serializer.PacketClassSerializer; ++import io.papermc.paper.util.ObfHelper; ++import net.minecraft.network.protocol.Packet; ++import org.bukkit.configuration.file.YamlConfiguration; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.slf4j.Logger; ++import org.spongepowered.configurate.BasicConfigurationNode; ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.transformation.ConfigurationTransformation; ++import org.spongepowered.configurate.transformation.TransformAction; ++ ++import static org.spongepowered.configurate.NodePath.path; ++ ++public final class LegacyPaperConfig { ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ private static final PacketClassSerializer PACKET_CLASS_SERIALIZER = new PacketClassSerializer(); ++ ++ private LegacyPaperConfig() { ++ } ++ ++ public static ConfigurationTransformation transformation(final YamlConfiguration spigotConfiguration) { ++ return ConfigurationTransformation.chain(versioned(), notVersioned(spigotConfiguration)); ++ } ++ ++ // Represents version transforms lifted directly from the old PaperConfig class ++ // must be run BEFORE the "settings" flatten ++ private static ConfigurationTransformation.Versioned versioned() { ++ return ConfigurationTransformation.versionedBuilder() ++ .versionKey(Configuration.LEGACY_CONFIG_VERSION_FIELD) ++ .addVersion(11, ConfigurationTransformation.builder().addAction(path("settings", "play-in-use-item-spam-threshold"), TransformAction.rename("incoming-packet-spam-threshold")).build()) ++ .addVersion(14, ConfigurationTransformation.builder().addAction(path("settings", "spam-limiter", "tab-spam-increment"), (path, value) -> { ++ if (value.getInt() == 10) { ++ value.set(2); ++ } ++ return null; ++ }).build()) ++ .addVersion(15, ConfigurationTransformation.builder().addAction(path("settings"), (path, value) -> { ++ value.node("async-chunks", "threads").set(-1); ++ return null; ++ }).build()) ++ .addVersion(21, ConfigurationTransformation.builder().addAction(path("use-display-name-in-quit-message"), (path, value) -> new Object[]{"settings", "use-display-name-in-quit-message"}).build()) ++ .addVersion(23, ConfigurationTransformation.builder().addAction(path("settings", "chunk-loading", "global-max-chunk-load-rate"), (path, value) -> { ++ if (value.getDouble() == 300.0) { ++ value.set(-1.0); ++ } ++ return null; ++ }).build()) ++ .addVersion(25, ConfigurationTransformation.builder().addAction(path("settings", "chunk-loading", "player-max-concurrent-loads"), (path, value) -> { ++ if (value.getDouble() == 4.0) { ++ value.set(20.0); ++ } ++ return null; ++ }).build()) ++ .build(); ++ } ++ ++ // other non-versioned transforms found in PaperConfig ++ // must be run BEFORE the "settings" flatten ++ private static ConfigurationTransformation notVersioned(final YamlConfiguration spigotConfiguration) { ++ return ConfigurationTransformation.builder() ++ .addAction(path("settings"), (path, value) -> { ++ final ConfigurationNode node = value.node("async-chunks"); ++ if (node.hasChild("load-threads")) { ++ if (!node.hasChild("threads")) { ++ node.node("threads").set(node.node("load-threads").getInt()); ++ } ++ node.removeChild("load-threads"); ++ } ++ node.removeChild("generation"); ++ node.removeChild("enabled"); ++ node.removeChild("thread-per-world-generation"); ++ return null; ++ }) ++ .addAction(path("allow-perm-block-break-exploits"), (path, value) -> new Object[]{"settings", "unsupported-settings", "allow-permanent-block-break-exploits"}) ++ .addAction(path("settings", "unsupported-settings", "allow-tnt-duplication"), TransformAction.rename("allow-piston-duplication")) ++ .addAction(path("settings", "save-player-data"), (path, value) -> { ++ final @Nullable Object val = value.raw(); ++ if (val instanceof Boolean bool) { ++ spigotConfiguration.set("players.disable-saving", !bool); ++ } ++ value.raw(null); ++ return null; ++ }) ++ .addAction(path("settings", "log-named-entity-deaths"), (path, value) -> { ++ final @Nullable Object val = value.raw(); ++ if (val instanceof Boolean bool && !bool) { ++ spigotConfiguration.set("settings.log-named-deaths", false); ++ } ++ value.raw(null); ++ return null; ++ }) ++ .build(); ++ } ++ ++ // transforms to new format with configurate ++ // must be run AFTER the "settings" flatten ++ public static ConfigurationTransformation toNewFormat() { ++ return ConfigurationTransformation.chain( ++ ConfigurationTransformation.versionedBuilder().versionKey(Configuration.LEGACY_CONFIG_VERSION_FIELD).addVersion(Configuration.FINAL_LEGACY_VERSION + 1, newFormatTransformation()).build(), ++ ConfigurationTransformation.builder().addAction(path(Configuration.LEGACY_CONFIG_VERSION_FIELD), TransformAction.rename(Configuration.VERSION_FIELD)).build() // rename to _version to place at the top ++ ); ++ } ++ ++ private static ConfigurationTransformation newFormatTransformation() { ++ final ConfigurationTransformation.Builder builder = ConfigurationTransformation.builder() ++ .addAction(path("verbose"), TransformAction.remove()) // not needed ++ .addAction(path("unsupported-settings", "allow-headless-pistons-readme"), TransformAction.remove()) ++ .addAction(path("unsupported-settings", "allow-permanent-block-break-exploits-readme"), TransformAction.remove()) ++ .addAction(path("unsupported-settings", "allow-piston-duplication-readme"), TransformAction.remove()) ++ .addAction(path("packet-limiter", "limits", "all"), (path, value) -> new Object[]{"packet-limiter", "all-packets"}) ++ .addAction(path("packet-limiter", "limits"), (path, value) -> new Object[]{"packet-limiter", "overrides"}) ++ .addAction(path("packet-limiter", "overrides", ConfigurationTransformation.WILDCARD_OBJECT), (path, value) -> { ++ if (ObfHelper.INSTANCE.mappingsByObfName() != null) { // requires mappings to be present ++ final Class> packet = PACKET_CLASS_SERIALIZER.deserialize(Void.TYPE /* doesn't matter */, BasicConfigurationNode.root(value.options()).set(value.key())); ++ final Object[] newPath = new Object[path.size()]; ++ newPath[path.size() - 1] = packet.getSimpleName(); ++ return newPath; ++ } else { ++ LOGGER.warn("Could not convert spigot-mapped packet class names because no mappings were found in the jar"); ++ } ++ return null; ++ }).addAction(path("loggers"), TransformAction.rename("logging")); ++ ++ moveFromRootAndRename(builder, "incoming-packet-spam-threshold", "incoming-packet-threshold", "spam-limiter"); ++ ++ moveFromRoot(builder, "save-empty-scoreboard-teams", "scoreboards"); ++ moveFromRoot(builder, "track-plugin-scoreboards", "scoreboards"); ++ ++ moveFromRoot(builder, "suggest-player-names-when-null-tab-completions", "commands"); ++ moveFromRoot(builder, "time-command-affects-all-worlds", "commands"); ++ moveFromRoot(builder, "fix-target-selector-tag-completion", "commands"); ++ ++ moveFromRoot(builder, "log-player-ip-addresses", "loggers"); ++ ++ moveFromRoot(builder, "use-display-name-in-quit-message", "messages"); ++ ++ moveFromRootAndRename(builder, "console-has-all-permissions", "has-all-permissions", "console"); ++ ++ moveFromRootAndRename(builder, "bungee-online-mode", "online-mode", "proxies", "bungee-cord"); ++ moveFromRootAndRename(builder, "velocity-support", "velocity", "proxies"); ++ ++ moveFromRoot(builder, "book-size", "item-validation"); ++ moveFromRoot(builder, "resolve-selectors-in-books", "item-validation"); ++ ++ moveFromRoot(builder, "enable-player-collisions", "collisions"); ++ moveFromRoot(builder, "send-full-pos-for-hard-colliding-entities", "collisions"); ++ ++ moveFromRootAndRename(builder, "player-auto-save-rate", "rate", "player-auto-save"); ++ moveFromRootAndRename(builder, "max-player-auto-save-per-tick", "max-per-tick", "player-auto-save"); ++ ++ moveFromRootToMisc(builder, "max-joins-per-tick"); ++ moveFromRootToMisc(builder, "fix-entity-position-desync"); ++ moveFromRootToMisc(builder, "load-permissions-yml-before-plugins"); ++ moveFromRootToMisc(builder, "region-file-cache-size"); ++ moveFromRootToMisc(builder, "use-alternative-luck-formula"); ++ moveFromRootToMisc(builder, "lag-compensate-block-breaking"); ++ moveFromRootToMisc(builder, "use-dimension-type-for-custom-spawners"); ++ ++ moveFromRoot(builder, "proxy-protocol", "proxies"); ++ ++ return builder.build(); ++ } ++ ++ private static void moveFromRootToMisc(final ConfigurationTransformation.Builder builder, String key) { ++ moveFromRoot(builder, key, "misc"); ++ } ++ ++ private static void moveFromRoot(final ConfigurationTransformation.Builder builder, final String key, final String... parents) { ++ moveFromRootAndRename(builder, key, key, parents); ++ } ++ ++ private static void moveFromRootAndRename(final ConfigurationTransformation.Builder builder, final String oldKey, final String newKey, final String... parents) { ++ builder.addAction(path(oldKey), (path, value) -> { ++ final Object[] newPath = new Object[parents.length + 1]; ++ newPath[parents.length] = newKey; ++ System.arraycopy(parents, 0, newPath, 0, parents.length); ++ return newPath; ++ }); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/LegacyPaperWorldConfig.java b/src/main/java/io/papermc/paper/configuration/transformation/world/LegacyPaperWorldConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/transformation/world/LegacyPaperWorldConfig.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.transformation.world; ++ ++import io.papermc.paper.configuration.Configuration; ++import io.papermc.paper.configuration.WorldConfiguration; ++import net.minecraft.core.Holder; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.world.entity.MobCategory; ++import net.minecraft.world.item.Item; ++import org.bukkit.Material; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.transformation.ConfigurationTransformation; ++import org.spongepowered.configurate.transformation.TransformAction; ++ ++import java.util.List; ++import java.util.Optional; ++ ++import static io.papermc.paper.configuration.transformation.Transformations.moveFromRoot; ++import static io.papermc.paper.configuration.transformation.Transformations.moveFromRootAndRename; ++import static org.spongepowered.configurate.NodePath.path; ++ ++public final class LegacyPaperWorldConfig { ++ ++ private LegacyPaperWorldConfig() { ++ } ++ ++ public static ConfigurationTransformation transformation() { ++ return ConfigurationTransformation.chain(versioned(), notVersioned()); ++ } ++ ++ private static ConfigurationTransformation.Versioned versioned() { ++ return ConfigurationTransformation.versionedBuilder().versionKey(Configuration.LEGACY_CONFIG_VERSION_FIELD) ++ .addVersion(13, ConfigurationTransformation.builder().addAction(path("enable-old-tnt-cannon-behaviors"), TransformAction.rename("prevent-tnt-from-moving-in-water")).build()).addVersion(16, ConfigurationTransformation.builder().addAction(path("use-chunk-inhabited-timer"), (path, value) -> { ++ if (!value.getBoolean(true)) { ++ value.raw(0); ++ } ++ final Object[] newPath = path.array(); ++ newPath[newPath.length - 1] = "fixed-chunk-inhabited-time"; ++ return newPath; ++ }).build()) ++ .addVersion(18, ConfigurationTransformation.builder().addAction(path("nether-ceiling-void-damage"), (path, value) -> { ++ if (value.getBoolean(false)) { ++ value.raw(128); ++ } ++ final Object[] newPath = path.array(); ++ newPath[newPath.length - 1] = "nether-ceiling-void-damage-height"; ++ return newPath; ++ }).build()) ++ .addVersion(19, ConfigurationTransformation.builder() ++ .addAction(path("anti-xray", "hidden-blocks"), (path, value) -> { ++ @Nullable final List hiddenBlocks = value.getList(String.class); ++ if (hiddenBlocks != null) { ++ hiddenBlocks.remove("lit_redstone_ore"); ++ } ++ return null; ++ }) ++ .addAction(path("anti-xray", "replacement-blocks"), (path, value) -> { ++ @Nullable final List replacementBlocks = value.getList(String.class); ++ if (replacementBlocks != null) { ++ final int index = replacementBlocks.indexOf("planks"); ++ if (index != -1) { ++ replacementBlocks.set(index, "oak_planks"); ++ } ++ } ++ value.raw(replacementBlocks); ++ return null; ++ }).build()) ++ .addVersion(20, ConfigurationTransformation.builder().addAction(path("baby-zombie-movement-speed"), TransformAction.rename("baby-zombie-movement-modifier")).build()) ++ .addVersion(22, ConfigurationTransformation.builder().addAction(path("per-player-mob-spawns"), (path, value) -> { ++ value.raw(true); ++ return null; ++ }).build()) ++ .addVersion(24, ++ ConfigurationTransformation.builder() ++ .addAction(path("spawn-limits", "monsters"), TransformAction.rename("monster")) ++ .addAction(path("spawn-limits", "animals"), TransformAction.rename("creature")) ++ .addAction(path("spawn-limits", "water-animals"), TransformAction.rename("water_creature")) ++ .addAction(path("spawn-limits", "water-ambient"), TransformAction.rename("water_ambient")) ++ .build(), ++ ConfigurationTransformation.builder().addAction(path("despawn-ranges"), (path, value) -> { ++ final int softDistance = value.node("soft").getInt(32); ++ final int hardDistance = value.node("hard").getInt(128); ++ value.node("soft").raw(null); ++ value.node("hard").raw(null); ++ for (final MobCategory category : MobCategory.values()) { ++ if (softDistance != 32) { ++ value.node(category.getName(), "soft").raw(softDistance); ++ } ++ if (hardDistance != 128) { ++ value.node(category.getName(), "hard").raw(hardDistance); ++ } ++ } ++ return null; ++ }).build() ++ ) ++ .addVersion(26, ConfigurationTransformation.builder().addAction(path("alt-item-despawn-rate", "items", ConfigurationTransformation.WILDCARD_OBJECT), (path, value) -> { ++ String itemName = path.get(path.size() - 1).toString(); ++ final Optional> item = Registry.ITEM.getHolder(ResourceKey.create(Registry.ITEM_REGISTRY, new ResourceLocation(itemName))); ++ if (item.isEmpty()) { ++ itemName = Material.valueOf(itemName).getKey().toString(); ++ } ++ final Object[] newPath = path.array(); ++ newPath[newPath.length - 1] = itemName; ++ return newPath; ++ }).build()) ++ .addVersion(27, ConfigurationTransformation.builder().addAction(path("use-faster-eigencraft-redstone"), (path, value) -> { ++ final WorldConfiguration.Misc.RedstoneImplementation redstoneImplementation = value.getBoolean(false) ? WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT : WorldConfiguration.Misc.RedstoneImplementation.VANILLA; ++ value.raw(redstoneImplementation); ++ final Object[] newPath = path.array(); ++ newPath[newPath.length - 1] = "redstone-implementation"; ++ return newPath; ++ }).build()) ++ .build(); ++ } ++ ++ // other transformations found in PaperWorldConfig that aren't versioned ++ private static ConfigurationTransformation notVersioned() { ++ return ConfigurationTransformation.builder() ++ .addAction(path("treasure-maps-return-already-discovered"), (path, value) -> { ++ boolean prevValue = value.getBoolean(false); ++ value.node("villager-trade").set(prevValue); ++ value.node("loot-tables").set(prevValue); ++ return path.with(path.size() - 1, "treasure-maps-find-already-discovered").array(); ++ }) ++ .build(); ++ } ++ ++ public static ConfigurationTransformation toNewFormat() { ++ return ConfigurationTransformation.chain(ConfigurationTransformation.versionedBuilder().versionKey(Configuration.LEGACY_CONFIG_VERSION_FIELD).addVersion(Configuration.FINAL_LEGACY_VERSION + 1, newFormatTransformation()).build(), ConfigurationTransformation.builder().addAction(path(Configuration.LEGACY_CONFIG_VERSION_FIELD), TransformAction.rename(Configuration.VERSION_FIELD)).build()); ++ } ++ ++ private static ConfigurationTransformation newFormatTransformation() { ++ final ConfigurationTransformation.Builder builder = ConfigurationTransformation.builder(); ++ ++ moveFromRoot(builder, "anti-xray", "anticheat"); ++ ++ moveFromRootAndRename(builder, "armor-stands-do-collision-entity-lookups", "do-collision-entity-lookups", "entities", "armor-stands"); ++ moveFromRootAndRename(builder, "armor-stands-tick", "tick", "entities", "armor-stands"); ++ ++ moveFromRoot(builder, "auto-save-interval", "chunks"); ++ moveFromRoot(builder, "delay-chunk-unloads-by", "chunks"); ++ moveFromRoot(builder, "entity-per-chunk-save-limit", "chunks"); ++ moveFromRoot(builder, "fixed-chunk-inhabited-time", "chunks"); ++ moveFromRoot(builder, "max-auto-save-chunks-per-tick", "chunks"); ++ moveFromRoot(builder, "prevent-moving-into-unloaded-chunks", "chunks"); ++ ++ moveFromRoot(builder, "entities-target-with-follow-range", "entities"); ++ moveFromRoot(builder, "mob-effects", "entities"); ++ ++ moveFromRoot(builder, "filter-nbt-data-from-spawn-eggs-and-related", "entities", "spawning"); ++ moveFromGameMechanics(builder, "disable-mob-spawner-spawn-egg-transformation", "entities", "spawning"); ++ moveFromRoot(builder, "per-player-mob-spawns", "entities", "spawning"); ++ moveFromGameMechanics(builder, "scan-for-legacy-ender-dragon", "entities", "spawning"); ++ moveFromRoot(builder, "spawn-limits", "entities", "spawning"); ++ moveFromRoot(builder, "despawn-ranges", "entities", "spawning"); ++ moveFromRoot(builder, "wateranimal-spawn-height", "entities", "spawning"); ++ moveFromRoot(builder, "slime-spawn-height", "entities", "spawning"); ++ moveFromRoot(builder, "wandering-trader", "entities", "spawning"); ++ moveFromRoot(builder, "all-chunks-are-slime-chunks", "entities", "spawning"); ++ moveFromRoot(builder, "skeleton-horse-thunder-spawn-chance", "entities", "spawning"); ++ moveFromRoot(builder, "iron-golems-can-spawn-in-air", "entities", "spawning"); ++ moveFromRoot(builder, "alt-item-despawn-rate", "entities", "spawning"); ++ moveFromRoot(builder, "count-all-mobs-for-spawning", "entities", "spawning"); ++ moveFromRoot(builder, "creative-arrow-despawn-rate", "entities", "spawning"); ++ moveFromRoot(builder, "non-player-arrow-despawn-rate", "entities", "spawning"); ++ moveFromRoot(builder, "monster-spawn-max-light-level", "entities", "spawning"); ++ ++ ++ moveFromRootAndRename(builder, "duplicate-uuid-saferegen-delete-range", "safe-regen-delete-range", "entities", "spawning", "duplicate-uuid"); ++ ++ moveFromRoot(builder, "baby-zombie-movement-modifier", "entities", "behavior"); ++ moveFromRoot(builder, "disable-creeper-lingering-effect", "entities", "behavior"); ++ moveFromRoot(builder, "door-breaking-difficulty", "entities", "behavior"); ++ moveFromGameMechanics(builder, "disable-chest-cat-detection", "entities", "behavior"); ++ moveFromGameMechanics(builder, "disable-player-crits", "entities", "behavior"); ++ moveFromRoot(builder, "experience-merge-max-value", "entities", "behavior"); ++ moveFromRoot(builder, "mobs-can-always-pick-up-loot", "entities", "behavior"); ++ moveFromGameMechanics(builder, "nerf-pigmen-from-nether-portals", "entities", "behavior"); ++ moveFromRoot(builder, "parrots-are-unaffected-by-player-movement", "entities", "behavior"); ++ moveFromRoot(builder, "phantoms-do-not-spawn-on-creative-players", "entities", "behavior"); ++ moveFromRoot(builder, "phantoms-only-attack-insomniacs", "entities", "behavior"); ++ moveFromRoot(builder, "piglins-guard-chests", "entities", "behavior"); ++ moveFromRoot(builder, "spawner-nerfed-mobs-should-jump", "entities", "behavior"); ++ moveFromRoot(builder, "zombie-villager-infection-chance", "entities", "behavior"); ++ moveFromRoot(builder, "zombies-target-turtle-eggs", "entities", "behavior"); ++ moveFromRoot(builder, "ender-dragons-death-always-places-dragon-egg", "entities", "behavior"); ++ moveFromGameMechanicsAndRename(builder, "disable-pillager-patrols", "disable", "game-mechanics", "pillager-patrols"); ++ moveFromGameMechanics(builder, "pillager-patrols", "entities", "behavior"); ++ moveFromRoot(builder, "should-remove-dragon", "entities", "behavior"); ++ ++ moveFromRootAndRename(builder, "map-item-frame-cursor-limit", "item-frame-cursor-limit", "maps"); ++ moveFromRootAndRename(builder, "map-item-frame-cursor-update-interval", "item-frame-cursor-update-interval", "maps"); ++ ++ moveFromRootAndRename(builder, "mob-spawner-tick-rate", "mob-spawner", "tick-rates"); ++ moveFromRootAndRename(builder, "container-update-tick-rate", "container-update", "tick-rates"); ++ moveFromRootAndRename(builder, "grass-spread-tick-rate", "grass-spread", "tick-rates"); ++ ++ moveFromRoot(builder, "allow-non-player-entities-on-scoreboards", "scoreboards"); ++ moveFromRoot(builder, "use-vanilla-world-scoreboard-name-coloring", "scoreboards"); ++ ++ moveFromRoot(builder, "disable-thunder", "environment"); ++ moveFromRoot(builder, "disable-ice-and-snow", "environment"); ++ moveFromRoot(builder, "optimize-explosions", "environment"); ++ moveFromRoot(builder, "disable-explosion-knockback", "environment"); ++ moveFromRoot(builder, "frosted-ice", "environment"); ++ moveFromRoot(builder, "disable-teleportation-suffocation-check", "environment"); ++ moveFromRoot(builder, "portal-create-radius", "environment"); ++ moveFromRoot(builder, "portal-search-radius", "environment"); ++ moveFromRoot(builder, "portal-search-vanilla-dimension-scaling", "environment"); ++ moveFromRootAndRename(builder, "enable-treasure-maps", "enabled", "environment", "treasure-maps"); ++ moveFromRootAndRename(builder, "treasure-maps-find-already-discovered", "find-already-discovered", "environment", "treasure-maps"); ++ moveFromRoot(builder, "water-over-lava-flow-speed", "environment"); ++ moveFromRoot(builder, "nether-ceiling-void-damage-height", "environment"); ++ ++ moveFromRoot(builder, "keep-spawn-loaded", "spawn"); ++ moveFromRoot(builder, "keep-spawn-loaded-range", "spawn"); ++ moveFromRoot(builder, "allow-using-signs-inside-spawn-protection", "spawn"); ++ ++ moveFromRoot(builder, "max-entity-collisions", "collisions"); ++ moveFromRoot(builder, "allow-vehicle-collisions", "collisions"); ++ moveFromRoot(builder, "fix-climbing-bypassing-cramming-rule", "collisions"); ++ moveFromRoot(builder, "only-players-collide", "collisions"); ++ moveFromRoot(builder, "allow-player-cramming-damage", "collisions"); ++ ++ moveFromRoot(builder, "falling-block-height-nerf", "fixes"); ++ moveFromRoot(builder, "fix-items-merging-through-walls", "fixes"); ++ moveFromRoot(builder, "prevent-tnt-from-moving-in-water", "fixes"); ++ moveFromRoot(builder, "remove-corrupt-tile-entities", "fixes"); ++ moveFromRoot(builder, "split-overstacked-loot", "fixes"); ++ moveFromRoot(builder, "tnt-entity-height-nerf", "fixes"); ++ moveFromGameMechanics(builder, "disable-unloaded-chunk-enderpearl-exploit", "fixes"); ++ moveFromGameMechanics(builder, "fix-curing-zombie-villager-discount-exploit", "fixes"); ++ ++ builder.addAction(path("fishing-time-range", "MaximumTicks"), TransformAction.rename("maximum")); ++ builder.addAction(path("fishing-time-range", "MinimumTicks"), TransformAction.rename("minimum")); ++ ++ builder.addAction(path("generator-settings", "flat-bedrock"), (path, value) -> new Object[]{"environment", "generate-flat-bedrock"}); ++ builder.addAction(path("generator-settings"), TransformAction.remove()); ++ ++ builder.addAction(path("game-mechanics", ConfigurationTransformation.WILDCARD_OBJECT), (path, value) -> new Object[]{"misc", path.array()[1]}); ++ builder.addAction(path("game-mechanics"), TransformAction.remove()); ++ ++ builder.addAction(path("feature-seeds", ConfigurationTransformation.WILDCARD_OBJECT), (path, value) -> { ++ final String key = path.array()[path.size() - 1].toString(); ++ if (!key.equals("generate-random-seeds-for-all")) { ++ return new Object[]{"feature-seeds", "features", key}; ++ } ++ return null; ++ }); ++ ++ builder.addAction(path("duplicate-uuid-resolver"), (path, value) -> { ++ final WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode duplicateUUIDMode = switch (value.require(String.class)) { ++ case "regen", "regenerate", "saferegen", "saferegenerate" -> WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.SAFE_REGEN; ++ case "remove", "delete" -> WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.DELETE; ++ case "silent", "nothing" -> WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.NOTHING; ++ default -> WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.WARN; ++ }; ++ value.set(duplicateUUIDMode); ++ return new Object[]{"entities", "spawning", "duplicate-uuid", "mode"}; ++ }); ++ ++ moveToMisc(builder, "light-queue-size"); ++ moveToMisc(builder, "update-pathfinding-on-block-update"); ++ moveToMisc(builder, "show-sign-click-command-failure-msgs-to-player"); ++ moveToMisc(builder, "redstone-implementation"); ++ moveToMisc(builder, "max-leash-distance"); ++ ++ return builder.build(); ++ } ++ ++ private static void moveToMisc(final ConfigurationTransformation.Builder builder, String... key) { ++ moveFromRootAndRename(builder, path((Object[]) key), key[key.length - 1], "misc"); ++ } ++ ++ private static void moveFromGameMechanics(final ConfigurationTransformation.Builder builder, final String key, final String... parents) { ++ moveFromGameMechanicsAndRename(builder, key, key, parents); ++ } ++ ++ private static void moveFromGameMechanicsAndRename(final ConfigurationTransformation.Builder builder, final String oldKey, final String newKey, final String... parents) { ++ moveFromRootAndRename(builder, path("game-mechanics", oldKey), newKey, parents); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java b/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.type; ++ ++import org.apache.commons.lang3.BooleanUtils; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.lang.reflect.Type; ++import java.util.Locale; ++import java.util.function.Predicate; ++ ++public record BooleanOrDefault(@Nullable Boolean value) { ++ private static final String DEFAULT_VALUE = "default"; ++ public static final BooleanOrDefault USE_DEFAULT = new BooleanOrDefault(null); ++ public static final ScalarSerializer SERIALIZER = new Serializer(); ++ ++ public boolean or(boolean fallback) { ++ return this.value != null && this.value; ++ } ++ ++ private static final class Serializer extends ScalarSerializer { ++ Serializer() { ++ super(BooleanOrDefault.class); ++ } ++ ++ @Override ++ public BooleanOrDefault deserialize(Type type, Object obj) throws SerializationException { ++ if (obj instanceof String string) { ++ if (DEFAULT_VALUE.equalsIgnoreCase(string)) { ++ return USE_DEFAULT; ++ } ++ try { ++ return new BooleanOrDefault(BooleanUtils.toBoolean(string.toLowerCase(Locale.ENGLISH), "true", "false")); ++ } catch (IllegalArgumentException ex) { ++ throw new SerializationException(BooleanOrDefault.class, obj + "(" + type + ") is not a boolean or '" + DEFAULT_VALUE + "'", ex); ++ } ++ } else if (obj instanceof Boolean bool) { ++ return new BooleanOrDefault(bool); ++ } ++ throw new SerializationException(obj + "(" + type + ") is not a boolean or '" + DEFAULT_VALUE + "'"); ++ } ++ ++ @Override ++ protected Object serialize(BooleanOrDefault item, Predicate> typeSupported) { ++ final @Nullable Boolean value = item.value; ++ if (value != null) { ++ return value.toString(); ++ } else { ++ return DEFAULT_VALUE; ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/type/DoubleOrDefault.java b/src/main/java/io/papermc/paper/configuration/type/DoubleOrDefault.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/type/DoubleOrDefault.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.type; ++ ++import org.apache.commons.lang3.math.NumberUtils; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.lang.reflect.Type; ++import java.util.OptionalDouble; ++import java.util.function.Predicate; ++ ++public final class DoubleOrDefault { ++ private static final String DEFAULT_VALUE = "default"; ++ public static final DoubleOrDefault USE_DEFAULT = new DoubleOrDefault(OptionalDouble.empty()); ++ public static final ScalarSerializer SERIALIZER = new Serializer(); ++ ++ private OptionalDouble value; ++ ++ public DoubleOrDefault(final OptionalDouble value) { ++ this.value = value; ++ } ++ ++ public OptionalDouble value() { ++ return this.value; ++ } ++ ++ public void value(final OptionalDouble value) { ++ this.value = value; ++ } ++ ++ public double or(final double fallback) { ++ return this.value.orElse(fallback); ++ } ++ ++ private static final class Serializer extends ScalarSerializer { ++ Serializer() { ++ super(DoubleOrDefault.class); ++ } ++ ++ @Override ++ public DoubleOrDefault deserialize(final Type type, final Object obj) throws SerializationException { ++ if (obj instanceof String string) { ++ if (DEFAULT_VALUE.equalsIgnoreCase(string)) { ++ return USE_DEFAULT; ++ } ++ if (NumberUtils.isParsable(string)) { ++ return new DoubleOrDefault(OptionalDouble.of(Double.parseDouble(string))); ++ } ++ } else if (obj instanceof Double num) { ++ return new DoubleOrDefault(OptionalDouble.of(num)); ++ } ++ throw new SerializationException(obj + " is of an unexpected type " + type); ++ } ++ ++ @Override ++ protected Object serialize(final DoubleOrDefault item, final Predicate> typeSupported) { ++ final OptionalDouble value = item.value(); ++ if (value.isPresent()) { ++ return value.getAsDouble(); ++ } else { ++ return DEFAULT_VALUE; ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/type/Duration.java b/src/main/java/io/papermc/paper/configuration/type/Duration.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/type/Duration.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.type; ++ ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.lang.reflect.Type; ++import java.util.Objects; ++import java.util.function.Predicate; ++import java.util.regex.Pattern; ++ ++public final class Duration { ++ + private static final Pattern SPACE = Pattern.compile(" "); + private static final Pattern NOT_NUMERIC = Pattern.compile("[^-\\d.]"); -+ public static int getSeconds(String str) { ++ public static final Serializer SERIALIZER = new Serializer(); ++ ++ private final long seconds; ++ private final String value; ++ ++ private Duration(String value) { ++ this.value = value; ++ this.seconds = getSeconds(value); ++ } ++ ++ public long seconds() { ++ return this.seconds; ++ } ++ ++ public long ticks() { ++ return this.seconds * 20; ++ } ++ ++ public String value() { ++ return this.value; ++ } ++ ++ @Override ++ public boolean equals(@Nullable Object o) { ++ if (this == o) return true; ++ if (o == null || getClass() != o.getClass()) return false; ++ Duration duration = (Duration) o; ++ return seconds == duration.seconds && this.value.equals(duration.value); ++ } ++ ++ @Override ++ public int hashCode() { ++ return Objects.hash(this.seconds, this.value); ++ } ++ ++ @Override ++ public String toString() { ++ return "Duration{" + ++ "seconds=" + this.seconds + ++ ", value='" + this.value + '\'' + ++ '}'; ++ } ++ ++ public static Duration of(String time) { ++ return new Duration(time); ++ } ++ ++ private static int getSeconds(String str) { + str = SPACE.matcher(str).replaceAll(""); + final char unit = str.charAt(str.length() - 1); + str = NOT_NUMERIC.matcher(str).replaceAll(""); @@ -146,167 +3039,348 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return (int) num; + } + -+ protected static String timeSummary(int seconds) { -+ String time = ""; -+ -+ if (seconds > 60 * 60 * 24) { -+ time += TimeUnit.SECONDS.toDays(seconds) + "d"; -+ seconds %= 60 * 60 * 24; ++ private static final class Serializer extends ScalarSerializer { ++ private Serializer() { ++ super(Duration.class); + } + -+ if (seconds > 60 * 60) { -+ time += TimeUnit.SECONDS.toHours(seconds) + "h"; -+ seconds %= 60 * 60; ++ @Override ++ public Duration deserialize(Type type, Object obj) throws SerializationException { ++ return new Duration(obj.toString()); + } + -+ if (seconds > 0) { -+ time += TimeUnit.SECONDS.toMinutes(seconds) + "m"; ++ @Override ++ protected Object serialize(Duration item, Predicate> typeSupported) { ++ return item.value(); + } -+ return time; -+ } -+ -+ private static void set(String path, Object val) { -+ config.set(path, val); -+ } -+ -+ private static boolean getBoolean(String path, boolean def) { -+ config.addDefault(path, def); -+ return config.getBoolean(path, config.getBoolean(path)); -+ } -+ -+ private static double getDouble(String path, double def) { -+ config.addDefault(path, def); -+ return config.getDouble(path, config.getDouble(path)); -+ } -+ -+ private static float getFloat(String path, float def) { -+ // TODO: Figure out why getFloat() always returns the default value. -+ return (float) getDouble(path, (double) def); -+ } -+ -+ private static int getInt(String path, int def) { -+ config.addDefault(path, def); -+ return config.getInt(path, config.getInt(path)); -+ } -+ -+ private static List getList(String path, T def) { -+ config.addDefault(path, def); -+ return (List) config.getList(path, config.getList(path)); -+ } -+ -+ private static String getString(String path, String def) { -+ config.addDefault(path, def); -+ return config.getString(path, config.getString(path)); + } +} -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +diff --git a/src/main/java/io/papermc/paper/configuration/type/IntOrDefault.java b/src/main/java/io/papermc/paper/configuration/type/IntOrDefault.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 --- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/io/papermc/paper/configuration/type/IntOrDefault.java @@ -0,0 +0,0 @@ -+package com.destroystokyo.paper; ++package io.papermc.paper.configuration.type; + -+import java.util.List; ++import java.lang.reflect.Type; ++import java.util.OptionalInt; ++import java.util.function.Predicate; ++import org.apache.commons.lang3.math.NumberUtils; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++public record IntOrDefault(OptionalInt value) { ++ private static final String DEFAULT_VALUE = "default"; ++ public static final IntOrDefault USE_DEFAULT = new IntOrDefault(OptionalInt.empty()); ++ public static final ScalarSerializer SERIALIZER = new Serializer(); ++ ++ public int or(final int fallback) { ++ return this.value.orElse(fallback); ++ } ++ ++ private static final class Serializer extends ScalarSerializer { ++ Serializer() { ++ super(IntOrDefault.class); ++ } ++ ++ @Override ++ public IntOrDefault deserialize(final Type type, final Object obj) throws SerializationException { ++ if (obj instanceof String string) { ++ if (DEFAULT_VALUE.equalsIgnoreCase(string)) { ++ return USE_DEFAULT; ++ } ++ if (NumberUtils.isParsable(string)) { ++ return new IntOrDefault(OptionalInt.of(Integer.parseInt(string))); ++ } ++ } else if (obj instanceof Integer num) { ++ return new IntOrDefault(OptionalInt.of(num)); ++ } ++ throw new SerializationException(obj + "(" + type + ") is not a integer or '" + DEFAULT_VALUE + "'"); ++ } ++ ++ @Override ++ protected Object serialize(final IntOrDefault item, final Predicate> typeSupported) { ++ final OptionalInt value = item.value(); ++ if (value.isPresent()) { ++ return value.getAsInt(); ++ } else { ++ return DEFAULT_VALUE; ++ } ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/type/fallback/ArrowDespawnRate.java b/src/main/java/io/papermc/paper/configuration/type/fallback/ArrowDespawnRate.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/type/fallback/ArrowDespawnRate.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.type.fallback; + -+import java.util.stream.Collectors; -+import org.bukkit.Bukkit; -+import org.bukkit.configuration.file.YamlConfiguration; +import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.serialize.SerializationException; + -+import static com.destroystokyo.paper.PaperConfig.log; -+import static com.destroystokyo.paper.PaperConfig.logError; -+import static com.destroystokyo.paper.PaperConfig.saveConfig; ++import java.util.Map; ++import java.util.OptionalInt; ++import java.util.Set; + -+public class PaperWorldConfig { ++public class ArrowDespawnRate extends FallbackValue.Int { + -+ private final String worldName; -+ private final SpigotWorldConfig spigotConfig; -+ private YamlConfiguration config; -+ private boolean verbose; -+ -+ public PaperWorldConfig(String worldName, SpigotWorldConfig spigotConfig) { -+ this.worldName = worldName; -+ this.spigotConfig = spigotConfig; -+ this.config = PaperConfig.config; -+ init(); ++ ArrowDespawnRate(Map, Object> context, Object value) throws SerializationException { ++ super(context, fromObject(value)); + } + -+ public void init() { -+ this.config = PaperConfig.config; // grab updated reference -+ log("-------- World Settings For [" + worldName + "] --------"); -+ PaperConfig.readConfig(PaperWorldConfig.class, this); ++ private ArrowDespawnRate(Map, Object> context) { ++ super(context, OptionalInt.empty()); + } + -+ private void set(String path, Object val) { -+ config.set("world-settings.default." + path, val); -+ if (config.get("world-settings." + worldName + "." + path) != null) { -+ config.set("world-settings." + worldName + "." + path, val); ++ @Override ++ protected OptionalInt process(int value) { ++ return Util.negToDef(value); ++ } ++ ++ @Override ++ public Set> required() { ++ return Set.of(FallbackValue.SPIGOT_WORLD_CONFIG); ++ } ++ ++ @Override ++ protected int fallback() { ++ return this.get(FallbackValue.SPIGOT_WORLD_CONFIG).arrowDespawnRate; ++ } ++ ++ public static ArrowDespawnRate def(SpigotWorldConfig spigotConfig) { ++ return new ArrowDespawnRate(FallbackValue.SPIGOT_WORLD_CONFIG.singleton(spigotConfig)); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/type/fallback/AutosavePeriod.java b/src/main/java/io/papermc/paper/configuration/type/fallback/AutosavePeriod.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/type/fallback/AutosavePeriod.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.type.fallback; ++ ++import net.minecraft.server.MinecraftServer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.util.Map; ++import java.util.OptionalInt; ++import java.util.Set; ++import java.util.function.Supplier; ++ ++public class AutosavePeriod extends FallbackValue.Int { ++ ++ AutosavePeriod(Map, Object> contextMap, Object value) throws SerializationException { ++ super(contextMap, fromObject(value)); ++ } ++ ++ private AutosavePeriod(Map, Object> contextMap) { ++ super(contextMap, OptionalInt.empty()); ++ } ++ ++ @Override ++ protected OptionalInt process(int value) { ++ return Util.negToDef(value); ++ } ++ ++ @Override ++ protected Set> required() { ++ return Set.of(FallbackValue.MINECRAFT_SERVER); ++ } ++ ++ @Override ++ protected int fallback() { ++ return this.get(FallbackValue.MINECRAFT_SERVER).get().autosavePeriod; ++ } ++ ++ public static AutosavePeriod def() { ++ return new AutosavePeriod(FallbackValue.MINECRAFT_SERVER.singleton(MinecraftServer::getServer)); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/type/fallback/FallbackValue.java b/src/main/java/io/papermc/paper/configuration/type/fallback/FallbackValue.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/type/fallback/FallbackValue.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.type.fallback; ++ ++import com.google.common.base.Preconditions; ++import net.minecraft.server.MinecraftServer; ++import org.apache.commons.lang3.math.NumberUtils; ++import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.util.Map; ++import java.util.Objects; ++import java.util.OptionalInt; ++import java.util.Set; ++import java.util.function.Supplier; ++ ++public sealed abstract class FallbackValue permits FallbackValue.Int { ++ ++ private static final String DEFAULT_VALUE = "default"; ++ static final ContextKey SPIGOT_WORLD_CONFIG = new ContextKey<>("SpigotWorldConfig"); ++ static final ContextKey> MINECRAFT_SERVER = new ContextKey<>("MinecraftServer"); ++ ++ private final Map, Object> contextMap; ++ ++ protected FallbackValue(Map, Object> contextMap) { ++ for (ContextKey contextKey : this.required()) { ++ Preconditions.checkArgument(contextMap.containsKey(contextKey), contextMap + " is missing " + contextKey); ++ } ++ this.contextMap = contextMap; ++ } ++ ++ protected abstract String serialize(); ++ ++ protected abstract Set> required(); ++ ++ @SuppressWarnings("unchecked") ++ protected T get(ContextKey contextKey) { ++ return (T) Objects.requireNonNull(this.contextMap.get(contextKey), "Missing " + contextKey); ++ } ++ ++ public non-sealed abstract static class Int extends FallbackValue { ++ ++ private final OptionalInt value; ++ ++ Int(Map, Object> contextMap, OptionalInt value) { ++ super(contextMap); ++ if (value.isEmpty()) { ++ this.value = value; ++ } else { ++ this.value = this.process(value.getAsInt()); ++ } ++ } ++ ++ public int value() { ++ return value.orElseGet(this::fallback); ++ } ++ ++ @Override ++ protected final String serialize() { ++ return value.isPresent() ? String.valueOf(this.value.getAsInt()) : DEFAULT_VALUE; ++ } ++ ++ protected OptionalInt process(int value) { ++ return OptionalInt.of(value); ++ } ++ ++ protected abstract int fallback(); ++ ++ protected static OptionalInt fromObject(Object obj) throws SerializationException { ++ if (obj instanceof OptionalInt optionalInt) { ++ return optionalInt; ++ } else if (obj instanceof String string) { ++ if (DEFAULT_VALUE.equalsIgnoreCase(string)) { ++ return OptionalInt.empty(); ++ } ++ if (NumberUtils.isParsable(string)) { ++ return OptionalInt.of(Integer.parseInt(string)); ++ } ++ } else if (obj instanceof Integer num) { ++ return OptionalInt.of(num); ++ } ++ throw new SerializationException(obj + " is not a integer or '" + DEFAULT_VALUE + "'"); + } + } + -+ private void remove(String path) { -+ config.addDefault("world-settings.default." + path, null); -+ set(path, null); -+ } ++ static class ContextKey { + -+ public void removeOldValues() { -+ boolean needsSave = false; ++ private final String name; + -+ if (needsSave) { -+ saveConfig(); ++ ContextKey(String name) { ++ this.name = name; ++ } ++ ++ @Override ++ public String toString() { ++ return this.name; ++ } ++ ++ Map, Object> singleton(T value) { ++ return Map.of(this, value); + } + } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/type/fallback/FallbackValueSerializer.java b/src/main/java/io/papermc/paper/configuration/type/fallback/FallbackValueSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/type/fallback/FallbackValueSerializer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.type.fallback; + -+ private boolean getBoolean(String path, boolean def) { -+ return this.getBoolean(path, def, true); ++import net.minecraft.server.MinecraftServer; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spigotmc.SpigotWorldConfig; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++import java.lang.reflect.Type; ++import java.util.HashMap; ++import java.util.Map; ++import java.util.function.Predicate; ++import java.util.function.Supplier; ++ ++import static io.leangen.geantyref.GenericTypeReflector.erase; ++ ++public class FallbackValueSerializer extends ScalarSerializer { ++ ++ private static final Map, FallbackCreator> REGISTRY = new HashMap<>(); ++ ++ static { ++ REGISTRY.put(ArrowDespawnRate.class, ArrowDespawnRate::new); ++ REGISTRY.put(AutosavePeriod.class, AutosavePeriod::new); + } -+ private boolean getBoolean(String path, boolean def, boolean setDefault) { -+ if (setDefault) { -+ config.addDefault("world-settings.default." + path, def); ++ ++ FallbackValueSerializer(Map, Object> contextMap) { ++ super(FallbackValue.class); ++ this.contextMap = contextMap; ++ } ++ ++ @FunctionalInterface ++ private interface FallbackCreator { ++ T create(Map, Object> context, Object value) throws SerializationException; ++ } ++ ++ private final Map, Object> contextMap; ++ ++ @Override ++ public FallbackValue deserialize(Type type, Object obj) throws SerializationException { ++ final @Nullable FallbackCreator creator = REGISTRY.get(erase(type)); ++ if (creator == null) { ++ throw new SerializationException(type + " does not have a FallbackCreator registered"); + } -+ return config.getBoolean("world-settings." + worldName + "." + path, config.getBoolean("world-settings.default." + path, def)); ++ return creator.create(this.contextMap, obj); + } + -+ private double getDouble(String path, double def) { -+ config.addDefault("world-settings.default." + path, def); -+ return config.getDouble("world-settings." + worldName + "." + path, config.getDouble("world-settings.default." + path)); ++ @Override ++ protected Object serialize(FallbackValue item, Predicate> typeSupported) { ++ return item.serialize(); + } + -+ private int getInt(String path, int def) { -+ return getInt(path, def, true); ++ public static FallbackValueSerializer create(SpigotWorldConfig config, Supplier server) { ++ return new FallbackValueSerializer(Map.of(FallbackValue.SPIGOT_WORLD_CONFIG, config, FallbackValue.MINECRAFT_SERVER, server)); + } ++} +diff --git a/src/main/java/io/papermc/paper/configuration/type/fallback/Util.java b/src/main/java/io/papermc/paper/configuration/type/fallback/Util.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/type/fallback/Util.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration.type.fallback; + -+ private int getInt(String path, int def, boolean setDefault) { -+ if (setDefault) { -+ config.addDefault("world-settings.default." + path, def); -+ } -+ return config.getInt("world-settings." + worldName + "." + path, config.getInt("world-settings.default." + path, def)); -+ } ++import java.util.OptionalInt; + -+ private long getLong(String path, long def) { -+ config.addDefault("world-settings.default." + path, def); -+ return config.getLong("world-settings." + worldName + "." + path, config.getLong("world-settings.default." + path)); -+ } ++final class Util { + -+ private float getFloat(String path, float def) { -+ // TODO: Figure out why getFloat() always returns the default value. -+ return (float) getDouble(path, (double) def); -+ } -+ -+ private List getList(String path, List def) { -+ config.addDefault("world-settings.default." + path, def); -+ return (List) config.getList("world-settings." + worldName + "." + path, config.getList("world-settings.default." + path)); -+ } -+ -+ private String getString(String path, String def) { -+ config.addDefault("world-settings.default." + path, def); -+ return config.getString("world-settings." + worldName + "." + path, config.getString("world-settings.default." + path)); -+ } -+ -+ private > List getEnumList(String path, List def, Class type) { -+ config.addDefault("world-settings.default." + path, def.stream().map(Enum::name).collect(Collectors.toList())); -+ return ((List) (config.getList("world-settings." + worldName + "." + path, config.getList("world-settings.default." + path)))).stream().map(s -> Enum.valueOf(type, s)).collect(Collectors.toList()); ++ static OptionalInt negToDef(int value) { ++ return value < 0 ? OptionalInt.empty() : OptionalInt.of(value); + } +} diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java @@ -318,47 +3392,78 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 dedicatedserversettings.forceSave(); + // Paper start - load config files for access below if needed -+ org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = loadConfigFile((File) optionset.valueOf("bukkit-settings")); -+ org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = loadConfigFile((File) optionset.valueOf("spigot-settings")); -+ org.bukkit.configuration.file.YamlConfiguration paperConfiguration = loadConfigFile((File) optionset.valueOf("paper-settings")); ++ org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("bukkit-settings")); ++ org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("spigot-settings")); + // Paper end + Path path1 = Paths.get("eula.txt"); Eula eula = new Eula(path1); @@ -0,0 +0,0 @@ public class Main { + } - } - -+ // Paper start - load config files -+ private static org.bukkit.configuration.file.YamlConfiguration loadConfigFile(File configFile) throws Exception { -+ org.bukkit.configuration.file.YamlConfiguration config = new org.bukkit.configuration.file.YamlConfiguration(); -+ if (configFile.exists()) { -+ try { -+ config.load(configFile); -+ } catch (Exception ex) { -+ throw new Exception("Failed to load configuration file: " + configFile.getName(), ex); -+ } -+ } -+ return config; -+ } -+ // Paper end -+ - public static void forceUpgrade(LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, boolean eraseCache, BooleanSupplier continueCheck, WorldGenSettings generatorOptions) { - Main.LOGGER.info("Forcing world upgrade! {}", session.getLevelId()); // CraftBukkit - WorldUpgrader worldupgrader = new WorldUpgrader(session, dataFixer, generatorOptions, eraseCache); + File file = (File) optionset.valueOf("universe"); // CraftBukkit +- Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), file); ++ Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper + // CraftBukkit start + String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName); + LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath()); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { + AtomicReference atomicreference = new AtomicReference(); +@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> 4, net.minecraft.util.Mth.floor(entity.getZ()) >> 4)); -+ } -+ // Paper end -+ - public boolean isPositionTicking(long pos) { - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); - -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -0,0 +0,0 @@ public class EntityType implements EntityTypeTest { - - T create(EntityType type, Level world); - } -+ -+ // Paper start -+ public static java.util.Set getEntityNameList() { -+ return Registry.ENTITY_TYPE.keySet(); -+ } -+ // Paper end - } +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { + public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { + // Holder holder = worlddimension.typeHolder(); // CraftBukkit - decompile error + // Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error +- super(iworlddataserver, resourcekey, worlddimension.typeHolder(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env); ++ super(iworlddataserver, resourcekey, worlddimension.typeHolder(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), spigotConfig)); // Paper + this.pvpMode = minecraftserver.isPvpAllowed(); + this.convertable = convertable_conversionsession; + this.uuid = WorldUUID.getUUID(convertable_conversionsession.levelDirectory.path().toFile()); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); public boolean populating; public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot ++ // Paper start ++ private final io.papermc.paper.configuration.WorldConfiguration paperConfig; ++ public io.papermc.paper.configuration.WorldConfiguration paperConfig() { ++ return this.paperConfig; ++ } ++ // Paper end -+ public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper -+ public final SpigotTimings.WorldTimingsHandler timings; // Spigot public static BlockPos lastPhysicsProblem; // Spigot - private org.spigotmc.TickLimiter entityLimiter; @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env) { + public abstract ResourceKey getTypeKey(); + +- protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env) { ++ protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator) { // Paper this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot -+ this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), this.spigotConfig); // Paper ++ this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper this.generator = gen; this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); @@ -440,61 +3529,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot -+ com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper ++ this.console.paperConfigurations.reloadConfigs(this.console); for (ServerLevel world : this.console.getAllLevels()) { world.serverLevelData.setDifficulty(config.difficulty); world.setSpawnSettings(config.spawnMonsters, config.spawnAnimals); @@ -0,0 +0,0 @@ public final class CraftServer implements Server { - } - } - world.spigotConfig.init(); // Spigot -+ world.paperConfig.init(); // Paper - } - - this.pluginManager.clearPlugins(); this.commandMap.clearCommands(); this.reloadData(); org.spigotmc.SpigotConfig.registerCommands(); // Spigot -+ com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper ++ io.papermc.paper.configuration.PaperConfigurations.registerCommands(this.console); this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); -@@ -0,0 +0,0 @@ public final class CraftServer implements Server { - return this.spigot; - } - // Spigot end -+ -+ // Paper start -+ @SuppressWarnings({"rawtypes", "unchecked"}) -+ public static java.nio.file.Path dumpHeap(java.nio.file.Path dir, String name) { -+ try { -+ java.nio.file.Files.createDirectories(dir); -+ -+ javax.management.MBeanServer server = java.lang.management.ManagementFactory.getPlatformMBeanServer(); -+ java.nio.file.Path file; -+ -+ try { -+ Class clazz = Class.forName("openj9.lang.management.OpenJ9DiagnosticsMXBean"); -+ Object openj9Mbean = java.lang.management.ManagementFactory.newPlatformMXBeanProxy(server, "openj9.lang.management:type=OpenJ9Diagnostics", clazz); -+ java.lang.reflect.Method m = clazz.getMethod("triggerDumpToFile", String.class, String.class); -+ file = dir.resolve(name + ".phd"); -+ m.invoke(openj9Mbean, "heap", file.toString()); -+ } catch (ClassNotFoundException e) { -+ Class clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean"); -+ Object hotspotMBean = java.lang.management.ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", clazz); -+ java.lang.reflect.Method m = clazz.getMethod("dumpHeap", String.class, boolean.class); -+ file = dir.resolve(name + ".hprof"); -+ m.invoke(hotspotMBean, file.toString(), true); -+ } -+ -+ return file; -+ } catch (Throwable t) { -+ Bukkit.getLogger().log(Level.SEVERE, "Could not write heap", t); -+ return null; -+ } -+ } -+ // Paper end - } diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java @@ -514,6 +3560,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } }; +diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/spigotmc/SpigotConfig.java ++++ b/src/main/java/org/spigotmc/SpigotConfig.java +@@ -0,0 +0,0 @@ public class SpigotConfig + } + } + +- static void readConfig(Class clazz, Object instance) ++ public static void readConfig(Class clazz, Object instance) // Paper - package-private -> public + { + for ( Method method : clazz.getDeclaredMethods() ) + { diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/SpigotWorldConfig.java @@ -535,3 +3594,41 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public List getList(String path, T def) +diff --git a/src/test/java/io/papermc/paper/configuration/GlobalConfigTestingBase.java b/src/test/java/io/papermc/paper/configuration/GlobalConfigTestingBase.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/configuration/GlobalConfigTestingBase.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.configuration; ++ ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++public final class GlobalConfigTestingBase { ++ ++ public static void setupGlobalConfigForTest() { ++ //noinspection ConstantConditions ++ if (GlobalConfiguration.get() == null) { ++ ConfigurationNode node = PaperConfigurations.createForTesting(); ++ try { ++ GlobalConfiguration globalConfiguration = node.require(GlobalConfiguration.class); ++ GlobalConfiguration.set(globalConfiguration); ++ } catch (SerializationException e) { ++ throw new RuntimeException(e); ++ } ++ } ++ } ++} +diff --git a/src/test/java/org/bukkit/support/AbstractTestingBase.java b/src/test/java/org/bukkit/support/AbstractTestingBase.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/test/java/org/bukkit/support/AbstractTestingBase.java ++++ b/src/test/java/org/bukkit/support/AbstractTestingBase.java +@@ -0,0 +0,0 @@ public abstract class AbstractTestingBase { + + DummyServer.setup(); + DummyEnchantments.setup(); ++ io.papermc.paper.configuration.GlobalConfigTestingBase.setupGlobalConfigForTest(); // Paper + + ImmutableList.Builder builder = ImmutableList.builder(); + for (Material m : Material.values()) { diff --git a/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch index 9de4abaefa..bc6257ed45 100644 --- a/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch +++ b/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch @@ -9,29 +9,6 @@ start day per player. (Based on the time played statistic) When not per player it will use the Vanilla mechanic of one delay per world and the world age for the start day. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - - public boolean disablePillagerPatrols = false; -+ public double patrolSpawnChance = 0.2; -+ public boolean patrolPerPlayerDelay = false; -+ public int patrolDelay = 12000; -+ public boolean patrolPerPlayerStart = false; -+ public int patrolStartDay = 5; - private void pillagerSettings() { - disablePillagerPatrols = getBoolean("game-mechanics.disable-pillager-patrols", disablePillagerPatrols); -+ patrolSpawnChance = getDouble("game-mechanics.pillager-patrols.spawn-chance", patrolSpawnChance); -+ patrolPerPlayerDelay = getBoolean("game-mechanics.pillager-patrols.spawn-delay.per-player", patrolPerPlayerDelay); -+ patrolDelay = getInt("game-mechanics.pillager-patrols.spawn-delay.ticks", patrolDelay); -+ patrolPerPlayerStart = getBoolean("game-mechanics.pillager-patrols.start.per-player", patrolPerPlayerStart); -+ patrolStartDay = getInt("game-mechanics.pillager-patrols.start.day", patrolStartDay); - } - - public boolean generateFlatBedrock = false; diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -52,8 +29,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { -- if (world.paperConfig.disablePillagerPatrols) return 0; // Paper -+ if (world.paperConfig.disablePillagerPatrols || world.paperConfig.patrolSpawnChance == 0) return 0; // Paper +- if (world.paperConfig().entities.behavior.pillagerPatrols.disable) return 0; // Paper ++ if (world.paperConfig().entities.behavior.pillagerPatrols.disable || world.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return 0; // Paper if (!spawnMonsters) { return 0; } else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) { @@ -76,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + int patrolSpawnDelay; -+ if (world.paperConfig.patrolPerPlayerDelay) { ++ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { + --entityhuman.patrolSpawnDelay; + patrolSpawnDelay = entityhuman.patrolSpawnDelay; } else { @@ -90,21 +67,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return 0; + } else { + long days; -+ if (world.paperConfig.patrolPerPlayerStart) { ++ if (world.paperConfig().entities.behavior.pillagerPatrols.start.perPlayer) { + days = entityhuman.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.PLAY_TIME)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang + } else { + days = world.getDayTime() / 24000L; + } -+ if (world.paperConfig.patrolPerPlayerDelay) { -+ entityhuman.patrolSpawnDelay += world.paperConfig.patrolDelay + randomsource.nextInt(1200); ++ if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { ++ entityhuman.patrolSpawnDelay += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200); + } else { -+ this.nextTick += world.paperConfig.patrolDelay + randomsource.nextInt(1200); ++ this.nextTick += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200); + } - if (i >= 5L && world.isDay()) { - if (randomsource.nextInt(5) != 0) { -+ if (days >= world.paperConfig.patrolStartDay && world.isDay()) { -+ if (randomsource.nextDouble() >= world.paperConfig.patrolSpawnChance) { ++ if (days >= world.paperConfig().entities.behavior.pillagerPatrols.start.day && world.isDay()) { ++ if (randomsource.nextDouble() >= world.paperConfig().entities.behavior.pillagerPatrols.spawnChance) { + // Paper end return 0; } else { diff --git a/patches/server/Preserve-overstacked-loot.patch b/patches/server/Preserve-overstacked-loot.patch index 0b6da48322..e74bcd37e0 100644 --- a/patches/server/Preserve-overstacked-loot.patch +++ b/patches/server/Preserve-overstacked-loot.patch @@ -9,22 +9,6 @@ chunk bans via the large amount of NBT created by unstacking the items. Fixes GH-5140 and GH-4748. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - allowPlayerCrammingDamage = getBoolean("allow-player-cramming-damage", allowPlayerCrammingDamage); - } - -+ public boolean splitOverstackedLoot = true; -+ private void splitOverstackedLoot() { -+ splitOverstackedLoot = getBoolean("split-overstacked-loot", splitOverstackedLoot); -+ } -+ - private com.google.common.collect.Table sensorTickRates; - private com.google.common.collect.Table behaviorTickRates; - private void tickRates() { diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java @@ -40,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public static Consumer createStackSplitter(Consumer lootConsumer, @org.jetbrains.annotations.Nullable net.minecraft.server.level.ServerLevel world) { -+ boolean skipSplitter = world != null && !world.paperConfig.splitOverstackedLoot; ++ boolean skipSplitter = world != null && !world.paperConfig().fixes.splitOverstackedLoot; + // Paper end return (itemstack) -> { - if (itemstack.getCount() < itemstack.getMaxStackSize()) { diff --git a/patches/server/Prevent-Frosted-Ice-from-loading-holding-chunks.patch b/patches/server/Prevent-Frosted-Ice-from-loading-holding-chunks.patch index ab30261e51..5d4b50178e 100644 --- a/patches/server/Prevent-Frosted-Ice-from-loading-holding-chunks.patch +++ b/patches/server/Prevent-Frosted-Ice-from-loading-holding-chunks.patch @@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + BlockState blockState = world.getBlockStateIfLoaded(mutableBlockPos); // Paper + if (blockState == null) { continue; } // Paper if (blockState.is(this) && !this.slightlyMelt(blockState, world, mutableBlockPos)) { - world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, world.paperConfig.frostedIceDelayMin, world.paperConfig.frostedIceDelayMax)); // Paper - use configurable min/max delay + world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, world.paperConfig().environment.frostedIce.delay.min, world.paperConfig().environment.frostedIce.delay.max)); // Paper - use configurable min/max delay } @@ -0,0 +0,0 @@ public class FrostedIceBlock extends IceBlock { diff --git a/patches/server/Prevent-headless-pistons-from-being-created.patch b/patches/server/Prevent-headless-pistons-from-being-created.patch index 9c1e1ebe00..befba7c8c4 100644 --- a/patches/server/Prevent-headless-pistons-from-being-created.patch +++ b/patches/server/Prevent-headless-pistons-from-being-created.patch @@ -5,43 +5,19 @@ Subject: [PATCH] Prevent headless pistons from being created Prevent headless pistons from being created by explosions or tree/mushroom growth. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - maxPlayerAutoSavePerTick = (playerAutoSaveRate == -1 || playerAutoSaveRate > 100) ? 10 : 20; - } - } -+ -+ public static boolean allowHeadlessPistons; -+ private static void allowHeadlessPistons() { -+ config.set("settings.unsupported-settings.allow-headless-pistons-readme", "This setting controls if players should be able to create headless pistons."); -+ allowHeadlessPistons = getBoolean("settings.unsupported-settings.allow-headless-pistons", false); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/Explosion.java +++ b/src/main/java/net/minecraft/world/level/Explosion.java -@@ -0,0 +0,0 @@ import net.minecraft.world.level.block.BaseFireBlock; - import net.minecraft.world.level.block.Block; - import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.entity.BlockEntity; -+import net.minecraft.world.level.block.piston.PistonHeadBlock; -+import net.minecraft.world.level.block.piston.PistonMovingBlockEntity; - import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.level.gameevent.GameEvent; - import net.minecraft.world.level.material.FluidState; @@ -0,0 +0,0 @@ public class Explosion { if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockposition, iblockdata, f)) { set.add(blockposition); + // Paper start - prevent headless pistons from forming -+ if (!com.destroystokyo.paper.PaperConfig.allowHeadlessPistons && iblockdata.getBlock() == Blocks.MOVING_PISTON) { ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == Blocks.MOVING_PISTON) { + BlockEntity extension = this.level.getBlockEntity(blockposition); -+ if (extension instanceof PistonMovingBlockEntity && ((PistonMovingBlockEntity) extension).isSourcePiston()) { -+ net.minecraft.core.Direction direction = iblockdata.getValue(PistonHeadBlock.FACING); ++ if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) { ++ net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING); + set.add(blockposition.relative(direction.getOpposite())); + } + } diff --git a/patches/server/Prevent-opening-inventories-when-frozen.patch b/patches/server/Prevent-opening-inventories-when-frozen.patch index 506cff1f9b..06ac60c3eb 100644 --- a/patches/server/Prevent-opening-inventories-when-frozen.patch +++ b/patches/server/Prevent-opening-inventories-when-frozen.patch @@ -9,7 +9,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -0,0 +0,0 @@ public class ServerPlayer extends Player { - containerUpdateDelay = level.paperConfig.containerUpdateTickRate; + containerUpdateDelay = level.paperConfig().tickRates.containerUpdate; } // Paper end - if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) { diff --git a/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch index cdae389a24..344b090fec 100644 --- a/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch +++ b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch @@ -12,26 +12,6 @@ So protect them from a multitude of methods of destroying them. A config is provided if you rather let players use these exploits, and let them destroy the worlds End Portals and get on top of the nether easy. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void loggerSettings() { - deobfuscateStacktraces = getBoolean("settings.loggers.deobfuscate-stacktraces", deobfuscateStacktraces); - } -+ -+ public static boolean allowBlockPermanentBreakingExploits = false; -+ private static void allowBlockPermanentBreakingExploits() { -+ if (config.contains("allow-perm-block-break-exploits")) { -+ allowBlockPermanentBreakingExploits = config.getBoolean("allow-perm-block-break-exploits", false); -+ config.set("allow-perm-block-break-exploits", null); -+ } -+ -+ config.set("settings.unsupported-settings.allow-permanent-block-break-exploits-readme", "This setting controls if players should be able to break bedrock, end portals and other intended to be permanent blocks."); -+ allowBlockPermanentBreakingExploits = getBoolean("settings.unsupported-settings.allow-permanent-block-break-exploits", allowBlockPermanentBreakingExploits); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/Explosion.java @@ -77,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private BlockState defaultBlockState; // Paper start + public final boolean isDestroyable() { -+ return com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits || ++ return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || + this != Blocks.BEDROCK && + this != Blocks.END_PORTAL_FRAME && + this != Blocks.END_PORTAL && @@ -102,7 +82,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING); + // Paper start - prevent retracting when we're facing the wrong way (we were replaced before retraction could occur) + Direction directionQueuedAs = Direction.from3DDataValue(data & 7); // Paper - copied from below -+ if (!com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits && enumdirection != directionQueuedAs) { ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && enumdirection != directionQueuedAs) { + return false; + } + // Paper end - prevent retracting when we're facing the wrong way @@ -125,7 +105,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - world.removeBlock(pos.relative(enumdirection), false); + // Paper start - fix headless pistons breaking blocks + BlockPos headPos = pos.relative(enumdirection); -+ if (com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits || world.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, enumdirection)) { // double check to make sure we're not a headless piston. ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || world.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, enumdirection)) { // double check to make sure we're not a headless piston. + world.removeBlock(headPos, false); + } else { + ((ServerLevel)world).getChunkSource().blockChanged(headPos); // ... fix client desync @@ -178,7 +158,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (int k = -1; k < 4; ++k) { temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal); + // Paper start - prevent destroying unbreakable blocks -+ if (!com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits) { ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) { + if (!this.level.getBlockState(temp).isDestroyable()) { + return false; + } diff --git a/patches/server/Rate-options-and-timings-for-sensors-and-behaviors.patch b/patches/server/Rate-options-and-timings-for-sensors-and-behaviors.patch index 9f6e969be1..8a24833ef2 100644 --- a/patches/server/Rate-options-and-timings-for-sensors-and-behaviors.patch +++ b/patches/server/Rate-options-and-timings-for-sensors-and-behaviors.patch @@ -27,79 +27,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 /** * Get a named timer for the specified tile entity type to track type specific timings. * @param entity -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; - import net.minecraft.world.entity.MobCategory; - import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray.EngineMode; - import java.util.HashMap; -+import java.util.Locale; - import java.util.Map; - import org.bukkit.Bukkit; -+import org.bukkit.configuration.ConfigurationSection; - import org.bukkit.configuration.file.YamlConfiguration; - import org.spigotmc.SpigotWorldConfig; - -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - private void playerCrammingDamage() { - allowPlayerCrammingDamage = getBoolean("allow-player-cramming-damage", allowPlayerCrammingDamage); - } -+ -+ private com.google.common.collect.Table sensorTickRates; -+ private com.google.common.collect.Table behaviorTickRates; -+ private void tickRates() { -+ config.addDefault("world-settings.default.tick-rates.sensor.villager.secondarypoisensor", 40); -+ config.addDefault("world-settings.default.tick-rates.behavior.villager.validatenearbypoi", -1); // Example -+ log("Tick rates:"); -+ sensorTickRates = loadTickRates("sensor"); -+ behaviorTickRates = loadTickRates("behavior"); -+ } -+ -+ private com.google.common.collect.Table loadTickRates(String type) { -+ log(" " + type + ":"); -+ com.google.common.collect.Table table = com.google.common.collect.HashBasedTable.create(); -+ -+ ConfigurationSection typeSection = config.getConfigurationSection("world-settings." + worldName + ".tick-rates." + type); -+ if (typeSection == null) { -+ typeSection = config.getConfigurationSection("world-settings.default.tick-rates." + type); -+ } -+ if (typeSection != null) { -+ for (String entity : typeSection.getKeys(false)) { -+ ConfigurationSection entitySection = typeSection.getConfigurationSection(entity); -+ if (entitySection != null) { -+ log(" " + entity + ":"); -+ for (String typeName : entitySection.getKeys(false)) { -+ if (entitySection.isInt(typeName)) { -+ int tickRate = entitySection.getInt(typeName); -+ table.put(entity.toLowerCase(Locale.ROOT), typeName.toLowerCase(Locale.ROOT), tickRate); -+ log(" " + typeName + ": " + tickRate); -+ } -+ } -+ } -+ } -+ } -+ -+ if (table.isEmpty()) { -+ log(" None configured"); -+ } -+ return table; -+ } -+ -+ public int getBehaviorTickRate(String typeName, String entityType, int def) { -+ return getIntOrDefault(behaviorTickRates, typeName, entityType, def); -+ } -+ -+ public int getSensorTickRate(String typeName, String entityType, int def) { -+ return getIntOrDefault(sensorTickRates, typeName, entityType, def); -+ } -+ -+ private int getIntOrDefault(com.google.common.collect.Table table, String rowKey, String columnKey, int def) { -+ Integer rate = table.get(columnKey, rowKey); -+ return rate != null && rate > -1 ? rate : def; -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java @@ -136,7 +63,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public final boolean tryStart(ServerLevel world, E entity, long time) { + // Paper start - behavior tick rate -+ int tickRate = world.paperConfig.getBehaviorTickRate(this.configKey, entity.getType().id, -1); ++ int tickRate = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.behavior.get(entity.getType(), this.configKey), -1); + if (tickRate > -1 && time < this.endTimestamp + tickRate) { + return false; + } @@ -197,7 +124,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (--this.timeToTick <= 0L) { - this.timeToTick = (long)this.scanRate; + // Paper start - configurable sensor tick rate and timings -+ this.timeToTick = world.paperConfig.getSensorTickRate(this.configKey, entity.getType().id, this.scanRate); ++ this.timeToTick = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.sensor.get(entity.getType(), this.configKey), this.scanRate); + this.timing.startTiming(); + // Paper end this.doTick(world, entity); diff --git a/patches/server/Remove-Metadata-on-reload.patch b/patches/server/Remove-Metadata-on-reload.patch index e732c32c7c..9a98689e54 100644 --- a/patches/server/Remove-Metadata-on-reload.patch +++ b/patches/server/Remove-Metadata-on-reload.patch @@ -11,7 +11,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -0,0 +0,0 @@ public final class CraftServer implements Server { - world.paperConfig.init(); // Paper + world.spigotConfig.init(); // Spigot } + Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper @@ -26,4 +26,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end this.reloadData(); org.spigotmc.SpigotConfig.registerCommands(); // Spigot - com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper + io.papermc.paper.configuration.PaperConfigurations.registerCommands(this.console); diff --git a/patches/server/Rewrite-entity-bounding-box-lookup-calls.patch b/patches/server/Rewrite-entity-bounding-box-lookup-calls.patch index d6a62365a5..343bbc5b99 100644 --- a/patches/server/Rewrite-entity-bounding-box-lookup-calls.patch +++ b/patches/server/Rewrite-entity-bounding-box-lookup-calls.patch @@ -1057,7 +1057,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime); this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime); - this.chunkPacketBlockController = this.paperConfig.antiXray ? new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray + this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray + this.entitySliceManager = new io.papermc.paper.world.EntitySliceManager((ServerLevel)this); // Paper } diff --git a/patches/server/Sanitise-RegionFileCache-and-make-configurable.patch b/patches/server/Sanitise-RegionFileCache-and-make-configurable.patch index 496eaabaa7..6dc02058ac 100644 --- a/patches/server/Sanitise-RegionFileCache-and-make-configurable.patch +++ b/patches/server/Sanitise-RegionFileCache-and-make-configurable.patch @@ -10,20 +10,6 @@ used RegionFile. The implementation uses a LinkedHashMap as an LRU cache (modified from HashMap). The maximum size of the RegionFileCache is also made configurable. -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void loadPermsBeforePlugins() { - loadPermsBeforePlugins = getBoolean("settings.load-permissions-yml-before-plugins", true); - } -+ -+ public static int regionFileCacheSize = 256; -+ private static void regionFileCacheSize() { -+ regionFileCacheSize = Math.max(getInt("settings.region-file-cache-size", 256), 4); -+ } - } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -33,7 +19,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return regionfile; } else { - if (this.regionCache.size() >= 256) { -+ if (this.regionCache.size() >= com.destroystokyo.paper.PaperConfig.regionFileCacheSize) { // Paper - configurable ++ if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - configurable ((RegionFile) this.regionCache.removeLast()).close(); } diff --git a/patches/server/Send-full-pos-packets-for-hard-colliding-entities.patch b/patches/server/Send-full-pos-packets-for-hard-colliding-entities.patch index f0145d841e..0eaee3c006 100644 --- a/patches/server/Send-full-pos-packets-for-hard-colliding-entities.patch +++ b/patches/server/Send-full-pos-packets-for-hard-colliding-entities.patch @@ -8,21 +8,6 @@ Prevent collision problems due to desync (i.e boats) Configurable under `send-full-pos-for-hard-colliding-entities` -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - } - } - } -+ -+ public static boolean sendFullPosForHardCollidingEntities; -+ -+ private static void sendFullPosForHardCollidingEntities() { -+ sendFullPosForHardCollidingEntities = getBoolean("settings.send-full-pos-for-hard-colliding-entities", true); -+ } - } diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java @@ -32,7 +17,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 boolean flag4 = k < -32768L || k > 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L; - if (!flag4 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.isOnGround()) { -+ if (!flag4 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.isOnGround() && !(com.destroystokyo.paper.PaperConfig.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Paper - send full pos for hard colliding entities to prevent collision problems due to desync ++ if (!flag4 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.isOnGround() && !(io.papermc.paper.configuration.GlobalConfiguration.get().collisions.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Paper - send full pos for hard colliding entities to prevent collision problems due to desync if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) { if (flag2) { packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), this.entity.isOnGround()); diff --git a/patches/server/Timings-v2.patch b/patches/server/Timings-v2.patch index bf8c68bc48..0582f383f3 100644 --- a/patches/server/Timings-v2.patch +++ b/patches/server/Timings-v2.patch @@ -13,6 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +package co.aikar.timings; + +import com.google.common.collect.MapMaker; ++import io.papermc.paper.configuration.GlobalConfiguration; +import net.minecraft.commands.CommandFunction; +import net.minecraft.network.protocol.Packet; +import net.minecraft.world.level.block.Block; @@ -160,6 +161,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static Timing getCommandFunctionTiming(CommandFunction function) { + return Timings.ofSafe("Command Function - " + function.getId()); + } ++ ++ public static void processConfig(GlobalConfiguration.Timings config) { ++ TimingsManager.url = config.url; ++ if (!TimingsManager.url.endsWith("/")) { ++ TimingsManager.url += "/"; ++ } ++ TimingsManager.privacy = config.serverNamePrivacy; ++ if (!config.hiddenConfigEntries.contains("proxies.velocity.secret")) { ++ config.hiddenConfigEntries.add("proxies.velocity.secret"); ++ } ++ TimingsManager.hiddenConfigs = config.hiddenConfigEntries; ++ co.aikar.timings.Timings.setVerboseTimingsEnabled(config.verbose); ++ co.aikar.timings.Timings.setTimingsEnabled(config.enabled); ++ co.aikar.timings.Timings.setHistoryInterval(config.historyInterval * 20); ++ co.aikar.timings.Timings.setHistoryLength(config.historyLength * 20); ++ } +} diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java new file mode 100644 @@ -677,62 +694,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return Timings.ofSafe(((PrimaryLevelData) worldserver.getLevelData()).getLevelName() + " - Scheduled " + timingsType); + } +} -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ import java.util.concurrent.TimeUnit; - import java.util.logging.Level; - import java.util.regex.Pattern; - -+import com.google.common.collect.Lists; - import net.minecraft.server.MinecraftServer; - import org.bukkit.Bukkit; - import org.bukkit.command.Command; - import org.bukkit.configuration.ConfigurationSection; - import org.bukkit.configuration.InvalidConfigurationException; - import org.bukkit.configuration.file.YamlConfiguration; -+import co.aikar.timings.Timings; -+import co.aikar.timings.TimingsManager; - - public class PaperConfig { - -@@ -0,0 +0,0 @@ public class PaperConfig { - } - useDisplayNameInQuit = getBoolean("settings.use-display-name-in-quit-message", useDisplayNameInQuit); - } -+ -+ public static String timingsServerName; -+ private static void timings() { -+ boolean timings = getBoolean("timings.enabled", true); -+ boolean verboseTimings = getBoolean("timings.verbose", true); -+ TimingsManager.url = getString("timings.url", "https://timings.aikar.co/"); -+ if (!TimingsManager.url.endsWith("/")) { -+ TimingsManager.url += "/"; -+ } -+ TimingsManager.privacy = getBoolean("timings.server-name-privacy", false); -+ TimingsManager.hiddenConfigs = getList("timings.hidden-config-entries", Lists.newArrayList("database", "settings.bungeecord-addresses", "settings.velocity-support.secret")); -+ if (!TimingsManager.hiddenConfigs.contains("settings.velocity-support.secret")) { -+ TimingsManager.hiddenConfigs.add("settings.velocity-support.secret"); -+ } -+ int timingHistoryInterval = getInt("timings.history-interval", 300); -+ int timingHistoryLength = getInt("timings.history-length", 3600); -+ timingsServerName = getString("timings.server-name", "Unknown Server"); -+ -+ -+ Timings.setVerboseTimingsEnabled(verboseTimings); -+ Timings.setTimingsEnabled(timings); -+ Timings.setHistoryInterval(timingHistoryInterval * 20); -+ Timings.setHistoryLength(timingHistoryLength * 20); -+ -+ log("Timings: " + timings + -+ " - Url: " + TimingsManager.url + -+ " - Verbose: " + verboseTimings + -+ " - Interval: " + timeSummary(Timings.getHistoryInterval() / 20) + -+ " - Length: " + timeSummary(Timings.getHistoryLength() / 20) + -+ " - Server Name: " + timingsServerName); -+ } - } diff --git a/src/main/java/net/minecraft/commands/CommandFunction.java b/src/main/java/net/minecraft/commands/CommandFunction.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/commands/CommandFunction.java @@ -1554,8 +1515,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.data.CraftBlockData; @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - - public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper + } + // Paper end - public final SpigotTimings.WorldTimingsHandler timings; // Spigot + public final co.aikar.timings.WorldTimingsHandler timings; // Paper @@ -1702,7 +1663,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + @Override + public YamlConfiguration getPaperConfig() + { -+ return com.destroystokyo.paper.PaperConfig.config; ++ return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console); + } + @Override @@ -2097,7 +2058,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + @Override + public String getTimingsServerName() { -+ return com.destroystokyo.paper.PaperConfig.timingsServerName; ++ return io.papermc.paper.configuration.GlobalConfiguration.get().timings.serverName; + } + // Paper end + diff --git a/patches/server/Toggle-for-removing-existing-dragon.patch b/patches/server/Toggle-for-removing-existing-dragon.patch index f1373df509..1b46b5adbe 100644 --- a/patches/server/Toggle-for-removing-existing-dragon.patch +++ b/patches/server/Toggle-for-removing-existing-dragon.patch @@ -4,25 +4,6 @@ Date: Wed, 30 Sep 2020 22:49:14 +0200 Subject: [PATCH] Toggle for removing existing dragon -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - } - -+ public boolean shouldRemoveDragon = false; -+ private void shouldRemoveDragon() { -+ shouldRemoveDragon = getBoolean("should-remove-dragon", shouldRemoveDragon); -+ if (shouldRemoveDragon) { -+ log("The Ender Dragon will be removed if she already exists without a portal."); -+ } -+ } -+ - public short keepLoadedRange; - private void keepLoadedRange() { - keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java @@ -32,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 LOGGER.info("Found that there's a dragon still alive ({})", (Object)enderDragon); this.dragonKilled = false; - if (!bl) { -+ if (!bl && this.level.paperConfig.shouldRemoveDragon) { ++ if (!bl && this.level.paperConfig().entities.behavior.shouldRemoveDragon) { LOGGER.info("But we didn't have a portal, let's remove it."); enderDragon.discard(); this.dragonUUID = null; diff --git a/patches/server/Toggleable-player-crits-helps-mitigate-hacked-client.patch b/patches/server/Toggleable-player-crits-helps-mitigate-hacked-client.patch index cffd24ee4f..e619d3e3e7 100644 --- a/patches/server/Toggleable-player-crits-helps-mitigate-hacked-client.patch +++ b/patches/server/Toggleable-player-crits-helps-mitigate-hacked-client.patch @@ -4,22 +4,6 @@ Date: Sat, 10 Mar 2018 00:50:24 +0100 Subject: [PATCH] Toggleable player crits, helps mitigate hacked clients. -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - disableChestCatDetection = getBoolean("game-mechanics.disable-chest-cat-detection", false); - } - -+ public boolean disablePlayerCrits; -+ private void disablePlayerCrits() { -+ disablePlayerCrits = getBoolean("game-mechanics.disable-player-crits", false); -+ } -+ - public boolean allChunksAreSlimeChunks; - private void allChunksAreSlimeChunks() { - allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", false); diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java @@ -28,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity; -+ flag2 = flag2 && !level.paperConfig.disablePlayerCrits; // Paper ++ flag2 = flag2 && !level.paperConfig().entities.behavior.disablePlayerCrits; // Paper flag2 = flag2 && !this.isSprinting(); if (flag2) { f *= 1.5F; diff --git a/patches/server/Update-Log4j.patch b/patches/server/Update-Log4j.patch index dc2cfd169c..366b13b94f 100644 --- a/patches/server/Update-Log4j.patch +++ b/patches/server/Update-Log4j.patch @@ -21,4 +21,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + implementation("org.apache.logging.log4j:log4j-slf4j18-impl:2.17.1") // Paper implementation("org.ow2.asm:asm:9.3") implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation - implementation("commons-lang:commons-lang:2.6") + implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files diff --git a/patches/server/Upstream-config-migrations.patch b/patches/server/Upstream-config-migrations.patch deleted file mode 100644 index 8bd5da5a8f..0000000000 --- a/patches/server/Upstream-config-migrations.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Mon, 26 Mar 2018 18:30:53 +0300 -Subject: [PATCH] Upstream config migrations - -This patch contains config migrations for when upstream adds options -which Paper already had. - -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - private static void authenticationServersDownKickMessage() { - authenticationServersDownKickMessage = Strings.emptyToNull(getString("messages.kick.authentication-servers-down", authenticationServersDownKickMessage)); - } -+ -+ private static void savePlayerData() { -+ Object val = config.get("settings.save-player-data"); -+ if (val instanceof Boolean) { -+ SpigotConfig.disablePlayerDataSaving = !(Boolean) val; -+ SpigotConfig.config.set("players.disable-saving", SpigotConfig.disablePlayerDataSaving); -+ SpigotConfig.save(); -+ config.set("settings.save-player-data", null); -+ } -+ } -+ -+ private static void namedEntityDeaths() { -+ Object val = config.get("settings.log-named-entity-deaths"); -+ if (val instanceof Boolean bool && !bool) { -+ SpigotConfig.logNamedDeaths = false; -+ SpigotConfig.config.set("settings.log-named-deaths", false); -+ SpigotConfig.save(); -+ } -+ } - } diff --git a/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch b/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch index 1f640a0240..f4148c923a 100644 --- a/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch +++ b/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch @@ -150,8 +150,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ + // Paper end Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this)); + this.paperConfigurations = services.paperConfigurations(); // Paper } - // CraftBukkit end @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop getTypeKey(); - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor diff --git a/patches/server/Validate-usernames.patch b/patches/server/Validate-usernames.patch index dc5ad47a0d..806532cb8f 100644 --- a/patches/server/Validate-usernames.patch +++ b/patches/server/Validate-usernames.patch @@ -4,23 +4,6 @@ Date: Sat, 1 Jan 2022 05:19:37 -0800 Subject: [PATCH] Validate usernames -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - set("settings.unsupported-settings.allow-tnt-duplication", null); - } - -+ public static boolean performUsernameValidation; -+ private static void performUsernameValidation() { -+ performUsernameValidation = getBoolean("settings.unsupported-settings.perform-username-validation", true); -+ } -+ -+ - public static int playerAutoSaveRate = -1; - public static int maxPlayerAutoSavePerTick = 10; - private static void playerAutoSaveRate() { diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -62,7 +45,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet", new Object[0]); Validate.validState(ServerLoginPacketListenerImpl.isValidUsername(packet.name()), "Invalid characters in username", new Object[0]); + // Paper start - validate usernames -+ if (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode() && com.destroystokyo.paper.PaperConfig.performUsernameValidation) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation) { + if (!this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation && !validateUsername(packet.name())) { + ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!"); + return; @@ -81,7 +64,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (int i = 0; i < this.players.size(); ++i) { entityplayer = (ServerPlayer) this.players.get(i); - if (entityplayer.getUUID().equals(uuid)) { -+ if (entityplayer.getUUID().equals(uuid) || (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode() && entityplayer.getGameProfile().getName().equalsIgnoreCase(gameprofile.getName()))) { // Paper - validate usernames ++ if (entityplayer.getUUID().equals(uuid) || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && entityplayer.getGameProfile().getName().equalsIgnoreCase(gameprofile.getName()))) { // Paper - validate usernames list.add(entityplayer); } } diff --git a/patches/server/add-DragonEggFormEvent.patch b/patches/server/add-DragonEggFormEvent.patch index 5f5c2ba6df..7f2d18df5a 100644 --- a/patches/server/add-DragonEggFormEvent.patch +++ b/patches/server/add-DragonEggFormEvent.patch @@ -17,12 +17,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + org.bukkit.craftbukkit.block.CraftBlockState eggState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(this.level, eggPosition); + eggState.setData(Blocks.DRAGON_EGG.defaultBlockState()); + io.papermc.paper.event.block.DragonEggFormEvent eggEvent = new io.papermc.paper.event.block.DragonEggFormEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this.level, eggPosition), eggState, -+ new org.bukkit.craftbukkit.boss.CraftDragonBattle(this)); ++ new org.bukkit.craftbukkit.boss.CraftDragonBattle(this)); + // Paper end - DragonEggFormEvent - if (this.level.paperConfig.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - always place dragon egg + if (this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - always place dragon egg - this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.END_PODIUM_LOCATION), Blocks.DRAGON_EGG.defaultBlockState()); + // Paper start - DragonEggFormEvent -+ //this.world.setTypeUpdate(this.world.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING, WorldGenEndTrophy.a), Blocks.DRAGON_EGG.getBlockData()); ++ //this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.END_PODIUM_LOCATION), Blocks.DRAGON_EGG.defaultBlockState()); + } else { + eggEvent.setCancelled(true); + } diff --git a/patches/server/add-per-world-spawn-limits.patch b/patches/server/add-per-world-spawn-limits.patch index 1de924b2f3..47d5f17754 100644 --- a/patches/server/add-per-world-spawn-limits.patch +++ b/patches/server/add-per-world-spawn-limits.patch @@ -5,44 +5,6 @@ Subject: [PATCH] add per world spawn limits Taken from #2982. Credit to Chasewhip8 -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - - set("despawn-ranges.soft", null); - set("despawn-ranges.hard", null); -+ -+ set("spawn-limits.monsters", null); -+ set("spawn-limits.animals", null); -+ set("spawn-limits.water-animals", null); -+ set("spawn-limits.water-ambient", null); - } - - if (this.config.isSet("world-settings.default.treasure-maps-return-already-discovered") || this.config.isSet("world-settings." + worldName + ".treasure-maps-return-already-discovered")) { -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - zombieVillagerInfectionChance = getDouble("zombie-villager-infection-chance", zombieVillagerInfectionChance); - } - -+ public Reference2IntMap perWorldSpawnLimits = new Reference2IntOpenHashMap<>(net.minecraft.world.level.NaturalSpawner.SPAWNING_CATEGORIES.length); -+ private void perWorldSpawnLimits() { -+ perWorldSpawnLimits.defaultReturnValue(-1); -+ if (PaperConfig.version < 24) { -+ // ambient category already had correct name -+ perWorldSpawnLimits.put(MobCategory.MONSTER, getInt("spawn-limits.monsters", -1, false)); -+ perWorldSpawnLimits.put(MobCategory.CREATURE, getInt("spawn-limits.animals", -1, false)); -+ perWorldSpawnLimits.put(MobCategory.WATER_CREATURE, getInt("spawn-limits.water-animals", -1, false)); -+ perWorldSpawnLimits.put(MobCategory.WATER_AMBIENT, getInt("spawn-limits.water-ambient", -1, false)); -+ } -+ for (MobCategory value : net.minecraft.world.level.NaturalSpawner.SPAWNING_CATEGORIES) { -+ perWorldSpawnLimits.put(value, getInt("spawn-limits." + value.getName(), perWorldSpawnLimits.getInt(value))); -+ } -+ } -+ - public int lightQueueSize = 20; - private void lightQueueSize() { - lightQueueSize = getInt("light-queue-size", lightQueueSize); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -54,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - per world spawn limits + for (SpawnCategory spawnCategory : SpawnCategory.values()) { + if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { -+ setSpawnLimit(spawnCategory, this.world.paperConfig.perWorldSpawnLimits.getInt(CraftSpawnCategory.toNMS(spawnCategory))); ++ setSpawnLimit(spawnCategory, this.world.paperConfig().entities.spawning.spawnLimits.getInt(CraftSpawnCategory.toNMS(spawnCategory))); + } + } + // Paper end diff --git a/patches/server/added-option-to-disable-pathfinding-updates-on-block.patch b/patches/server/added-option-to-disable-pathfinding-updates-on-block.patch index f0aac1e9b6..2121f14b8c 100644 --- a/patches/server/added-option-to-disable-pathfinding-updates-on-block.patch +++ b/patches/server/added-option-to-disable-pathfinding-updates-on-block.patch @@ -4,22 +4,6 @@ Date: Mon, 25 Jan 2021 14:37:57 +0100 Subject: [PATCH] added option to disable pathfinding updates on block changes -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - enderDragonsDeathAlwaysPlacesDragonEgg = getBoolean("ender-dragons-death-always-places-dragon-egg", enderDragonsDeathAlwaysPlacesDragonEgg); - } - -+ public boolean updatePathfindingOnBlockUpdate = true; -+ private void setUpdatePathfindingOnBlockUpdate() { -+ updatePathfindingOnBlockUpdate = getBoolean("update-pathfinding-on-block-update", this.updatePathfindingOnBlockUpdate); -+ } -+ - public boolean phantomIgnoreCreative = true; - public boolean phantomOnlyAttackInsomniacs = true; - private void phantomSettings() { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -28,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } this.getChunkSource().blockChanged(pos); -+ if(this.paperConfig.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates ++ if(this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates VoxelShape voxelshape = oldState.getCollisionShape(this, pos); VoxelShape voxelshape1 = newState.getCollisionShape(this, pos); diff --git a/patches/server/fix-converting-txt-to-json-file.patch b/patches/server/fix-converting-txt-to-json-file.patch index 13a97ad031..de68573b53 100644 --- a/patches/server/fix-converting-txt-to-json-file.patch +++ b/patches/server/fix-converting-txt-to-json-file.patch @@ -35,8 +35,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames + // Paper end // Paper start - try { - com.destroystokyo.paper.PaperConfig.init((java.io.File) options.valueOf("paper-settings")); + io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc. + paperConfigurations.initializeGlobalConfiguration(); @@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface DedicatedServer.LOGGER.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file."); } diff --git a/patches/server/getPlayerUniqueId-API.patch b/patches/server/getPlayerUniqueId-API.patch index 4432e5feaf..6b004cee25 100644 --- a/patches/server/getPlayerUniqueId-API.patch +++ b/patches/server/getPlayerUniqueId-API.patch @@ -25,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + GameProfile profile; + // Only fetch an online UUID in online mode -+ if (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode()) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()) { + profile = console.getProfileCache().get(name).orElse(null); + } else { + // Make an OfflinePlayer using an offline mode UUID since the name has no profile diff --git a/patches/server/implement-optional-per-player-mob-spawns.patch b/patches/server/implement-optional-per-player-mob-spawns.patch index ddc70ae7b3..8ee5fcdd0e 100644 --- a/patches/server/implement-optional-per-player-mob-spawns.patch +++ b/patches/server/implement-optional-per-player-mob-spawns.patch @@ -4,23 +4,6 @@ Date: Mon, 19 Aug 2019 01:27:58 +0500 Subject: [PATCH] implement optional per player mob spawns -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - log("Alternative item despawn rate of " + key.getPath() + ": " + altItemDespawnRateMap.get(key)); - } - } -+ -+ public boolean perPlayerMobSpawns = false; -+ private void perPlayerMobSpawns() { -+ if (PaperConfig.version < 22) { -+ set("per-player-mob-spawns", Boolean.TRUE); -+ } -+ perPlayerMobSpawns = getBoolean("per-player-mob-spawns", true); -+ } - } diff --git a/src/main/java/com/destroystokyo/paper/util/PooledHashSets.java b/src/main/java/com/destroystokyo/paper/util/PooledHashSets.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -316,7 +299,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new); this.regionManagers.add(this.dataRegionManager); // Paper end -+ this.playerMobDistanceMap = this.level.paperConfig.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper ++ this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper } protected ChunkGenerator generator() { @@ -326,7 +309,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + public void updatePlayerMobTypeMap(Entity entity) { -+ if (!this.level.paperConfig.perPlayerMobSpawns) { ++ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { + return; + } + int index = entity.getType().getCategory().ordinal(); @@ -462,7 +445,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + int k1 = limit * info.getSpawnableChunkCount() / NaturalSpawner.MAGIC_NUMBER; + int difference = k1 - currEntityCount; + -+ if (world.paperConfig.perPlayerMobSpawns) { ++ if (world.paperConfig().entities.spawning.perPlayerMobSpawns) { + int minDiff = Integer.MAX_VALUE; + final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet inRange = world.getChunkSource().chunkMap.playerMobDistanceMap.getObjectsInRange(chunk.getPos()); + if (inRange != null) { @@ -486,7 +469,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn); + // Paper start + int spawnCount = NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn, -+ difference, world.paperConfig.perPlayerMobSpawns ? world.getChunkSource().chunkMap::updatePlayerMobTypeMap : null); ++ difference, world.paperConfig().entities.spawning.perPlayerMobSpawns ? world.getChunkSource().chunkMap::updatePlayerMobTypeMap : null); + info.mobCategoryCounts.mergeInt(enumcreaturetype, spawnCount, Integer::sum); + // Paper end } diff --git a/patches/server/incremental-chunk-and-player-saving.patch b/patches/server/incremental-chunk-and-player-saving.patch index f5fe637ed2..3066c362bd 100644 --- a/patches/server/incremental-chunk-and-player-saving.patch +++ b/patches/server/incremental-chunk-and-player-saving.patch @@ -4,51 +4,6 @@ Date: Sun, 9 Jun 2019 03:53:22 +0100 Subject: [PATCH] incremental chunk and player saving -diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -0,0 +0,0 @@ public class PaperConfig { - set("settings.unsupported-settings.allow-tnt-duplication", null); - } - -+ public static int playerAutoSaveRate = -1; -+ public static int maxPlayerAutoSavePerTick = 10; -+ private static void playerAutoSaveRate() { -+ playerAutoSaveRate = getInt("settings.player-auto-save-rate", -1); -+ maxPlayerAutoSavePerTick = getInt("settings.max-player-auto-save-per-tick", -1); -+ if (maxPlayerAutoSavePerTick == -1) { // -1 Automatic / "Recommended" -+ // 10 should be safe for everyone unless you mass spamming player auto save -+ maxPlayerAutoSavePerTick = (playerAutoSaveRate == -1 || playerAutoSaveRate > 100) ? 10 : 20; -+ } -+ } - } -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - log( "Keep Spawn Loaded Range: " + (keepLoadedRange/16)); - } - -+ public int autoSavePeriod = -1; -+ private void autoSavePeriod() { -+ autoSavePeriod = getInt("auto-save-interval", -1); -+ if (autoSavePeriod > 0) { -+ log("Auto Save Interval: " +autoSavePeriod + " (" + (autoSavePeriod / 20) + "s)"); -+ } else if (autoSavePeriod < 0) { -+ autoSavePeriod = net.minecraft.server.MinecraftServer.getServer().autosavePeriod; -+ } -+ } -+ -+ public int maxAutoSaveChunksPerTick = 24; -+ private void maxAutoSaveChunksPerTick() { -+ maxAutoSaveChunksPerTick = getInt("max-auto-save-chunks-per-tick", 24); -+ } -+ - private boolean getBoolean(String path, boolean def) { - return this.getBoolean(path, def, true); - } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java @@ -73,7 +28,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.profiler.pop(); - MinecraftServer.LOGGER.debug("Autosave finished"); + // Paper start - incremental chunk and player saving -+ int playerSaveInterval = com.destroystokyo.paper.PaperConfig.playerAutoSaveRate; ++ int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate; + if (playerSaveInterval < 0) { + playerSaveInterval = autosavePeriod; } @@ -85,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.playerList.saveAll(playerSaveInterval); + } + for (ServerLevel level : this.getAllLevels()) { -+ if (level.paperConfig.autoSavePeriod > 0) { ++ if (level.paperConfig().chunks.autoSaveInterval.value() > 0) { + level.saveIncrementally(fullSave); + } + } @@ -121,7 +76,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + long timeSinceAutoSave = this.inactiveTimeStart - this.lastAutoSaveTime; + if (timeSinceAutoSave < 0) { + // safest bet is to assume autosave is needed here -+ timeSinceAutoSave = this.chunkMap.level.paperConfig.autoSavePeriod; ++ timeSinceAutoSave = this.chunkMap.level.paperConfig().chunks.autoSaveInterval.value(); + } + this.lastAutoSaveTime = this.chunkMap.level.getGameTime() - timeSinceAutoSave; + this.chunkMap.autoSaveQueue.add(this); @@ -142,7 +97,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + long timeSinceAutoSave = this.inactiveTimeStart - this.lastAutoSaveTime; + if (timeSinceAutoSave < 0) { + // safest bet is to assume autosave is needed here -+ timeSinceAutoSave = this.chunkMap.level.paperConfig.autoSavePeriod; ++ timeSinceAutoSave = this.chunkMap.level.paperConfig().chunks.autoSaveInterval.value(); + } + this.lastAutoSaveTime = this.chunkMap.level.getGameTime() - timeSinceAutoSave; + this.chunkMap.autoSaveQueue.add(this); @@ -193,9 +148,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + protected void saveIncrementally() { + int savedThisTick = 0; + // optimized since we search far less chunks to hit ones that need to be saved -+ List reschedule = new java.util.ArrayList<>(this.level.paperConfig.maxAutoSaveChunksPerTick); ++ List reschedule = new java.util.ArrayList<>(this.level.paperConfig().chunks.maxAutoSaveChunksPerTick); + long currentTick = this.level.getGameTime(); -+ long maxSaveTime = currentTick - this.level.paperConfig.autoSavePeriod; ++ long maxSaveTime = currentTick - this.level.paperConfig().chunks.autoSaveInterval.value(); + + for (Iterator iterator = this.autoSaveQueue.iterator(); iterator.hasNext();) { + ChunkHolder playerchunk = iterator.next(); @@ -215,7 +170,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (!playerchunk.setHasBeenLoaded()) { + // do not fall through to reschedule logic + playerchunk.inactiveTimeStart = currentTick; -+ if (savedThisTick >= this.level.paperConfig.maxAutoSaveChunksPerTick) { ++ if (savedThisTick >= this.level.paperConfig().chunks.maxAutoSaveChunksPerTick) { + break; + } + continue; @@ -225,7 +180,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + reschedule.add(playerchunk); + -+ if (savedThisTick >= this.level.paperConfig.maxAutoSaveChunksPerTick) { ++ if (savedThisTick >= this.level.paperConfig().chunks.maxAutoSaveChunksPerTick) { + break; + } + } @@ -384,7 +339,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ServerPlayer entityplayer = this.players.get(i); + if (interval == -1 || now - entityplayer.lastSave >= interval) { + this.save(entityplayer); -+ if (interval != -1 && ++numSaved <= com.destroystokyo.paper.PaperConfig.maxPlayerAutoSavePerTick) { break; } ++ if (interval != -1 && ++numSaved <= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; } + } + // Paper end } diff --git a/patches/server/provide-a-configurable-option-to-disable-creeper-lin.patch b/patches/server/provide-a-configurable-option-to-disable-creeper-lin.patch index 9b22046211..92e5942c61 100644 --- a/patches/server/provide-a-configurable-option-to-disable-creeper-lin.patch +++ b/patches/server/provide-a-configurable-option-to-disable-creeper-lin.patch @@ -5,21 +5,6 @@ Subject: [PATCH] provide a configurable option to disable creeper lingering effect spawns -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - parrotsHangOnBetter = getBoolean("parrots-are-unaffected-by-player-movement", false); - log("Parrots are unaffected by player movement: " + parrotsHangOnBetter); - } -+ -+ public boolean disableCreeperLingeringEffect; -+ private void setDisableCreeperLingeringEffect() { -+ disableCreeperLingeringEffect = getBoolean("disable-creeper-lingering-effect", false); -+ log("Creeper lingering effect: " + disableCreeperLingeringEffect); -+ } - } diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java @@ -29,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Collection collection = this.getActiveEffects(); - if (!collection.isEmpty()) { -+ if (!collection.isEmpty() && !level.paperConfig.disableCreeperLingeringEffect) { // Paper ++ if (!collection.isEmpty() && !level.paperConfig().entities.behavior.disableCreeperLingeringEffect) { // Paper AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level, this.getX(), this.getY(), this.getZ()); entityareaeffectcloud.setOwner(this); // CraftBukkit