From dd0274ddc107fd8acc4361b08aa84f9e3dc32402 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 6 Jul 2025 01:21:32 +0300 Subject: [PATCH 01/67] move patches to work --- ...BottleEvents-for-player-and-dispens.patch} | 0 ...r-PR-Throttle-failed-spawn-attempts.patch} | 4 +- ...6-Raytrace-AntiXray-SDK-integration.patch} | 2 +- ...et-on-player-join-to-avoid-chunk-lo.patch} | 6 +- ...I.patch => 0008-Smooth-teleport-API.patch} | 12 +- ...BottleEvents-for-player-and-dispens.patch} | 4 +- ...-PR-Player-standing-on-position-API.patch} | 0 ...r-PR-Throttle-failed-spawn-attempts.patch} | 0 ...Optimize-default-values-for-configs.patch} | 4 +- ...oading-plugins-from-external-folder.patch} | 0 ...I.patch => 0010-Smooth-teleport-API.patch} | 2 +- ...gurable-movement-speed-for-entities.patch} | 0 .../flowsched/executor/ExecutorManager.java | 191 ----- .../ishland/flowsched/executor/LockToken.java | 3 - .../flowsched/executor/SimpleTask.java | 37 - .../com/ishland/flowsched/executor/Task.java | 11 - .../flowsched/executor/WorkerThread.java | 84 --- .../structs/DynamicPriorityQueue.java | 86 --- .../ishland/flowsched/util/Assertions.java | 27 - .../bxteam/divinemc/region/IRegionFile.java | 42 -- .../divinemc/region/LinearImplementation.java | 6 - .../divinemc/region/LinearRegionFile.java | 664 ------------------ .../divinemc/region/RegionFileFactory.java | 34 - .../divinemc/region/RegionFileFormat.java | 55 -- .../server/chunk/ChunkSystemTaskQueue.java | 404 ----------- .../divinemc/server/chunk/TheChunkSystem.java | 355 ---------- .../divinemc/util/ConcurrentFlagMatrix.java | 64 -- .../org/bxteam/divinemc/util/RandomUtil.java | 40 -- .../divinemc/util/SynchronizedCodec.java | 40 -- .../bxteam/divinemc/util/ThreadBuilder.java | 12 - .../work/api}/MapPalette.java.patch | 0 .../0004-Implement-Secure-Seed.patch | 0 .../minecraft}/0005-Async-Pathfinding.patch | 0 .../0006-Async-locate-command.patch | 0 .../0007-Multithreaded-Tracker.patch | 0 .../minecraft}/0008-Misc-Optimizations.patch | 0 .../minecraft}/0009-Optimize-Fluids.patch | 0 .../0010-Chunk-System-Optimizations.patch | 0 .../0011-Optimize-entity-stupid-brain.patch | 0 .../minecraft}/0012-Lag-compensation.patch | 0 .../0013-Implement-NoChatReports.patch | 0 ...-Carpet-Fixes-RecipeManager-Optimize.patch | 0 .../minecraft}/0015-Optimize-explosions.patch | 0 ...weird-movement-and-disable-teleporti.patch | 0 .../0017-Snowball-and-Egg-knockback.patch | 0 .../0018-Block-Log4Shell-exploit.patch | 0 ...qr-call-in-ServerEntity-sendChanges-.patch | 0 .../0020-Optimize-canSee-checks.patch | 0 .../0021-Verify-Minecraft-EULA-earlier.patch | 0 ...able-saving-of-snowball-and-firework.patch | 0 .../minecraft}/0023-Re-Fix-MC-117075.patch | 0 .../minecraft}/0024-Virtual-Threads.patch | 0 .../0025-Optimize-Structure-Generation.patch | 0 ...26-Option-to-disable-disconnect.spam.patch | 0 .../minecraft}/0027-Async-Chunk-Sending.patch | 0 .../minecraft}/0028-Configurable-MC-67.patch | 0 .../0029-Configurable-MC-59471.patch | 0 .../0030-ModernFix-compact_bit_storage.patch | 0 .../minecraft}/0031-lithium-fast_util.patch | 0 ...-Command-block-parse-results-caching.patch | 0 ...-BlockEntity-ticking-isRemoved-check.patch | 0 ...ow-throttling-hopper-checks-if-the-t.patch | 0 ...igurable-movement-speed-for-entities.patch | 0 .../0037-Dynamic-Activation-of-Brain.patch | 0 .../0038-Linear-region-file-format.patch | 0 .../0040-Player-ProfileResult-caching.patch | 0 .../minecraft}/0041-Async-mob-spawning.patch | 0 ...0043-Carpet-Fixes-Sheep-Optimization.patch | 0 .../0044-Density-Function-Compiler.patch | 0 .../0045-Parallel-world-ticking.patch | 0 .../0046-MSPT-Tracking-for-each-world.patch | 0 .../minecraft}/0047-Optimize-Raids.patch | 0 .../0048-Catch-update-suppressors.patch | 0 .../0050-Optimize-suffocation.patch | 0 .../0051-Reduce-chunk-loading-lookups.patch | 0 ...MS-Addition-Optimized-dragon-respawn.patch | 0 .../0053-Regionized-Chunk-Ticking.patch | 0 .../0055-Clump-experience-orbs.patch | 0 .../paper}/0005-Implement-Secure-Seed.patch | 0 .../0006-Chunk-System-Optimizations.patch | 0 .../paper}/0007-Optimize-canSee-checks.patch | 0 ...08-Configurable-thread-pool-priority.patch | 0 .../server/paper}/0009-Virtual-Threads.patch | 0 .../paper}/0010-Multithreaded-Tracker.patch | 0 .../paper}/0014-Parallel-world-ticking.patch | 0 .../0003-MSPT-Tracking-for-each-world.patch | 0 86 files changed, 17 insertions(+), 2172 deletions(-) rename divinemc-server/minecraft-patches/features/{0036-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch => 0004-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch} (100%) rename divinemc-server/minecraft-patches/features/{0039-Paper-PR-Throttle-failed-spawn-attempts.patch => 0005-Paper-PR-Throttle-failed-spawn-attempts.patch} (99%) rename divinemc-server/minecraft-patches/features/{0042-Raytrace-AntiXray-SDK-integration.patch => 0006-Raytrace-AntiXray-SDK-integration.patch} (96%) rename divinemc-server/minecraft-patches/features/{0049-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch => 0007-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch} (93%) rename divinemc-server/minecraft-patches/features/{0054-Smooth-teleport-API.patch => 0008-Smooth-teleport-API.patch} (87%) rename divinemc-server/paper-patches/features/{0011-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch => 0005-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch} (92%) rename divinemc-server/paper-patches/features/{0012-Paper-PR-Player-standing-on-position-API.patch => 0006-Paper-PR-Player-standing-on-position-API.patch} (100%) rename divinemc-server/paper-patches/features/{0013-Paper-PR-Throttle-failed-spawn-attempts.patch => 0007-Paper-PR-Throttle-failed-spawn-attempts.patch} (100%) rename divinemc-server/paper-patches/features/{0015-Optimize-default-values-for-configs.patch => 0008-Optimize-default-values-for-configs.patch} (98%) rename divinemc-server/paper-patches/features/{0016-Implement-loading-plugins-from-external-folder.patch => 0009-Implement-loading-plugins-from-external-folder.patch} (100%) rename divinemc-server/paper-patches/features/{0017-Smooth-teleport-API.patch => 0010-Smooth-teleport-API.patch} (92%) rename divinemc-server/purpur-patches/features/{0004-Configurable-movement-speed-for-entities.patch => 0003-Configurable-movement-speed-for-entities.patch} (100%) delete mode 100644 divinemc-server/src/main/java/com/ishland/flowsched/executor/ExecutorManager.java delete mode 100644 divinemc-server/src/main/java/com/ishland/flowsched/executor/LockToken.java delete mode 100644 divinemc-server/src/main/java/com/ishland/flowsched/executor/SimpleTask.java delete mode 100644 divinemc-server/src/main/java/com/ishland/flowsched/executor/Task.java delete mode 100644 divinemc-server/src/main/java/com/ishland/flowsched/executor/WorkerThread.java delete mode 100644 divinemc-server/src/main/java/com/ishland/flowsched/structs/DynamicPriorityQueue.java delete mode 100644 divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearImplementation.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFactory.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/ChunkSystemTaskQueue.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/TheChunkSystem.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/util/ConcurrentFlagMatrix.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/util/SynchronizedCodec.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/util/ThreadBuilder.java rename {divinemc-api/paper-patches/files/src/main/java/org/bukkit/map => patches/work/api}/MapPalette.java.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0004-Implement-Secure-Seed.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0005-Async-Pathfinding.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0006-Async-locate-command.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0007-Multithreaded-Tracker.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0008-Misc-Optimizations.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0009-Optimize-Fluids.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0010-Chunk-System-Optimizations.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0011-Optimize-entity-stupid-brain.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0012-Lag-compensation.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0013-Implement-NoChatReports.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0014-Carpet-Fixes-RecipeManager-Optimize.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0015-Optimize-explosions.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0017-Snowball-and-Egg-knockback.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0018-Block-Log4Shell-exploit.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0020-Optimize-canSee-checks.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0021-Verify-Minecraft-EULA-earlier.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0022-Option-to-disable-saving-of-snowball-and-firework.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0023-Re-Fix-MC-117075.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0024-Virtual-Threads.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0025-Optimize-Structure-Generation.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0026-Option-to-disable-disconnect.spam.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0027-Async-Chunk-Sending.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0028-Configurable-MC-67.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0029-Configurable-MC-59471.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0030-ModernFix-compact_bit_storage.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0031-lithium-fast_util.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0032-Command-block-parse-results-caching.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0035-Configurable-movement-speed-for-entities.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0037-Dynamic-Activation-of-Brain.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0038-Linear-region-file-format.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0040-Player-ProfileResult-caching.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0041-Async-mob-spawning.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0043-Carpet-Fixes-Sheep-Optimization.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0044-Density-Function-Compiler.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0045-Parallel-world-ticking.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0046-MSPT-Tracking-for-each-world.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0047-Optimize-Raids.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0048-Catch-update-suppressors.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0050-Optimize-suffocation.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0051-Reduce-chunk-loading-lookups.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0053-Regionized-Chunk-Ticking.patch (100%) rename {divinemc-server/minecraft-patches/features => patches/work/server/minecraft}/0055-Clump-experience-orbs.patch (100%) rename {divinemc-server/paper-patches/features => patches/work/server/paper}/0005-Implement-Secure-Seed.patch (100%) rename {divinemc-server/paper-patches/features => patches/work/server/paper}/0006-Chunk-System-Optimizations.patch (100%) rename {divinemc-server/paper-patches/features => patches/work/server/paper}/0007-Optimize-canSee-checks.patch (100%) rename {divinemc-server/paper-patches/features => patches/work/server/paper}/0008-Configurable-thread-pool-priority.patch (100%) rename {divinemc-server/paper-patches/features => patches/work/server/paper}/0009-Virtual-Threads.patch (100%) rename {divinemc-server/paper-patches/features => patches/work/server/paper}/0010-Multithreaded-Tracker.patch (100%) rename {divinemc-server/paper-patches/features => patches/work/server/paper}/0014-Parallel-world-ticking.patch (100%) rename {divinemc-server/purpur-patches/features => patches/work/server/purpur}/0003-MSPT-Tracking-for-each-world.patch (100%) diff --git a/divinemc-server/minecraft-patches/features/0036-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch b/divinemc-server/minecraft-patches/features/0004-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0036-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch rename to divinemc-server/minecraft-patches/features/0004-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch diff --git a/divinemc-server/minecraft-patches/features/0039-Paper-PR-Throttle-failed-spawn-attempts.patch b/divinemc-server/minecraft-patches/features/0005-Paper-PR-Throttle-failed-spawn-attempts.patch similarity index 99% rename from divinemc-server/minecraft-patches/features/0039-Paper-PR-Throttle-failed-spawn-attempts.patch rename to divinemc-server/minecraft-patches/features/0005-Paper-PR-Throttle-failed-spawn-attempts.patch index 6c35e64..3ee3718 100644 --- a/divinemc-server/minecraft-patches/features/0039-Paper-PR-Throttle-failed-spawn-attempts.patch +++ b/divinemc-server/minecraft-patches/features/0005-Paper-PR-Throttle-failed-spawn-attempts.patch @@ -175,10 +175,10 @@ index 345d4b80bd4383e0fb66d744d87bc8ef4100fd32..68a074a1eb11b158af773a2c44aa49d5 private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel level, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double distance) { diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java -index 5e9f3856c384dbb2bd462121b903cd2b326e4376..19f74518923783d8d5560b526a1f267dabd23156 100644 +index 182c14b660f8860bed627eed4e01fd4002153e9a..81511de113c292549fe5fe720a15bf3e0497ca84 100644 --- a/net/minecraft/world/level/chunk/ChunkAccess.java +++ b/net/minecraft/world/level/chunk/ChunkAccess.java -@@ -92,6 +92,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh +@@ -88,6 +88,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(ChunkAccess.DATA_TYPE_REGISTRY); // CraftBukkit end public final Registry biomeRegistry; // CraftBukkit diff --git a/divinemc-server/minecraft-patches/features/0042-Raytrace-AntiXray-SDK-integration.patch b/divinemc-server/minecraft-patches/features/0006-Raytrace-AntiXray-SDK-integration.patch similarity index 96% rename from divinemc-server/minecraft-patches/features/0042-Raytrace-AntiXray-SDK-integration.patch rename to divinemc-server/minecraft-patches/features/0006-Raytrace-AntiXray-SDK-integration.patch index 8eb5ecb..0b7d832 100644 --- a/divinemc-server/minecraft-patches/features/0042-Raytrace-AntiXray-SDK-integration.patch +++ b/divinemc-server/minecraft-patches/features/0006-Raytrace-AntiXray-SDK-integration.patch @@ -25,7 +25,7 @@ index c4a4f08272b34f72dea4feaaeb66d153b2aab8c8..be5da5a81246b4f4abe19f7c0cf68990 } diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 6e8075618baf98fcc396f0b5e241a806805b3d94..37f5bd2a63e2ec074fbc55d366e0d128f1918089 100644 +index 4c1ce7e85f9c3315635472047ffaf15a711aeffd..9625213b7c1295b813071dbedea5366510c7072f 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -1171,6 +1171,12 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl diff --git a/divinemc-server/minecraft-patches/features/0049-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch b/divinemc-server/minecraft-patches/features/0007-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch similarity index 93% rename from divinemc-server/minecraft-patches/features/0049-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch rename to divinemc-server/minecraft-patches/features/0007-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch index ccb4be8..24cf19a 100644 --- a/divinemc-server/minecraft-patches/features/0049-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch +++ b/divinemc-server/minecraft-patches/features/0007-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch @@ -15,7 +15,7 @@ The delay is currently set to 2 seconds, however, we may want to adjust this bef This patch fixes PaperMC/Paper#9581 diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -index e93a006cde4dd85a9976e0d6a64643755ba99fb7..62e89385fcdc3fa0202863f3199c98a2df4be2a6 100644 +index bdc1200ef5317fdaf58973bf580b0a672aee800f..1ed2ae41e47b2446bf1835efc8bad369408d52da 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java @@ -48,6 +48,7 @@ public final class RegionizedPlayerChunkLoader { @@ -27,10 +27,10 @@ index e93a006cde4dd85a9976e0d6a64643755ba99fb7..62e89385fcdc3fa0202863f3199c98a2 public static final int GENERATED_TICKET_LEVEL = ChunkHolderManager.FULL_LOADED_TICKET_LEVEL; public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY); diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index e1ca822d41311e3be44c52badb907619ca681cf9..bd6cff4916fdf379ee887259d18ee274ff2f8bc6 100644 +index 8a67672f1175769ac213099331453fbae59442fa..c70b5ce2dc8cbcdea8715339a63e038f94849bfb 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -316,6 +316,13 @@ public abstract class PlayerList { +@@ -315,6 +315,13 @@ public abstract class PlayerList { // this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player))); // CraftBukkit - replaced with loop below // Paper start - Fire PlayerJoinEvent when Player is actually ready; correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks player.supressTrackerForLogin = true; diff --git a/divinemc-server/minecraft-patches/features/0054-Smooth-teleport-API.patch b/divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch similarity index 87% rename from divinemc-server/minecraft-patches/features/0054-Smooth-teleport-API.patch rename to divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch index 6878d12..bb87d52 100644 --- a/divinemc-server/minecraft-patches/features/0054-Smooth-teleport-API.patch +++ b/divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch @@ -5,22 +5,22 @@ Subject: [PATCH] Smooth teleport API diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index cf4ab76f463836a8ed9aeedd09ae95e75b9e8dbc..f5a0c5a2f56376bf89b16a809d465bc45a80eb38 100644 +index a1b4720ef128ba5cbe1466a7a584d4fe501a71f8..b75d2d2746c3e7b12f65b0bcb559cd7e0ce7ebf8 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -431,6 +431,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -430,6 +430,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + private boolean tpsBar = false; // Purpur - Implement TPSBar private boolean compassBar = false; // Purpur - Add compass command private boolean ramBar = false; // Purpur - Implement rambar commands - public boolean hasTickedAtLeastOnceInNewWorld = false; // DivineMC - Parallel world ticking + public boolean smoothWorldTeleport; // DivineMC - Smooth teleport API // Paper start - rewrite chunk system private ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader; diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 04f82f77e1ad2b7105cbace2a4ef99590965ae4f..147535646319018ec5dfe42d12fdb19d9e1f7543 100644 +index c70b5ce2dc8cbcdea8715339a63e038f94849bfb..9362bfdf8f5495d237b1e74be4dd925db2452dc0 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -758,11 +758,11 @@ public abstract class PlayerList { +@@ -748,11 +748,11 @@ public abstract class PlayerList { byte b = (byte)(keepInventory ? 1 : 0); ServerLevel serverLevel = serverPlayer.level(); LevelData levelData = serverLevel.getLevelData(); @@ -34,7 +34,7 @@ index 04f82f77e1ad2b7105cbace2a4ef99590965ae4f..147535646319018ec5dfe42d12fdb19d serverPlayer.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getSharedSpawnPos(), level.getSharedSpawnAngle())); serverPlayer.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); serverPlayer.connection -@@ -849,6 +849,12 @@ public abstract class PlayerList { +@@ -839,6 +839,12 @@ public abstract class PlayerList { return serverPlayer; } diff --git a/divinemc-server/paper-patches/features/0011-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch b/divinemc-server/paper-patches/features/0005-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch similarity index 92% rename from divinemc-server/paper-patches/features/0011-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch rename to divinemc-server/paper-patches/features/0005-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch index ac9198a..461c24f 100644 --- a/divinemc-server/paper-patches/features/0011-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch +++ b/divinemc-server/paper-patches/features/0005-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Paper PR: Add FillBottleEvents for player and dispenser diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 214bc24aa301f99c911a129676bc7d7d50df7236..83c6cf3cb062c8a6508728822e37d52a543415a3 100644 +index a162440a583801671787163d998d6b9546ef7e61..d10ee84ed2f6b1c81667b968984f3ebf5c39e445 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -2148,4 +2148,18 @@ public class CraftEventFactory { +@@ -2128,4 +2128,18 @@ public class CraftEventFactory { return disconnectReason; } diff --git a/divinemc-server/paper-patches/features/0012-Paper-PR-Player-standing-on-position-API.patch b/divinemc-server/paper-patches/features/0006-Paper-PR-Player-standing-on-position-API.patch similarity index 100% rename from divinemc-server/paper-patches/features/0012-Paper-PR-Player-standing-on-position-API.patch rename to divinemc-server/paper-patches/features/0006-Paper-PR-Player-standing-on-position-API.patch diff --git a/divinemc-server/paper-patches/features/0013-Paper-PR-Throttle-failed-spawn-attempts.patch b/divinemc-server/paper-patches/features/0007-Paper-PR-Throttle-failed-spawn-attempts.patch similarity index 100% rename from divinemc-server/paper-patches/features/0013-Paper-PR-Throttle-failed-spawn-attempts.patch rename to divinemc-server/paper-patches/features/0007-Paper-PR-Throttle-failed-spawn-attempts.patch diff --git a/divinemc-server/paper-patches/features/0015-Optimize-default-values-for-configs.patch b/divinemc-server/paper-patches/features/0008-Optimize-default-values-for-configs.patch similarity index 98% rename from divinemc-server/paper-patches/features/0015-Optimize-default-values-for-configs.patch rename to divinemc-server/paper-patches/features/0008-Optimize-default-values-for-configs.patch index 918b060..8c164d6 100644 --- a/divinemc-server/paper-patches/features/0015-Optimize-default-values-for-configs.patch +++ b/divinemc-server/paper-patches/features/0008-Optimize-default-values-for-configs.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimize default values for configs diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -index d13c749cfb49ce3c70b4c24ece780a4fc9482d78..a25a2bb0008901a249cf2cc320944bd69cf8ae72 100644 +index c5a491acfe4b93bfa8fd21861edbaf464a178bf3..f572613f3b2aeacfbfcd0a5f96048f55ec2384b9 100644 --- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -347,8 +347,8 @@ public class GlobalConfiguration extends ConfigurationPart { +@@ -348,8 +348,8 @@ public class GlobalConfiguration extends ConfigurationPart { @Constraints.Min(4) public int regionFileCacheSize = 256; @Comment("See https://luckformula.emc.gs") diff --git a/divinemc-server/paper-patches/features/0016-Implement-loading-plugins-from-external-folder.patch b/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch similarity index 100% rename from divinemc-server/paper-patches/features/0016-Implement-loading-plugins-from-external-folder.patch rename to divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch diff --git a/divinemc-server/paper-patches/features/0017-Smooth-teleport-API.patch b/divinemc-server/paper-patches/features/0010-Smooth-teleport-API.patch similarity index 92% rename from divinemc-server/paper-patches/features/0017-Smooth-teleport-API.patch rename to divinemc-server/paper-patches/features/0010-Smooth-teleport-API.patch index cd260bc..6fbddaa 100644 --- a/divinemc-server/paper-patches/features/0017-Smooth-teleport-API.patch +++ b/divinemc-server/paper-patches/features/0010-Smooth-teleport-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Smooth teleport API diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index f2a7c688597d9a07e7ef07476cedbd423c8b3b0d..60669bf18850811546b46d85c6650b02cda963ab 100644 +index 218556fdaf4ea4993864e22530b4bad3335a535d..6a1ac6cdd0cf4f6a62216c264f6fd3cd25476254 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1329,6 +1329,17 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa diff --git a/divinemc-server/purpur-patches/features/0004-Configurable-movement-speed-for-entities.patch b/divinemc-server/purpur-patches/features/0003-Configurable-movement-speed-for-entities.patch similarity index 100% rename from divinemc-server/purpur-patches/features/0004-Configurable-movement-speed-for-entities.patch rename to divinemc-server/purpur-patches/features/0003-Configurable-movement-speed-for-entities.patch diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/ExecutorManager.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/ExecutorManager.java deleted file mode 100644 index b1f2d69..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/ExecutorManager.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.ishland.flowsched.executor; - -import com.ishland.flowsched.structs.DynamicPriorityQueue; -import com.ishland.flowsched.util.Assertions; -import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executor; -import java.util.function.Consumer; - -public class ExecutorManager { - public final DynamicPriorityQueue globalWorkQueue; - protected final ConcurrentMap lockListeners = new ConcurrentHashMap<>(); - protected final WorkerThread[] workerThreads; - final Object workerMonitor = new Object(); - - /** - * Creates a new executor manager. - * - * @param workerThreadCount the number of worker threads. - */ - public ExecutorManager(int workerThreadCount) { - this(workerThreadCount, thread -> { }); - } - - /** - * Creates a new executor manager. - * - * @param workerThreadCount the number of worker threads. - * @param threadInitializer the thread initializer. - */ - public ExecutorManager(int workerThreadCount, Consumer threadInitializer) { - globalWorkQueue = new DynamicPriorityQueue<>(); - workerThreads = new WorkerThread[workerThreadCount]; - for (int i = 0; i < workerThreadCount; i++) { - final WorkerThread thread = new WorkerThread(this); - threadInitializer.accept(thread); - thread.start(); - workerThreads[i] = thread; - } - } - - /** - * Attempt to lock the given tokens. - * The caller should discard the task if this method returns false, as it reschedules the task. - * - * @return {@code true} if the lock is acquired, {@code false} otherwise. - */ - boolean tryLock(Task task) { - retry: - while (true) { - final FreeableTaskList listenerSet = new FreeableTaskList(); - LockToken[] lockTokens = task.lockTokens(); - for (int i = 0; i < lockTokens.length; i++) { - LockToken token = lockTokens[i]; - final FreeableTaskList present = this.lockListeners.putIfAbsent(token, listenerSet); - if (present != null) { - for (int j = 0; j < i; j++) { - this.lockListeners.remove(lockTokens[j], listenerSet); - } - callListeners(listenerSet); - synchronized (present) { - if (present.freed) { - continue retry; - } else { - present.add(task); - } - } - return false; - } - } - return true; - } - } - - /** - * Release the locks held by the given task. - * - * @param task the task. - */ - void releaseLocks(Task task) { - FreeableTaskList expectedListeners = null; - for (LockToken token : task.lockTokens()) { - final FreeableTaskList listeners = this.lockListeners.remove(token); - if (listeners != null) { - if (expectedListeners == null) { - expectedListeners = listeners; - } else { - Assertions.assertTrue(expectedListeners == listeners, "Inconsistent lock listeners"); - } - } else { - throw new IllegalStateException("Lock token " + token + " is not locked"); - } - } - if (expectedListeners != null) { - callListeners(expectedListeners); // synchronizes - } - } - - private void callListeners(FreeableTaskList listeners) { - synchronized (listeners) { - listeners.freed = true; - if (listeners.isEmpty()) return; - for (Task listener : listeners) { - this.schedule0(listener); - } - } - this.wakeup(); - } - - /** - * Polls an executable task from the global work queue. - * - * @return the task, or {@code null} if no task is executable. - */ - Task pollExecutableTask() { - Task task; - while ((task = this.globalWorkQueue.dequeue()) != null) { - if (this.tryLock(task)) { - return task; - } - } - return null; - } - - /** - * Shuts down the executor manager. - */ - public void shutdown() { - for (WorkerThread workerThread : workerThreads) { - workerThread.shutdown(); - } - } - - /** - * Schedules a task. - * - * @param task the task. - */ - public void schedule(Task task) { - schedule0(task); - wakeup(); - } - - private void schedule0(Task task) { - this.globalWorkQueue.enqueue(task, task.priority()); - } - - public void wakeup() { // Canvas - private -> public - synchronized (this.workerMonitor) { - this.workerMonitor.notify(); - } - } - - public boolean hasPendingTasks() { - return this.globalWorkQueue.size() != 0; - } - - /** - * Schedules a runnable for execution with the given priority. - * - * @param runnable the runnable. - * @param priority the priority. - */ - public void schedule(Runnable runnable, int priority) { - this.schedule(new SimpleTask(runnable, priority)); - } - - /** - * Creates an executor that schedules runnables with the given priority. - * - * @param priority the priority. - * @return the executor. - */ - public Executor executor(int priority) { - return runnable -> this.schedule(runnable, priority); - } - - /** - * Notifies the executor manager that the priority of the given task has changed. - * - * @param task the task. - */ - public void notifyPriorityChange(Task task) { - this.globalWorkQueue.changePriority(task, task.priority()); - } - - protected static class FreeableTaskList extends ReferenceArrayList { // Canvas - private -> protected - private boolean freed = false; - } -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/LockToken.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/LockToken.java deleted file mode 100644 index 96b9eb7..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/LockToken.java +++ /dev/null @@ -1,3 +0,0 @@ -package com.ishland.flowsched.executor; - -public interface LockToken { } diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/SimpleTask.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/SimpleTask.java deleted file mode 100644 index 93a32fa..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/SimpleTask.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ishland.flowsched.executor; - -import java.util.Objects; - -public class SimpleTask implements Task { - private final Runnable wrapped; - private final int priority; - - public SimpleTask(Runnable wrapped, int priority) { - this.wrapped = Objects.requireNonNull(wrapped); - this.priority = priority; - } - - @Override - public void run(Runnable releaseLocks) { - try { - wrapped.run(); - } finally { - releaseLocks.run(); - } - } - - @Override - public void propagateException(Throwable t) { - t.printStackTrace(); - } - - @Override - public LockToken[] lockTokens() { - return new LockToken[0]; - } - - @Override - public int priority() { - return this.priority; - } -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/Task.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/Task.java deleted file mode 100644 index 86aa983..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/Task.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.ishland.flowsched.executor; - -public interface Task { - void run(Runnable releaseLocks); - - void propagateException(Throwable t); - - LockToken[] lockTokens(); - - int priority(); -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/WorkerThread.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/WorkerThread.java deleted file mode 100644 index 6f93999..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/WorkerThread.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.ishland.flowsched.executor; - -import ca.spottedleaf.moonrise.common.util.TickThread; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.LockSupport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class WorkerThread extends TickThread { - private static final Logger LOGGER = LoggerFactory.getLogger("FlowSched Executor Worker Thread"); - - private final ExecutorManager executorManager; - private final AtomicBoolean shutdown = new AtomicBoolean(false); - public volatile boolean active = false; - - public WorkerThread(ExecutorManager executorManager) { - super("null_worker"); - this.executorManager = executorManager; - } - - @Override - public void run() { - main_loop: - while (true) { - if (this.shutdown.get()) { - return; - } - active = true; - if (pollTasks()) { - continue; - } - - synchronized (this.executorManager.workerMonitor) { - if (this.executorManager.hasPendingTasks()) continue main_loop; - try { - active = false; - this.executorManager.workerMonitor.wait(); - } catch (InterruptedException ignored) { - } - } - } - } - - private boolean pollTasks() { - final Task task = executorManager.pollExecutableTask(); - try { - if (task != null) { - AtomicBoolean released = new AtomicBoolean(false); - try { - task.run(() -> { - if (released.compareAndSet(false, true)) { - executorManager.releaseLocks(task); - } - }); - } catch (Throwable t) { - try { - if (released.compareAndSet(false, true)) { - executorManager.releaseLocks(task); - } - } catch (Throwable t1) { - t.addSuppressed(t1); - LOGGER.error("Exception thrown while releasing locks", t); - } - try { - task.propagateException(t); - } catch (Throwable t1) { - t.addSuppressed(t1); - LOGGER.error("Exception thrown while propagating exception", t); - } - } - return true; - } - return false; - } catch (Throwable t) { - LOGGER.error("Exception thrown while executing task", t); - return true; - } - } - - public void shutdown() { - shutdown.set(true); - LockSupport.unpark(this); - } -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/structs/DynamicPriorityQueue.java b/divinemc-server/src/main/java/com/ishland/flowsched/structs/DynamicPriorityQueue.java deleted file mode 100644 index b17a49d..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/structs/DynamicPriorityQueue.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.ishland.flowsched.structs; - -import ca.spottedleaf.moonrise.common.util.MoonriseConstants; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicIntegerArray; - -@SuppressWarnings("unchecked") -public class DynamicPriorityQueue { - public static final int MAX_PRIORITY = MoonriseConstants.MAX_VIEW_DISTANCE + 3; - private final AtomicIntegerArray taskCount; - public final ConcurrentLinkedQueue[] priorities; - private final ConcurrentHashMap priorityMap = new ConcurrentHashMap<>(); - - public DynamicPriorityQueue() { - this.taskCount = new AtomicIntegerArray(MAX_PRIORITY); - this.priorities = new ConcurrentLinkedQueue[MAX_PRIORITY]; - for (int i = 0; i < (MAX_PRIORITY); i++) { - this.priorities[i] = new ConcurrentLinkedQueue<>(); - } - } - - public void enqueue(E element, int priority) { - if (this.priorityMap.putIfAbsent(element, priority) != null) - throw new IllegalArgumentException("Element already in queue"); - - this.priorities[priority].add(element); - this.taskCount.incrementAndGet(priority); - } - - public boolean changePriority(E element, int newPriority) { - Integer currentPriority = this.priorityMap.get(element); - if (currentPriority == null || currentPriority == newPriority) { - return false; - } - - int currentIndex = currentPriority; - boolean removedFromQueue = this.priorities[currentIndex].remove(element); - if (!removedFromQueue) { - return false; - } - - this.taskCount.decrementAndGet(currentIndex); - final boolean changeSuccess = this.priorityMap.replace(element, currentPriority, newPriority); - if (!changeSuccess) { - return false; - } - - this.priorities[newPriority].add(element); - this.taskCount.incrementAndGet(newPriority); - return true; - } - - public E dequeue() { - for (int i = 0; i < this.priorities.length; i++) { - if (this.taskCount.get(i) == 0) continue; - E element = priorities[i].poll(); - if (element != null) { - this.taskCount.decrementAndGet(i); - this.priorityMap.remove(element); - return element; - } - } - return null; - } - - public boolean contains(E element) { - return priorityMap.containsKey(element); - } - - public void remove(E element) { - Integer priority = this.priorityMap.remove(element); - if (priority == null) return; - - boolean removed = this.priorities[priority].remove(element); - if (removed) this.taskCount.decrementAndGet(priority); - } - - public int size() { - return priorityMap.size(); - } - - public boolean isEmpty() { - return size() == 0; - } -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java b/divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java deleted file mode 100644 index c3ee6c4..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.ishland.flowsched.util; - -public final class Assertions { - public static void assertTrue(boolean value, String message) { - if (!value) { - final AssertionError error = new AssertionError(message); - error.printStackTrace(); - throw error; - } - } - - public static void assertTrue(boolean state, String format, Object... args) { - if (!state) { - final AssertionError error = new AssertionError(String.format(format, args)); - error.printStackTrace(); - throw error; - } - } - - public static void assertTrue(boolean value) { - if (!value) { - final AssertionError error = new AssertionError(); - error.printStackTrace(); - throw error; - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java deleted file mode 100644 index cf4104a..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bxteam.divinemc.region; - -import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.ChunkPos; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.file.Path; - -public interface IRegionFile extends AutoCloseable, ChunkSystemRegionFile { - Path getPath(); - - void flush() throws IOException; - - void clear(ChunkPos pos) throws IOException; - - @Override - void close() throws IOException; - - void setOversized(int x, int z, boolean b) throws IOException; - - void write(ChunkPos pos, ByteBuffer buffer) throws IOException; - - boolean hasChunk(ChunkPos pos); - - boolean doesChunkExist(ChunkPos pos) throws Exception; - - boolean isOversized(int x, int z); - - boolean recalculateHeader() throws IOException; - - int getRecalculateCount(); - - DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException; - - DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException; - - CompoundTag getOversizedData(int x, int z) throws IOException; -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearImplementation.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearImplementation.java deleted file mode 100644 index e521593..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearImplementation.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.bxteam.divinemc.region; - -public enum LinearImplementation { - V1, - V2 -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java deleted file mode 100644 index 3e25b24..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java +++ /dev/null @@ -1,664 +0,0 @@ -package org.bxteam.divinemc.region; - -import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; -import com.github.luben.zstd.ZstdInputStream; -import com.github.luben.zstd.ZstdOutputStream; -import com.mojang.logging.LogUtils; -import net.jpountz.lz4.LZ4Compressor; -import net.jpountz.lz4.LZ4Factory; -import net.jpountz.lz4.LZ4FastDecompressor; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.ChunkPos; -import net.openhft.hashing.LongHashFunction; -import org.bxteam.divinemc.config.DivineConfig; -import org.bxteam.divinemc.spark.ThreadDumperRegistry; -import org.jspecify.annotations.Nullable; -import org.slf4j.Logger; - -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.LockSupport; - -public class LinearRegionFile implements IRegionFile { - public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; - private static final Object SAVE_LOCK = new Object(); - private static final long SUPERBLOCK = 0xc3ff13183cca9d9aL; - private static final Logger LOGGER = LogUtils.getLogger(); - - private static final byte V1_VERSION = 2; - private static final byte V2_VERSION = 3; - - private byte[][] bucketBuffers; - private final byte[][] chunkCompressedBuffers = new byte[1024][]; - private final int[] chunkUncompressedSizes = new int[1024]; - private final long[] chunkTimestamps = new long[1024]; - - private final Object markedToSaveLock = new Object(); - private boolean markedToSave = false; - - private final LZ4Compressor compressor; - private final LZ4FastDecompressor decompressor; - - private volatile boolean regionFileOpen = false; - private volatile boolean close = false; - - private final Path regionFilePath; - private final int gridSizeDefault = 8; - private int gridSize = gridSizeDefault; - private int bucketSize = 4; - private final int compressionLevel; - private final LinearImplementation linearImpl; - private final Thread schedulingThread; - - private static int activeSaveThreads = 0; - - public LinearRegionFile(Path path, LinearImplementation linearImplementation, int compressionLevel) { - this.regionFilePath = path; - this.linearImpl = linearImplementation; - this.compressionLevel = compressionLevel; - this.compressor = LZ4Factory.fastestInstance().fastCompressor(); - this.decompressor = LZ4Factory.fastestInstance().fastDecompressor(); - - Runnable flushCheck = () -> { - while (!close) { - synchronized (SAVE_LOCK) { - if (markedToSave && activeSaveThreads < DivineConfig.MiscCategory.linearFlushMaxThreads) { - activeSaveThreads++; - Runnable flushOperation = () -> { - try { - flush(); - } catch (IOException ex) { - LOGGER.error("Region file {} flush failed", regionFilePath.toAbsolutePath(), ex); - } finally { - synchronized (SAVE_LOCK) { - activeSaveThreads--; - } - } - }; - Thread saveThread = DivineConfig.MiscCategory.linearUseVirtualThread - ? Thread.ofVirtual().name("Linear IO - " + this.hashCode()).unstarted(flushOperation) - : Thread.ofPlatform().name("Linear IO - " + this.hashCode()).unstarted(flushOperation); - saveThread.setPriority(Thread.NORM_PRIORITY - 3); - saveThread.start(); - ThreadDumperRegistry.REGISTRY.add(saveThread.getName()); - } - } - LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(DivineConfig.MiscCategory.linearFlushDelay)); - } - }; - this.schedulingThread = DivineConfig.MiscCategory.linearUseVirtualThread - ? Thread.ofVirtual().unstarted(flushCheck) - : Thread.ofPlatform().unstarted(flushCheck); - this.schedulingThread.setName("Linear IO Schedule - " + this.hashCode()); - ThreadDumperRegistry.REGISTRY.add(this.schedulingThread.getName()); - } - - private synchronized void openRegionFile() { - if (regionFileOpen) return; - regionFileOpen = true; - - File file = regionFilePath.toFile(); - if (!file.canRead()) { - schedulingThread.start(); - return; - } - - try { - byte[] fileContent = Files.readAllBytes(regionFilePath); - ByteBuffer byteBuffer = ByteBuffer.wrap(fileContent); - - long superBlock = byteBuffer.getLong(); - if (superBlock != SUPERBLOCK) { - throw new RuntimeException("Invalid superblock: " + superBlock + " file " + regionFilePath); - } - - byte version = byteBuffer.get(); - if (version == V1_VERSION) { - parseLinearV1(byteBuffer); - } else if (version == V2_VERSION) { - parseLinearV2(byteBuffer); - } else { - throw new RuntimeException("Invalid version: " + version + " file " + regionFilePath); - } - - schedulingThread.start(); - } catch (IOException e) { - throw new RuntimeException("Failed to open region file " + regionFilePath, e); - } - } - - private void parseLinearV1(ByteBuffer buffer) throws IOException { - final int HEADER_SIZE = 32; - final int FOOTER_SIZE = 8; - buffer.position(buffer.position() + 11); - - int dataCount = buffer.getInt(); - long fileLength = regionFilePath.toFile().length(); - if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) { - throw new IOException("Invalid file length: " + regionFilePath + " " + fileLength + " expected " + (HEADER_SIZE + dataCount + FOOTER_SIZE)); - } - - buffer.position(buffer.position() + 8); - - byte[] rawCompressed = new byte[dataCount]; - buffer.get(rawCompressed); - - try (ByteArrayInputStream bais = new ByteArrayInputStream(rawCompressed); - ZstdInputStream zstdIn = new ZstdInputStream(bais)) { - ByteBuffer decompressedBuffer = ByteBuffer.wrap(zstdIn.readAllBytes()); - int[] starts = new int[1024]; - for (int i = 0; i < 1024; i++) { - starts[i] = decompressedBuffer.getInt(); - decompressedBuffer.getInt(); - } - - for (int i = 0; i < 1024; i++) { - if (starts[i] > 0) { - int size = starts[i]; - byte[] chunkData = new byte[size]; - decompressedBuffer.get(chunkData); - - int maxCompressedLength = compressor.maxCompressedLength(size); - byte[] compressed = new byte[maxCompressedLength]; - int compressedLength = compressor.compress(chunkData, 0, size, compressed, 0, maxCompressedLength); - byte[] finalCompressed = new byte[compressedLength]; - System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength); - - chunkCompressedBuffers[i] = finalCompressed; - chunkUncompressedSizes[i] = size; - chunkTimestamps[i] = currentTimestamp(); - } - } - } - } - - private void parseLinearV2(ByteBuffer buffer) throws IOException { - buffer.getLong(); - gridSize = buffer.get(); - if (!(gridSize == 1 || gridSize == 2 || gridSize == 4 || gridSize == 8 || gridSize == 16 || gridSize == 32)) { - throw new RuntimeException("Invalid grid size: " + gridSize + " file " + regionFilePath); - } - bucketSize = 32 / gridSize; - - buffer.getInt(); - buffer.getInt(); - - boolean[] chunkExistenceBitmap = deserializeExistenceBitmap(buffer); - - while (true) { - byte featureNameLength = buffer.get(); - if (featureNameLength == 0) break; - byte[] featureNameBytes = new byte[featureNameLength]; - buffer.get(featureNameBytes); - String featureName = new String(featureNameBytes); - int featureValue = buffer.getInt(); - } - - int bucketCount = gridSize * gridSize; - int[] bucketSizes = new int[bucketCount]; - byte[] bucketCompressionLevels = new byte[bucketCount]; - long[] bucketHashes = new long[bucketCount]; - - for (int i = 0; i < bucketCount; i++) { - bucketSizes[i] = buffer.getInt(); - bucketCompressionLevels[i] = buffer.get(); - bucketHashes[i] = buffer.getLong(); - } - - bucketBuffers = new byte[bucketCount][]; - for (int i = 0; i < bucketCount; i++) { - if (bucketSizes[i] > 0) { - bucketBuffers[i] = new byte[bucketSizes[i]]; - buffer.get(bucketBuffers[i]); - long rawHash = LongHashFunction.xx().hashBytes(bucketBuffers[i]); - if (rawHash != bucketHashes[i]) { - throw new IOException("Region file hash incorrect " + regionFilePath); - } - } - } - - long footerSuperBlock = buffer.getLong(); - if (footerSuperBlock != SUPERBLOCK) { - throw new IOException("Footer superblock invalid " + regionFilePath); - } - } - - private synchronized void markToSave() { - synchronized (markedToSaveLock) { - markedToSave = true; - } - } - - private synchronized boolean isMarkedToSave() { - synchronized (markedToSaveLock) { - if (markedToSave) { - markedToSave = false; - return true; - } - return false; - } - } - - @Override - public synchronized boolean doesChunkExist(ChunkPos pos) { - openRegionFile(); - return hasChunk(pos); - } - - @Override - public synchronized boolean hasChunk(ChunkPos pos) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - int index = getChunkIndex(pos.x, pos.z); - return chunkUncompressedSizes[index] > 0; - } - - @Override - public synchronized void flush() throws IOException { - if (!isMarkedToSave()) return; - openRegionFile(); - if (linearImpl == LinearImplementation.V1) { - flushLinearV1(); - } else if (linearImpl == LinearImplementation.V2) { - flushLinearV2(); - } - } - - private void flushLinearV1() throws IOException { - long timestamp = currentTimestamp(); - short chunkCount = 0; - File tempFile = new File(regionFilePath.toString() + ".tmp"); - - try (FileOutputStream fos = new FileOutputStream(tempFile); - ByteArrayOutputStream zstdBAOS = new ByteArrayOutputStream(); - ZstdOutputStream zstdOut = new ZstdOutputStream(zstdBAOS, compressionLevel); - DataOutputStream zstdDataOut = new DataOutputStream(zstdOut); - DataOutputStream fileDataOut = new DataOutputStream(fos)) { - - fileDataOut.writeLong(SUPERBLOCK); - fileDataOut.writeByte(V1_VERSION); - fileDataOut.writeLong(timestamp); - fileDataOut.writeByte(compressionLevel); - - ArrayList decompressedChunks = new ArrayList<>(1024); - for (int i = 0; i < 1024; i++) { - if (chunkUncompressedSizes[i] != 0) { - chunkCount++; - byte[] decompressed = new byte[chunkUncompressedSizes[i]]; - decompressor.decompress(chunkCompressedBuffers[i], 0, decompressed, 0, chunkUncompressedSizes[i]); - decompressedChunks.add(decompressed); - } else { - decompressedChunks.add(null); - } - } - - for (int i = 0; i < 1024; i++) { - zstdDataOut.writeInt(chunkUncompressedSizes[i]); - zstdDataOut.writeInt((int) chunkTimestamps[i]); - } - - for (int i = 0; i < 1024; i++) { - if (decompressedChunks.get(i) != null) { - zstdDataOut.write(decompressedChunks.get(i)); - } - } - zstdDataOut.close(); - - fileDataOut.writeShort(chunkCount); - byte[] compressedZstdData = zstdBAOS.toByteArray(); - fileDataOut.writeInt(compressedZstdData.length); - fileDataOut.writeLong(0); - fileDataOut.write(compressedZstdData); - fileDataOut.writeLong(SUPERBLOCK); - - fileDataOut.flush(); - fos.getFD().sync(); - fos.getChannel().force(true); - } - Files.move(tempFile.toPath(), regionFilePath, StandardCopyOption.REPLACE_EXISTING); - } - - private void flushLinearV2() throws IOException { - long timestamp = currentTimestamp(); - File tempFile = new File(regionFilePath.toString() + ".tmp"); - - try (FileOutputStream fos = new FileOutputStream(tempFile); - DataOutputStream dataOut = new DataOutputStream(fos)) { - - dataOut.writeLong(SUPERBLOCK); - dataOut.writeByte(V2_VERSION); - dataOut.writeLong(timestamp); - dataOut.writeByte(gridSize); - - int[] regionCoords = parseRegionCoordinates(regionFilePath.getFileName().toString()); - dataOut.writeInt(regionCoords[0]); - dataOut.writeInt(regionCoords[1]); - - boolean[] chunkExistence = new boolean[1024]; - for (int i = 0; i < 1024; i++) { - chunkExistence[i] = (chunkUncompressedSizes[i] > 0); - } - writeExistenceBitmap(dataOut, chunkExistence); - - writeNBTFeatures(dataOut); - - byte[][] buckets = buildBuckets(); - - int bucketCount = gridSize * gridSize; - for (int i = 0; i < bucketCount; i++) { - dataOut.writeInt(buckets[i] != null ? buckets[i].length : 0); - dataOut.writeByte(compressionLevel); - long bucketHash = buckets[i] != null ? LongHashFunction.xx().hashBytes(buckets[i]) : 0; - dataOut.writeLong(bucketHash); - } - for (int i = 0; i < bucketCount; i++) { - if (buckets[i] != null) { - dataOut.write(buckets[i]); - } - } - dataOut.writeLong(SUPERBLOCK); - - dataOut.flush(); - fos.getFD().sync(); - fos.getChannel().force(true); - } - Files.move(tempFile.toPath(), regionFilePath, StandardCopyOption.REPLACE_EXISTING); - } - - private void writeNBTFeatures(DataOutputStream dataOut) throws IOException { - dataOut.writeByte(0); - } - - private byte[][] buildBuckets() throws IOException { - int bucketCount = gridSize * gridSize; - byte[][] buckets = new byte[bucketCount][]; - - for (int bx = 0; bx < gridSize; bx++) { - for (int bz = 0; bz < gridSize; bz++) { - int bucketIdx = bx * gridSize + bz; - if (bucketBuffers != null && bucketBuffers[bucketIdx] != null) { - buckets[bucketIdx] = bucketBuffers[bucketIdx]; - continue; - } - - try (ByteArrayOutputStream bucketBAOS = new ByteArrayOutputStream(); - ZstdOutputStream bucketZstdOut = new ZstdOutputStream(bucketBAOS, compressionLevel); - DataOutputStream bucketDataOut = new DataOutputStream(bucketZstdOut)) { - - boolean hasData = false; - int cellCount = 32 / gridSize; - for (int cx = 0; cx < cellCount; cx++) { - for (int cz = 0; cz < cellCount; cz++) { - int chunkIndex = (bx * cellCount + cx) + (bz * cellCount + cz) * 32; - if (chunkUncompressedSizes[chunkIndex] > 0) { - hasData = true; - byte[] chunkData = new byte[chunkUncompressedSizes[chunkIndex]]; - decompressor.decompress(chunkCompressedBuffers[chunkIndex], 0, chunkData, 0, chunkUncompressedSizes[chunkIndex]); - bucketDataOut.writeInt(chunkData.length + 8); - bucketDataOut.writeLong(chunkTimestamps[chunkIndex]); - bucketDataOut.write(chunkData); - } else { - bucketDataOut.writeInt(0); - bucketDataOut.writeLong(chunkTimestamps[chunkIndex]); - } - } - } - bucketDataOut.close(); - if (hasData) { - buckets[bucketIdx] = bucketBAOS.toByteArray(); - } - } - } - } - return buckets; - } - - private void openBucketForChunk(int chunkX, int chunkZ) { - int modX = Math.floorMod(chunkX, 32); - int modZ = Math.floorMod(chunkZ, 32); - int bucketIdx = chunkToBucketIndex(modX, modZ); - if (bucketBuffers == null || bucketBuffers[bucketIdx] == null) { - return; - } - - try (ByteArrayInputStream bucketBAIS = new ByteArrayInputStream(bucketBuffers[bucketIdx]); - ZstdInputStream bucketZstdIn = new ZstdInputStream(bucketBAIS)) { - - ByteBuffer bucketBuffer = ByteBuffer.wrap(bucketZstdIn.readAllBytes()); - int cellsPerBucket = 32 / gridSize; - int bx = modX / bucketSize, bz = modZ / bucketSize; - for (int cx = 0; cx < cellsPerBucket; cx++) { - for (int cz = 0; cz < cellsPerBucket; cz++) { - int chunkIndex = (bx * cellsPerBucket + cx) + (bz * cellsPerBucket + cz) * 32; - int chunkSize = bucketBuffer.getInt(); - long timestamp = bucketBuffer.getLong(); - chunkTimestamps[chunkIndex] = timestamp; - - if (chunkSize > 0) { - byte[] chunkData = new byte[chunkSize - 8]; - bucketBuffer.get(chunkData); - - int maxCompressedLength = compressor.maxCompressedLength(chunkData.length); - byte[] compressed = new byte[maxCompressedLength]; - int compressedLength = compressor.compress(chunkData, 0, chunkData.length, compressed, 0, maxCompressedLength); - byte[] finalCompressed = new byte[compressedLength]; - System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength); - - chunkCompressedBuffers[chunkIndex] = finalCompressed; - chunkUncompressedSizes[chunkIndex] = chunkData.length; - } - } - } - } catch (IOException ex) { - throw new RuntimeException("Region file corrupted: " + regionFilePath + " bucket: " + bucketIdx, ex); - } - bucketBuffers[bucketIdx] = null; - } - - @Override - public synchronized void write(ChunkPos pos, ByteBuffer buffer) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - try { - byte[] rawData = toByteArray(new ByteArrayInputStream(buffer.array())); - int uncompressedSize = rawData.length; - if (uncompressedSize > MAX_CHUNK_SIZE) { - LOGGER.error("Chunk dupe attempt {}", regionFilePath); - clear(pos); - } else { - int maxCompressedLength = compressor.maxCompressedLength(uncompressedSize); - byte[] compressed = new byte[maxCompressedLength]; - int compressedLength = compressor.compress(rawData, 0, uncompressedSize, compressed, 0, maxCompressedLength); - byte[] finalCompressed = new byte[compressedLength]; - System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength); - - int index = getChunkIndex(pos.x, pos.z); - chunkCompressedBuffers[index] = finalCompressed; - chunkTimestamps[index] = currentTimestamp(); - chunkUncompressedSizes[index] = uncompressedSize; - } - } catch (IOException e) { - LOGGER.error("Chunk write IOException {} {}", e, regionFilePath); - } - markToSave(); - } - - @Override - public DataOutputStream getChunkDataOutputStream(ChunkPos pos) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos))); - } - - @Override - public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) { - DataOutputStream out = getChunkDataOutputStream(pos); - return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData( - data, - ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE, - out, - regionFile -> { - try { - out.close(); - } catch (IOException e) { - LOGGER.error("Failed to close region file stream", e); - } - } - ); - } - - private class ChunkBuffer extends ByteArrayOutputStream { - private final ChunkPos pos; - public ChunkBuffer(ChunkPos pos) { - super(); - this.pos = pos; - } - @Override - public void close() { - ByteBuffer byteBuffer = ByteBuffer.wrap(this.buf, 0, this.count); - LinearRegionFile.this.write(this.pos, byteBuffer); - } - } - - private byte[] toByteArray(InputStream in) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] tempBuffer = new byte[4096]; - int length; - while ((length = in.read(tempBuffer)) >= 0) { - out.write(tempBuffer, 0, length); - } - return out.toByteArray(); - } - - @Nullable - @Override - public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - int index = getChunkIndex(pos.x, pos.z); - if (chunkUncompressedSizes[index] != 0) { - byte[] decompressed = new byte[chunkUncompressedSizes[index]]; - decompressor.decompress(chunkCompressedBuffers[index], 0, decompressed, 0, chunkUncompressedSizes[index]); - return new DataInputStream(new ByteArrayInputStream(decompressed)); - } - return null; - } - - @Override - public synchronized void clear(ChunkPos pos) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - int index = getChunkIndex(pos.x, pos.z); - chunkCompressedBuffers[index] = null; - chunkUncompressedSizes[index] = 0; - chunkTimestamps[index] = 0; - markToSave(); - } - - @Override - public synchronized void close() throws IOException { - openRegionFile(); - close = true; - try { - flush(); - } catch (IOException e) { - throw new IOException("Region flush IOException " + e + " " + regionFilePath, e); - } - } - - private static int getChunkIndex(int x, int z) { - return (x & 31) + ((z & 31) << 5); - } - - private static int currentTimestamp() { - return (int) (System.currentTimeMillis() / 1000L); - } - - @Override - public boolean recalculateHeader() { - return false; - } - - @Override - public int getRecalculateCount() { - return 0; - } - - @Override - public void setOversized(int x, int z, boolean something) { - // stub - } - - @Override - public CompoundTag getOversizedData(int x, int z) throws IOException { - throw new IOException("getOversizedData is a stub " + regionFilePath); - } - - @Override - public boolean isOversized(int x, int z) { - return false; - } - - @Override - public Path getPath() { - return regionFilePath; - } - - private boolean[] deserializeExistenceBitmap(ByteBuffer buffer) { - boolean[] result = new boolean[1024]; - for (int i = 0; i < 128; i++) { - byte b = buffer.get(); - for (int j = 0; j < 8; j++) { - result[i * 8 + j] = ((b >> (7 - j)) & 1) == 1; - } - } - return result; - } - - private void writeExistenceBitmap(DataOutputStream out, boolean[] bitmap) throws IOException { - for (int i = 0; i < 128; i++) { - byte b = 0; - for (int j = 0; j < 8; j++) { - if (bitmap[i * 8 + j]) { - b |= (1 << (7 - j)); - } - } - out.writeByte(b); - } - } - - private int chunkToBucketIndex(int chunkX, int chunkZ) { - int bx = chunkX / bucketSize, bz = chunkZ / bucketSize; - return bx * gridSize + bz; - } - - private int[] parseRegionCoordinates(String fileName) { - int regionX = 0; - int regionZ = 0; - String[] parts = fileName.split("\\."); - if (parts.length >= 4) { - try { - regionX = Integer.parseInt(parts[1]); - regionZ = Integer.parseInt(parts[2]); - } catch (NumberFormatException e) { - LOGGER.error("Failed to parse region coordinates from file name: {}", fileName, e); - } - } else { - LOGGER.warn("Unexpected file name format: {}", fileName); - } - return new int[]{regionX, regionZ}; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFactory.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFactory.java deleted file mode 100644 index 6d9584b..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bxteam.divinemc.region; - -import net.minecraft.world.level.chunk.storage.RegionFile; -import net.minecraft.world.level.chunk.storage.RegionFileVersion; -import net.minecraft.world.level.chunk.storage.RegionStorageInfo; -import org.bxteam.divinemc.config.DivineConfig; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.nio.file.Path; - -public class RegionFileFactory { - @Contract("_, _, _, _ -> new") - public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { - return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); - } - - @Contract("_, _, _, _, _ -> new") - public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, @NotNull Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException { - final String fullFileName = path.getFileName().toString(); - final String[] fullNameSplit = fullFileName.split("\\."); - final String extensionName = fullNameSplit[fullNameSplit.length - 1]; - switch (RegionFileFormat.fromExtension(extensionName)) { - case LINEAR -> { - return new LinearRegionFile(path, DivineConfig.MiscCategory.linearImplementation, DivineConfig.MiscCategory.linearCompressionLevel); - } - - default -> { - return new RegionFile(storageKey, path, directory, compressionFormat, dsync); - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java deleted file mode 100644 index 30a54e5..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.bxteam.divinemc.region; - -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import java.util.Locale; - -public enum RegionFileFormat { - LINEAR(".linear"), - ANVIL(".mca"), - UNKNOWN(null); - - private final String extension; - - RegionFileFormat(String extension) { - this.extension = extension; - } - - public String getExtensionName() { - return this.extension; - } - - @Contract(pure = true) - public static RegionFileFormat fromName(@NotNull String name) { - switch (name.toUpperCase(Locale.ROOT)) { - case "MCA", "ANVIL" -> { - return ANVIL; - } - - case "LINEAR" -> { - return LINEAR; - } - - default -> { - throw new IllegalArgumentException("Unknown region file format: " + name); - } - } - } - - @Contract(pure = true) - public static RegionFileFormat fromExtension(@NotNull String name) { - switch (name.toLowerCase()) { - case "mca", "anvil" -> { - return ANVIL; - } - - case "linear" -> { - return LINEAR; - } - - default -> { - return UNKNOWN; - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/ChunkSystemTaskQueue.java b/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/ChunkSystemTaskQueue.java deleted file mode 100644 index 9842ea2..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/ChunkSystemTaskQueue.java +++ /dev/null @@ -1,404 +0,0 @@ -package org.bxteam.divinemc.server.chunk; - -import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor; -import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; -import ca.spottedleaf.concurrentutil.util.Priority; - -import java.lang.invoke.VarHandle; -import java.util.Comparator; -import java.util.Map; -import java.util.concurrent.ConcurrentSkipListMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - -public final class ChunkSystemTaskQueue implements PrioritisedExecutor { - private final AtomicLong taskIdGenerator = new AtomicLong(); - private final AtomicLong scheduledTasks = new AtomicLong(); - private final AtomicLong executedTasks = new AtomicLong(); - private final AtomicLong subOrderGenerator = new AtomicLong(); - private final AtomicBoolean shutdown = new AtomicBoolean(); - private final ConcurrentSkipListMap tasks = new ConcurrentSkipListMap<>(ChunkSystemTaskQueue.PrioritisedQueuedTask.COMPARATOR); - private final TheChunkSystem chunkSystem; - - public ChunkSystemTaskQueue(TheChunkSystem chunkSystem) { - this.chunkSystem = chunkSystem; - } - - @Override - public long getTotalTasksScheduled() { - return this.scheduledTasks.get(); - } - - @Override - public long getTotalTasksExecuted() { - return this.executedTasks.get(); - } - - @Override - public long generateNextSubOrder() { - return this.subOrderGenerator.getAndIncrement(); - } - - @Override - public boolean shutdown() { - return !this.shutdown.getAndSet(true); - } - - @Override - public boolean isShutdown() { - return this.shutdown.get(); - } - - @Override - public boolean executeTask() { - for (; ; ) { - final Map.Entry firstEntry = this.tasks.pollFirstEntry(); - if (firstEntry != null) { - final ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder task = firstEntry.getKey(); - task.markRemoved(); - if (!task.task.execute()) { - continue; - } - return true; - } - - return false; - } - } - - @Override - public PrioritisedTask createTask(final Runnable task) { - return this.createTask(task, Priority.NORMAL, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask createTask(final Runnable task, final Priority priority) { - return this.createTask(task, priority, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask createTask(final Runnable task, final Priority priority, final long subOrder) { - return new ChunkSystemTaskQueue.PrioritisedQueuedTask(task, priority, subOrder); - } - - @Override - public PrioritisedTask queueTask(final Runnable task) { - return this.queueTask(task, Priority.NORMAL, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask queueTask(final Runnable task, final Priority priority) { - return this.queueTask(task, priority, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask queueTask(final Runnable task, final Priority priority, final long subOrder) { - final ChunkSystemTaskQueue.PrioritisedQueuedTask ret = new ChunkSystemTaskQueue.PrioritisedQueuedTask(task, priority, subOrder); - - ret.queue(); - - return ret; - } - - private final class PrioritisedQueuedTask implements PrioritisedExecutor.PrioritisedTask { - public static final Comparator COMPARATOR = (final ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder t1, final ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder t2) -> { - final int priorityCompare = t1.priority - t2.priority; - if (priorityCompare != 0) { - return priorityCompare; - } - - final int subOrderCompare = Long.compare(t1.subOrder, t2.subOrder); - if (subOrderCompare != 0) { - return subOrderCompare; - } - - return Long.compare(t1.id, t2.id); - }; - private final long id; - private final Runnable execute; - private Priority priority; - private long subOrder; - private ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder holder; - - public PrioritisedQueuedTask(final Runnable execute, final Priority priority, final long subOrder) { - if (!Priority.isValidPriority(priority)) { - throw new IllegalArgumentException("Invalid priority " + priority); - } - - this.execute = execute; - this.priority = priority; - this.subOrder = subOrder; - this.id = ChunkSystemTaskQueue.this.taskIdGenerator.getAndIncrement(); - } - - @Override - public PrioritisedExecutor getExecutor() { - return ChunkSystemTaskQueue.this; - } - - @Override - public boolean queue() { - synchronized (this) { - if (this.holder != null || this.priority == Priority.COMPLETING) { - return false; - } - - if (ChunkSystemTaskQueue.this.isShutdown()) { - throw new IllegalStateException("Queue is shutdown"); - } - - this.holder = new Holder(this, this.priority.priority, this.subOrder, this.id); - - ChunkSystemTaskQueue.this.scheduledTasks.getAndIncrement(); - ChunkSystemTaskQueue.this.chunkSystem.schedule(this.holder.task.execute, this.holder.task.priority.priority); - } - - if (ChunkSystemTaskQueue.this.isShutdown()) { - this.cancel(); - throw new IllegalStateException("Queue is shutdown"); - } - - return true; - } - - @Override - public boolean isQueued() { - synchronized (this) { - return this.holder != null && this.priority != Priority.COMPLETING; - } - } - - @Override - public boolean cancel() { - synchronized (this) { - if (this.priority == Priority.COMPLETING) { - return false; - } - - this.priority = Priority.COMPLETING; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - ChunkSystemTaskQueue.this.executedTasks.getAndIncrement(); - } - - return true; - } - } - - @Override - public boolean execute() { - final boolean increaseExecuted; - - synchronized (this) { - if (this.priority == Priority.COMPLETING) { - return false; - } - - this.priority = Priority.COMPLETING; - - if (increaseExecuted = (this.holder != null)) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - } - } - - try { - this.execute.run(); - return true; - } finally { - if (increaseExecuted) { - ChunkSystemTaskQueue.this.executedTasks.getAndIncrement(); - } - } - } - - @Override - public Priority getPriority() { - synchronized (this) { - return this.priority; - } - } - - @Override - public boolean setPriority(final Priority priority) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.priority == priority) { - return false; - } - - this.priority = priority; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean raisePriority(final Priority priority) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.priority.isHigherOrEqualPriority(priority)) { - return false; - } - - this.priority = priority; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean lowerPriority(Priority priority) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.priority.isLowerOrEqualPriority(priority)) { - return false; - } - - this.priority = priority; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public long getSubOrder() { - synchronized (this) { - return this.subOrder; - } - } - - @Override - public boolean setSubOrder(final long subOrder) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.subOrder == subOrder) { - return false; - } - - this.subOrder = subOrder; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean raiseSubOrder(long subOrder) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.subOrder >= subOrder) { - return false; - } - - this.subOrder = subOrder; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean lowerSubOrder(final long subOrder) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.subOrder <= subOrder) { - return false; - } - - this.subOrder = subOrder; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean setPriorityAndSubOrder(final Priority priority, final long subOrder) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || (this.priority == priority && this.subOrder == subOrder)) { - return false; - } - - this.priority = priority; - this.subOrder = subOrder; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - private static final class Holder { - private static final VarHandle REMOVED_HANDLE = ConcurrentUtil.getVarHandle(ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder.class, "removed", boolean.class); - private final ChunkSystemTaskQueue.PrioritisedQueuedTask task; - private final int priority; - private final long subOrder; - private final long id; - private volatile boolean removed; - - private Holder( - final ChunkSystemTaskQueue.PrioritisedQueuedTask task, final int priority, final long subOrder, - final long id - ) { - this.task = task; - this.priority = priority; - this.subOrder = subOrder; - this.id = id; - } - - public boolean markRemoved() { - return !(boolean) REMOVED_HANDLE.getAndSet((ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder) this, (boolean) true); - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/TheChunkSystem.java b/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/TheChunkSystem.java deleted file mode 100644 index 2a51c6f..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/TheChunkSystem.java +++ /dev/null @@ -1,355 +0,0 @@ -package org.bxteam.divinemc.server.chunk; - -import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor; -import ca.spottedleaf.concurrentutil.util.Priority; -import com.ishland.flowsched.executor.ExecutorManager; -import org.bxteam.divinemc.util.ThreadBuilder; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.lang.reflect.Array; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicLong; - -public class TheChunkSystem extends ExecutorManager { - protected final Logger LOGGER = LoggerFactory.getLogger("TheChunkSystem"); - - private final TheChunkSystem.COWArrayList executors = new TheChunkSystem.COWArrayList<>(TheChunkSystem.ExecutorGroup.class); - private boolean shutdown; - - public TheChunkSystem(final int workerThreadCount, final ThreadBuilder threadInitializer) { - super(workerThreadCount, threadInitializer); - LOGGER.info("Initialized new ChunkSystem with {} allocated threads", workerThreadCount); - } - - @Override - public void shutdown() { - synchronized (this) { - this.shutdown = true; - } - - super.shutdown(); - this.wakeup(); - - for (final TheChunkSystem.ExecutorGroup group : this.executors.getArray()) { - for (final TheChunkSystem.ExecutorGroup.ThreadPoolExecutor executor : group.executors.getArray()) { - executor.shutdown(); - } - } - - LOGGER.info("ChunkSystem shutdown complete"); - } - - private void notifyAllThreads() { - this.wakeup(); - } - - public TheChunkSystem.ExecutorGroup createExecutorGroup() { - synchronized (this) { - if (this.shutdown) { - throw new IllegalStateException("Queue is shutdown: " + this); - } - - final TheChunkSystem.ExecutorGroup ret = new TheChunkSystem.ExecutorGroup(); - - this.executors.add(ret); - - return ret; - } - } - - private static final class COWArrayList { - private volatile E[] array; - - public COWArrayList(final Class clazz) { - this.array = (E[]) Array.newInstance(clazz, 0); - } - - public E[] getArray() { - return this.array; - } - - public void add(final E element) { - synchronized (this) { - final E[] array = this.array; - - final E[] copy = Arrays.copyOf(array, array.length + 1); - copy[array.length] = element; - - this.array = copy; - } - } - - public boolean remove(final E element) { - synchronized (this) { - final E[] array = this.array; - int index = -1; - for (int i = 0, len = array.length; i < len; ++i) { - if (array[i] == element) { - index = i; - break; - } - } - - if (index == -1) { - return false; - } - - final E[] copy = (E[]) Array.newInstance(array.getClass().getComponentType(), array.length - 1); - - System.arraycopy(array, 0, copy, 0, index); - System.arraycopy(array, index + 1, copy, index, (array.length - 1) - index); - - this.array = copy; - } - - return true; - } - } - - public final class ExecutorGroup { - private final AtomicLong subOrderGenerator = new AtomicLong(); - private final TheChunkSystem.COWArrayList executors = new TheChunkSystem.COWArrayList<>(TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.class); - - private ExecutorGroup() { } - - public TheChunkSystem.ExecutorGroup.ThreadPoolExecutor[] getAllExecutors() { - return this.executors.getArray().clone(); - } - - private TheChunkSystem getThreadPool() { - return TheChunkSystem.this; - } - - public TheChunkSystem.ExecutorGroup.@NotNull ThreadPoolExecutor createExecutor() { - synchronized (TheChunkSystem.this) { - if (TheChunkSystem.this.shutdown) { - throw new IllegalStateException("Queue is shutdown: " + TheChunkSystem.this); - } - - final TheChunkSystem.ExecutorGroup.ThreadPoolExecutor ret = new TheChunkSystem.ExecutorGroup.ThreadPoolExecutor(); - - this.executors.add(ret); - - return ret; - } - } - - public final class ThreadPoolExecutor implements PrioritisedExecutor { - private final ChunkSystemTaskQueue taskBuilder = new ChunkSystemTaskQueue(TheChunkSystem.this); - private volatile boolean halt; - - private ThreadPoolExecutor() { } - - private TheChunkSystem.ExecutorGroup getGroup() { - return TheChunkSystem.ExecutorGroup.this; - } - - private void notifyPriorityShift() { - TheChunkSystem.this.notifyAllThreads(); - } - - private void notifyScheduled() { - TheChunkSystem.this.notifyAllThreads(); - } - - /** - * Removes this queue from the thread pool without shutting the queue down or waiting for queued tasks to be executed - */ - public void halt() { - this.halt = true; - - TheChunkSystem.ExecutorGroup.this.executors.remove(this); - } - - public boolean isActive() { - if (this.halt) { - return false; - } else { - if (!this.isShutdown()) { - return true; - } - - return !TheChunkSystem.this.globalWorkQueue.isEmpty(); - } - } - - @Override - public boolean shutdown() { - if (TheChunkSystem.this.globalWorkQueue.isEmpty()) { - TheChunkSystem.ExecutorGroup.this.executors.remove(this); - } - - return true; - } - - @Override - public boolean isShutdown() { - return TheChunkSystem.this.shutdown; - } - - @Override - public long getTotalTasksScheduled() { - return 0; // TODO: implement - } - - @Override - public long getTotalTasksExecuted() { - return 0; // TODO: implement - } - - @Override - public long generateNextSubOrder() { - return TheChunkSystem.ExecutorGroup.this.subOrderGenerator.getAndIncrement(); - } - - @Override - public boolean executeTask() { - throw new UnsupportedOperationException("Unable to execute task from ThreadPoolExecutor as interface into FlowSched"); - } - - @Override - public PrioritisedTask queueTask(final Runnable task) { - final PrioritisedTask ret = this.createTask(task); - - ret.queue(); - - return ret; - } - - @Override - public PrioritisedTask queueTask(final Runnable task, final Priority priority) { - final PrioritisedTask ret = this.createTask(task, priority); - - ret.queue(); - - return ret; - } - - @Override - public PrioritisedTask queueTask(final Runnable task, final Priority priority, final long subOrder) { - final PrioritisedTask ret = this.createTask(task, priority, subOrder); - - ret.queue(); - - return ret; - } - - @Override - public PrioritisedTask createTask(final Runnable task) { - return this.createTask(task, Priority.NORMAL); - } - - @Override - public PrioritisedTask createTask(final Runnable task, final Priority priority) { - return this.createTask(task, priority, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask createTask(final Runnable task, final Priority priority, final long subOrder) { - return new TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.WrappedTask(this.taskBuilder.createTask(task, priority, subOrder)); - } - - private final class WrappedTask implements PrioritisedTask { - private final PrioritisedTask wrapped; - - private WrappedTask(final PrioritisedTask wrapped) { - this.wrapped = wrapped; - } - - @Override - public PrioritisedExecutor getExecutor() { - return TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this; - } - - @Override - public boolean queue() { - if (this.wrapped.queue()) { - final Priority priority = this.getPriority(); - if (priority != Priority.COMPLETING) { - TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyScheduled(); - } - return true; - } - - return false; - } - - @Override - public boolean isQueued() { - return this.wrapped.isQueued(); - } - - @Override - public boolean cancel() { - return this.wrapped.cancel(); - } - - @Override - public boolean execute() { - return this.wrapped.execute(); - } - - @Override - public Priority getPriority() { - return this.wrapped.getPriority(); - } - - @Override - public boolean setPriority(final Priority priority) { - if (this.wrapped.setPriority(priority)) { - TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyPriorityShift(); - return true; - } - - return false; - } - - @Override - public boolean raisePriority(final Priority priority) { - if (this.wrapped.raisePriority(priority)) { - TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyPriorityShift(); - return true; - } - - return false; - } - - @Override - public boolean lowerPriority(final Priority priority) { - return this.wrapped.lowerPriority(priority); - } - - @Override - public long getSubOrder() { - return this.wrapped.getSubOrder(); - } - - @Override - public boolean setSubOrder(final long subOrder) { - return this.wrapped.setSubOrder(subOrder); - } - - @Override - public boolean raiseSubOrder(final long subOrder) { - return this.wrapped.raiseSubOrder(subOrder); - } - - @Override - public boolean lowerSubOrder(final long subOrder) { - return this.wrapped.lowerSubOrder(subOrder); - } - - @Override - public boolean setPriorityAndSubOrder(final Priority priority, final long subOrder) { - if (this.wrapped.setPriorityAndSubOrder(priority, subOrder)) { - TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyPriorityShift(); - return true; - } - - return false; - } - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ConcurrentFlagMatrix.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/ConcurrentFlagMatrix.java deleted file mode 100644 index ed26ad6..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ConcurrentFlagMatrix.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.bxteam.divinemc.util; - -import java.util.concurrent.locks.ReentrantReadWriteLock; -import net.minecraft.world.level.levelgen.structure.structures.WoodlandMansionPieces; - -public class ConcurrentFlagMatrix extends WoodlandMansionPieces.SimpleGrid { - private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - - public ConcurrentFlagMatrix(int rows, int columns, int fallbackValue) { - super(rows, columns, fallbackValue); - } - - public void set(int row, int column, int value) { - this.readWriteLock.writeLock().lock(); - - try { - super.set(row, column, value); - } finally { - this.readWriteLock.writeLock().unlock(); - } - } - - public void set(int startRow, int startColumn, int endRow, int endColumn, int value) { - this.readWriteLock.writeLock().lock(); - - try { - super.set(startRow, startColumn, endRow, endColumn, value); - } finally { - this.readWriteLock.writeLock().unlock(); - } - } - - public int get(int row, int column) { - this.readWriteLock.readLock().lock(); - - int result; - try { - result = super.get(row, column); - } finally { - this.readWriteLock.readLock().unlock(); - } - - return result; - } - - public void setIf(int row, int column, int expectedValue, int newValue) { - if (this.get(row, column) == expectedValue) { - this.set(row, column, newValue); - } - } - - public boolean edgesTo(int row, int column, int value) { - this.readWriteLock.readLock().lock(); - - boolean result; - try { - result = super.edgesTo(row, column, value); - } finally { - this.readWriteLock.readLock().unlock(); - } - - return result; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java deleted file mode 100644 index 5f47188..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.bxteam.divinemc.util; - -import net.minecraft.util.Mth; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.levelgen.LegacyRandomSource; -import net.minecraft.world.level.levelgen.PositionalRandomFactory; -import net.minecraft.world.level.levelgen.SingleThreadedRandomSource; -import net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus; -import net.minecraft.world.level.levelgen.XoroshiroRandomSource; -import org.jetbrains.annotations.NotNull; - -public final class RandomUtil { - public static @NotNull RandomSource getRandom(PositionalRandomFactory deriver) { - if (deriver instanceof XoroshiroRandomSource.XoroshiroPositionalRandomFactory) { - return new XoroshiroRandomSource(0L, 0L); - } - if (deriver instanceof LegacyRandomSource.LegacyPositionalRandomFactory) { - return new SingleThreadedRandomSource(0L); - } - throw new IllegalArgumentException(); - } - - private static final ThreadLocal xoroshiro = ThreadLocal.withInitial(() -> new XoroshiroRandomSource(0L, 0L)); - private static final ThreadLocal simple = ThreadLocal.withInitial(() -> new SingleThreadedRandomSource(0L)); - - public static void derive(PositionalRandomFactory deriver, RandomSource random, int x, int y, int z) { - if (deriver instanceof final XoroshiroRandomSource.XoroshiroPositionalRandomFactory deriver1) { - final Xoroshiro128PlusPlus implementation = ((XoroshiroRandomSource) random).randomNumberGenerator; - implementation.seedLo = (Mth.getSeed(x, y, z) ^ deriver1.seedLo()); - implementation.seedHi = (deriver1.seedHi()); - return; - } - if (deriver instanceof LegacyRandomSource.LegacyPositionalRandomFactory(long seed)) { - final SingleThreadedRandomSource random1 = (SingleThreadedRandomSource) random; - random1.setSeed(Mth.getSeed(x, y, z) ^ seed); - return; - } - throw new IllegalArgumentException(); - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/SynchronizedCodec.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/SynchronizedCodec.java deleted file mode 100644 index 3fca958..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/SynchronizedCodec.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.bxteam.divinemc.util; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; -import java.util.concurrent.locks.ReentrantLock; - -public class SynchronizedCodec implements Codec { - private final ReentrantLock lock = new ReentrantLock(false); - private final Codec delegate; - - public SynchronizedCodec(Codec delegate) { - this.delegate = delegate; - } - - @Override - public DataResult> decode(DynamicOps ops, T input) { - try { - lock.lockInterruptibly(); - return this.delegate.decode(ops, input); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } finally { - if (lock.isHeldByCurrentThread()) lock.unlock(); - } - } - - @Override - public DataResult encode(A input, DynamicOps ops, T prefix) { - try { - lock.lockInterruptibly(); - return this.delegate.encode(input, ops, prefix); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } finally { - if (lock.isHeldByCurrentThread()) lock.unlock(); - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ThreadBuilder.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/ThreadBuilder.java deleted file mode 100644 index 3922885..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ThreadBuilder.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.bxteam.divinemc.util; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -public interface ThreadBuilder extends Consumer { - AtomicInteger id = new AtomicInteger(); - - default int getAndIncrementId() { - return id.getAndIncrement(); - } -} diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/map/MapPalette.java.patch b/patches/work/api/MapPalette.java.patch similarity index 100% rename from divinemc-api/paper-patches/files/src/main/java/org/bukkit/map/MapPalette.java.patch rename to patches/work/api/MapPalette.java.patch diff --git a/divinemc-server/minecraft-patches/features/0004-Implement-Secure-Seed.patch b/patches/work/server/minecraft/0004-Implement-Secure-Seed.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0004-Implement-Secure-Seed.patch rename to patches/work/server/minecraft/0004-Implement-Secure-Seed.patch diff --git a/divinemc-server/minecraft-patches/features/0005-Async-Pathfinding.patch b/patches/work/server/minecraft/0005-Async-Pathfinding.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0005-Async-Pathfinding.patch rename to patches/work/server/minecraft/0005-Async-Pathfinding.patch diff --git a/divinemc-server/minecraft-patches/features/0006-Async-locate-command.patch b/patches/work/server/minecraft/0006-Async-locate-command.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0006-Async-locate-command.patch rename to patches/work/server/minecraft/0006-Async-locate-command.patch diff --git a/divinemc-server/minecraft-patches/features/0007-Multithreaded-Tracker.patch b/patches/work/server/minecraft/0007-Multithreaded-Tracker.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0007-Multithreaded-Tracker.patch rename to patches/work/server/minecraft/0007-Multithreaded-Tracker.patch diff --git a/divinemc-server/minecraft-patches/features/0008-Misc-Optimizations.patch b/patches/work/server/minecraft/0008-Misc-Optimizations.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0008-Misc-Optimizations.patch rename to patches/work/server/minecraft/0008-Misc-Optimizations.patch diff --git a/divinemc-server/minecraft-patches/features/0009-Optimize-Fluids.patch b/patches/work/server/minecraft/0009-Optimize-Fluids.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0009-Optimize-Fluids.patch rename to patches/work/server/minecraft/0009-Optimize-Fluids.patch diff --git a/divinemc-server/minecraft-patches/features/0010-Chunk-System-Optimizations.patch b/patches/work/server/minecraft/0010-Chunk-System-Optimizations.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0010-Chunk-System-Optimizations.patch rename to patches/work/server/minecraft/0010-Chunk-System-Optimizations.patch diff --git a/divinemc-server/minecraft-patches/features/0011-Optimize-entity-stupid-brain.patch b/patches/work/server/minecraft/0011-Optimize-entity-stupid-brain.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0011-Optimize-entity-stupid-brain.patch rename to patches/work/server/minecraft/0011-Optimize-entity-stupid-brain.patch diff --git a/divinemc-server/minecraft-patches/features/0012-Lag-compensation.patch b/patches/work/server/minecraft/0012-Lag-compensation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0012-Lag-compensation.patch rename to patches/work/server/minecraft/0012-Lag-compensation.patch diff --git a/divinemc-server/minecraft-patches/features/0013-Implement-NoChatReports.patch b/patches/work/server/minecraft/0013-Implement-NoChatReports.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0013-Implement-NoChatReports.patch rename to patches/work/server/minecraft/0013-Implement-NoChatReports.patch diff --git a/divinemc-server/minecraft-patches/features/0014-Carpet-Fixes-RecipeManager-Optimize.patch b/patches/work/server/minecraft/0014-Carpet-Fixes-RecipeManager-Optimize.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0014-Carpet-Fixes-RecipeManager-Optimize.patch rename to patches/work/server/minecraft/0014-Carpet-Fixes-RecipeManager-Optimize.patch diff --git a/divinemc-server/minecraft-patches/features/0015-Optimize-explosions.patch b/patches/work/server/minecraft/0015-Optimize-explosions.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0015-Optimize-explosions.patch rename to patches/work/server/minecraft/0015-Optimize-explosions.patch diff --git a/divinemc-server/minecraft-patches/features/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch b/patches/work/server/minecraft/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch rename to patches/work/server/minecraft/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch diff --git a/divinemc-server/minecraft-patches/features/0017-Snowball-and-Egg-knockback.patch b/patches/work/server/minecraft/0017-Snowball-and-Egg-knockback.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0017-Snowball-and-Egg-knockback.patch rename to patches/work/server/minecraft/0017-Snowball-and-Egg-knockback.patch diff --git a/divinemc-server/minecraft-patches/features/0018-Block-Log4Shell-exploit.patch b/patches/work/server/minecraft/0018-Block-Log4Shell-exploit.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0018-Block-Log4Shell-exploit.patch rename to patches/work/server/minecraft/0018-Block-Log4Shell-exploit.patch diff --git a/divinemc-server/minecraft-patches/features/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch b/patches/work/server/minecraft/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch rename to patches/work/server/minecraft/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch diff --git a/divinemc-server/minecraft-patches/features/0020-Optimize-canSee-checks.patch b/patches/work/server/minecraft/0020-Optimize-canSee-checks.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0020-Optimize-canSee-checks.patch rename to patches/work/server/minecraft/0020-Optimize-canSee-checks.patch diff --git a/divinemc-server/minecraft-patches/features/0021-Verify-Minecraft-EULA-earlier.patch b/patches/work/server/minecraft/0021-Verify-Minecraft-EULA-earlier.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0021-Verify-Minecraft-EULA-earlier.patch rename to patches/work/server/minecraft/0021-Verify-Minecraft-EULA-earlier.patch diff --git a/divinemc-server/minecraft-patches/features/0022-Option-to-disable-saving-of-snowball-and-firework.patch b/patches/work/server/minecraft/0022-Option-to-disable-saving-of-snowball-and-firework.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0022-Option-to-disable-saving-of-snowball-and-firework.patch rename to patches/work/server/minecraft/0022-Option-to-disable-saving-of-snowball-and-firework.patch diff --git a/divinemc-server/minecraft-patches/features/0023-Re-Fix-MC-117075.patch b/patches/work/server/minecraft/0023-Re-Fix-MC-117075.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0023-Re-Fix-MC-117075.patch rename to patches/work/server/minecraft/0023-Re-Fix-MC-117075.patch diff --git a/divinemc-server/minecraft-patches/features/0024-Virtual-Threads.patch b/patches/work/server/minecraft/0024-Virtual-Threads.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0024-Virtual-Threads.patch rename to patches/work/server/minecraft/0024-Virtual-Threads.patch diff --git a/divinemc-server/minecraft-patches/features/0025-Optimize-Structure-Generation.patch b/patches/work/server/minecraft/0025-Optimize-Structure-Generation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0025-Optimize-Structure-Generation.patch rename to patches/work/server/minecraft/0025-Optimize-Structure-Generation.patch diff --git a/divinemc-server/minecraft-patches/features/0026-Option-to-disable-disconnect.spam.patch b/patches/work/server/minecraft/0026-Option-to-disable-disconnect.spam.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0026-Option-to-disable-disconnect.spam.patch rename to patches/work/server/minecraft/0026-Option-to-disable-disconnect.spam.patch diff --git a/divinemc-server/minecraft-patches/features/0027-Async-Chunk-Sending.patch b/patches/work/server/minecraft/0027-Async-Chunk-Sending.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0027-Async-Chunk-Sending.patch rename to patches/work/server/minecraft/0027-Async-Chunk-Sending.patch diff --git a/divinemc-server/minecraft-patches/features/0028-Configurable-MC-67.patch b/patches/work/server/minecraft/0028-Configurable-MC-67.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0028-Configurable-MC-67.patch rename to patches/work/server/minecraft/0028-Configurable-MC-67.patch diff --git a/divinemc-server/minecraft-patches/features/0029-Configurable-MC-59471.patch b/patches/work/server/minecraft/0029-Configurable-MC-59471.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0029-Configurable-MC-59471.patch rename to patches/work/server/minecraft/0029-Configurable-MC-59471.patch diff --git a/divinemc-server/minecraft-patches/features/0030-ModernFix-compact_bit_storage.patch b/patches/work/server/minecraft/0030-ModernFix-compact_bit_storage.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0030-ModernFix-compact_bit_storage.patch rename to patches/work/server/minecraft/0030-ModernFix-compact_bit_storage.patch diff --git a/divinemc-server/minecraft-patches/features/0031-lithium-fast_util.patch b/patches/work/server/minecraft/0031-lithium-fast_util.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0031-lithium-fast_util.patch rename to patches/work/server/minecraft/0031-lithium-fast_util.patch diff --git a/divinemc-server/minecraft-patches/features/0032-Command-block-parse-results-caching.patch b/patches/work/server/minecraft/0032-Command-block-parse-results-caching.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0032-Command-block-parse-results-caching.patch rename to patches/work/server/minecraft/0032-Command-block-parse-results-caching.patch diff --git a/divinemc-server/minecraft-patches/features/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch b/patches/work/server/minecraft/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch rename to patches/work/server/minecraft/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch diff --git a/divinemc-server/minecraft-patches/features/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch b/patches/work/server/minecraft/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch rename to patches/work/server/minecraft/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch diff --git a/divinemc-server/minecraft-patches/features/0035-Configurable-movement-speed-for-entities.patch b/patches/work/server/minecraft/0035-Configurable-movement-speed-for-entities.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0035-Configurable-movement-speed-for-entities.patch rename to patches/work/server/minecraft/0035-Configurable-movement-speed-for-entities.patch diff --git a/divinemc-server/minecraft-patches/features/0037-Dynamic-Activation-of-Brain.patch b/patches/work/server/minecraft/0037-Dynamic-Activation-of-Brain.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0037-Dynamic-Activation-of-Brain.patch rename to patches/work/server/minecraft/0037-Dynamic-Activation-of-Brain.patch diff --git a/divinemc-server/minecraft-patches/features/0038-Linear-region-file-format.patch b/patches/work/server/minecraft/0038-Linear-region-file-format.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0038-Linear-region-file-format.patch rename to patches/work/server/minecraft/0038-Linear-region-file-format.patch diff --git a/divinemc-server/minecraft-patches/features/0040-Player-ProfileResult-caching.patch b/patches/work/server/minecraft/0040-Player-ProfileResult-caching.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0040-Player-ProfileResult-caching.patch rename to patches/work/server/minecraft/0040-Player-ProfileResult-caching.patch diff --git a/divinemc-server/minecraft-patches/features/0041-Async-mob-spawning.patch b/patches/work/server/minecraft/0041-Async-mob-spawning.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0041-Async-mob-spawning.patch rename to patches/work/server/minecraft/0041-Async-mob-spawning.patch diff --git a/divinemc-server/minecraft-patches/features/0043-Carpet-Fixes-Sheep-Optimization.patch b/patches/work/server/minecraft/0043-Carpet-Fixes-Sheep-Optimization.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0043-Carpet-Fixes-Sheep-Optimization.patch rename to patches/work/server/minecraft/0043-Carpet-Fixes-Sheep-Optimization.patch diff --git a/divinemc-server/minecraft-patches/features/0044-Density-Function-Compiler.patch b/patches/work/server/minecraft/0044-Density-Function-Compiler.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0044-Density-Function-Compiler.patch rename to patches/work/server/minecraft/0044-Density-Function-Compiler.patch diff --git a/divinemc-server/minecraft-patches/features/0045-Parallel-world-ticking.patch b/patches/work/server/minecraft/0045-Parallel-world-ticking.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0045-Parallel-world-ticking.patch rename to patches/work/server/minecraft/0045-Parallel-world-ticking.patch diff --git a/divinemc-server/minecraft-patches/features/0046-MSPT-Tracking-for-each-world.patch b/patches/work/server/minecraft/0046-MSPT-Tracking-for-each-world.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0046-MSPT-Tracking-for-each-world.patch rename to patches/work/server/minecraft/0046-MSPT-Tracking-for-each-world.patch diff --git a/divinemc-server/minecraft-patches/features/0047-Optimize-Raids.patch b/patches/work/server/minecraft/0047-Optimize-Raids.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0047-Optimize-Raids.patch rename to patches/work/server/minecraft/0047-Optimize-Raids.patch diff --git a/divinemc-server/minecraft-patches/features/0048-Catch-update-suppressors.patch b/patches/work/server/minecraft/0048-Catch-update-suppressors.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0048-Catch-update-suppressors.patch rename to patches/work/server/minecraft/0048-Catch-update-suppressors.patch diff --git a/divinemc-server/minecraft-patches/features/0050-Optimize-suffocation.patch b/patches/work/server/minecraft/0050-Optimize-suffocation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0050-Optimize-suffocation.patch rename to patches/work/server/minecraft/0050-Optimize-suffocation.patch diff --git a/divinemc-server/minecraft-patches/features/0051-Reduce-chunk-loading-lookups.patch b/patches/work/server/minecraft/0051-Reduce-chunk-loading-lookups.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0051-Reduce-chunk-loading-lookups.patch rename to patches/work/server/minecraft/0051-Reduce-chunk-loading-lookups.patch diff --git a/divinemc-server/minecraft-patches/features/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch b/patches/work/server/minecraft/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch rename to patches/work/server/minecraft/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch diff --git a/divinemc-server/minecraft-patches/features/0053-Regionized-Chunk-Ticking.patch b/patches/work/server/minecraft/0053-Regionized-Chunk-Ticking.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0053-Regionized-Chunk-Ticking.patch rename to patches/work/server/minecraft/0053-Regionized-Chunk-Ticking.patch diff --git a/divinemc-server/minecraft-patches/features/0055-Clump-experience-orbs.patch b/patches/work/server/minecraft/0055-Clump-experience-orbs.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0055-Clump-experience-orbs.patch rename to patches/work/server/minecraft/0055-Clump-experience-orbs.patch diff --git a/divinemc-server/paper-patches/features/0005-Implement-Secure-Seed.patch b/patches/work/server/paper/0005-Implement-Secure-Seed.patch similarity index 100% rename from divinemc-server/paper-patches/features/0005-Implement-Secure-Seed.patch rename to patches/work/server/paper/0005-Implement-Secure-Seed.patch diff --git a/divinemc-server/paper-patches/features/0006-Chunk-System-Optimizations.patch b/patches/work/server/paper/0006-Chunk-System-Optimizations.patch similarity index 100% rename from divinemc-server/paper-patches/features/0006-Chunk-System-Optimizations.patch rename to patches/work/server/paper/0006-Chunk-System-Optimizations.patch diff --git a/divinemc-server/paper-patches/features/0007-Optimize-canSee-checks.patch b/patches/work/server/paper/0007-Optimize-canSee-checks.patch similarity index 100% rename from divinemc-server/paper-patches/features/0007-Optimize-canSee-checks.patch rename to patches/work/server/paper/0007-Optimize-canSee-checks.patch diff --git a/divinemc-server/paper-patches/features/0008-Configurable-thread-pool-priority.patch b/patches/work/server/paper/0008-Configurable-thread-pool-priority.patch similarity index 100% rename from divinemc-server/paper-patches/features/0008-Configurable-thread-pool-priority.patch rename to patches/work/server/paper/0008-Configurable-thread-pool-priority.patch diff --git a/divinemc-server/paper-patches/features/0009-Virtual-Threads.patch b/patches/work/server/paper/0009-Virtual-Threads.patch similarity index 100% rename from divinemc-server/paper-patches/features/0009-Virtual-Threads.patch rename to patches/work/server/paper/0009-Virtual-Threads.patch diff --git a/divinemc-server/paper-patches/features/0010-Multithreaded-Tracker.patch b/patches/work/server/paper/0010-Multithreaded-Tracker.patch similarity index 100% rename from divinemc-server/paper-patches/features/0010-Multithreaded-Tracker.patch rename to patches/work/server/paper/0010-Multithreaded-Tracker.patch diff --git a/divinemc-server/paper-patches/features/0014-Parallel-world-ticking.patch b/patches/work/server/paper/0014-Parallel-world-ticking.patch similarity index 100% rename from divinemc-server/paper-patches/features/0014-Parallel-world-ticking.patch rename to patches/work/server/paper/0014-Parallel-world-ticking.patch diff --git a/divinemc-server/purpur-patches/features/0003-MSPT-Tracking-for-each-world.patch b/patches/work/server/purpur/0003-MSPT-Tracking-for-each-world.patch similarity index 100% rename from divinemc-server/purpur-patches/features/0003-MSPT-Tracking-for-each-world.patch rename to patches/work/server/purpur/0003-MSPT-Tracking-for-each-world.patch From 9cae2dc1f2b184c9d39213bc69cd0054d2f28275 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 6 Jul 2025 01:30:45 +0300 Subject: [PATCH 02/67] update MapPalette patch --- ...0010-Vectorized-map-color-conversion.patch | 45 +++++++++++++++++++ patches/work/api/MapPalette.java.patch | 29 ------------ 2 files changed, 45 insertions(+), 29 deletions(-) create mode 100644 divinemc-api/paper-patches/features/0010-Vectorized-map-color-conversion.patch delete mode 100644 patches/work/api/MapPalette.java.patch diff --git a/divinemc-api/paper-patches/features/0010-Vectorized-map-color-conversion.patch b/divinemc-api/paper-patches/features/0010-Vectorized-map-color-conversion.patch new file mode 100644 index 0000000..abc0dcd --- /dev/null +++ b/divinemc-api/paper-patches/features/0010-Vectorized-map-color-conversion.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 01:23:49 +0300 +Subject: [PATCH] Vectorized map color conversion + +Original patch by: Kevin Raneri +As part of: Pufferfish (https://github.com/pufferfish-gg/Pufferfish) +Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) + +Pufferfish description: + +This patch does not add any API that should be used by plugins. Any +classes and methods added by this patch should NOT be used in plugins. + +diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java +index 2b9e4aa8cf35e7106e510e547954ee7e1bcf3d81..482a08c38748d82313e02f6f699006aa83a071bc 100644 +--- a/src/main/java/org/bukkit/map/MapPalette.java ++++ b/src/main/java/org/bukkit/map/MapPalette.java +@@ -35,7 +35,7 @@ public final class MapPalette { + } + + @NotNull +- static final Color[] colors = { ++ public static final Color[] colors = { // DivineMC - Vectorized map color conversion - package -> public + // Start generate - MapPalette#colors + // @GeneratedFrom 1.21.7 + new Color(0x00000000, true), +@@ -395,9 +395,15 @@ public final class MapPalette { + temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth()); + + byte[] result = new byte[temp.getWidth() * temp.getHeight()]; +- for (int i = 0; i < pixels.length; i++) { +- result[i] = matchColor(new Color(pixels[i], true)); ++ // DivineMC start - Vectorized map color conversion ++ if ((mapColorCache != null && mapColorCache.isCached()) || !gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled) { ++ for (int i = 0; i < pixels.length; i++) { ++ result[i] = matchColor(new Color(pixels[i], true)); ++ } ++ } else { ++ gg.pufferfish.pufferfish.simd.VectorMapPalette.matchColorVectorized(pixels, result); + } ++ // DivineMC end - Vectorized map color conversion + return result; + } + diff --git a/patches/work/api/MapPalette.java.patch b/patches/work/api/MapPalette.java.patch deleted file mode 100644 index 4564e34..0000000 --- a/patches/work/api/MapPalette.java.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- a/src/main/java/org/bukkit/map/MapPalette.java -+++ b/src/main/java/org/bukkit/map/MapPalette.java -@@ -35,7 +_,7 @@ - } - - @NotNull -- static final Color[] colors = { -+ public static final Color[] colors = { // DivineMC - Pufferfish SIMD - make public - // Start generate - MapPalette#colors - // @GeneratedFrom 1.21.7 - new Color(0x00000000, true), -@@ -395,9 +_,15 @@ - temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth()); - - byte[] result = new byte[temp.getWidth() * temp.getHeight()]; -- for (int i = 0; i < pixels.length; i++) { -- result[i] = matchColor(new Color(pixels[i], true)); -+ // DivineMC start - Pufferfish SIMD -+ if (gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled) { -+ gg.pufferfish.pufferfish.simd.VectorMapPalette.matchColorVectorized(pixels, result); -+ } else { -+ for (int i = 0; i < pixels.length; i++) { -+ result[i] = matchColor(new Color(pixels[i], true)); -+ } - } -+ // DivineMC end - Pufferfish SIMD - return result; - } - From e0646a0333806598802c5d109ad5d461c9e727c6 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 6 Jul 2025 03:10:05 +0300 Subject: [PATCH 03/67] switch from sources, split some patches --- .../features/0001-Rebrand.patch | 4 +- .../features/0002-Configuration.patch | 6 +- ...03-Completely-remove-Mojang-profiler.patch | 62 ++--- .../features/0008-Smooth-teleport-API.patch | 8 +- ...chment-Make-FixLight-use-action-bar.patch} | 22 +- .../0010-Pufferfish-SIMD-support.patch} | 14 +- .../features/0011-lithium-fast_util.patch | 2 +- ...ast_hand_swing-entity.fast_elytra_ch.patch | 32 +++ ...013-lithium-cached_iterate_outwards.patch} | 13 +- .../0014-C2ME-Reduce-Allocations.patch | 24 ++ .../0015-C2ME-Optimize-world-gen-math.patch | 68 +++++ .../features/0016-Re-Fix-MC-117075.patch | 6 +- .../features/0017-Fix-MC-119417.patch | 19 ++ .../features/0018-Fix-MC-7569.patch | 20 ++ .../features/0019-Fix-MC-110386.patch | 19 ++ .../0020-Fix-MC-200418.patch} | 11 +- .../features/0021-Fix-MC-31819.patch | 23 ++ .../features/0022-Fix-MC-172801.patch | 26 ++ .../0023-Fix-MC-258859.patch} | 11 +- ...aper-Clear-dirty-stats-after-copying.patch | 38 +++ .../features/0025-Async-locate-command.patch | 0 ...-Carpet-Fixes-RecipeManager-Optimize.patch | 0 ...7-lithium-faster-chunk-serialization.patch | 216 +++++++++++++++ ...um-skip-useless-secondary-poi-sensor.patch | 32 +++ ...skip-entity-move-if-movement-is-zero.patch | 39 +++ ...030-VMP-store-mob-counts-in-an-array.patch | 33 +++ .../0031-C2ME-optimize-noise-generation.patch | 245 ++++++++++++++++++ ...2-Skip-cloning-advancement-criteria.patch} | 10 +- .../features/0033-Fix-sprint-glitch.patch | 19 ++ .../0034-Optimize-block-state-lookup.patch} | 22 +- ...n-t-respond-ping-before-start-fully.patch} | 11 +- ...rs-that-were-dead-on-server-restart.patch} | 10 +- .../features/0037-Configurable-MC-67.patch | 4 +- .../features/0038-Configurable-MC-59471.patch | 0 .../0039-Use-Java-s-Math-functions.patch | 65 +++++ .../0040-Disable-leaf-decay.patch} | 14 +- ...t-Fixes-Fix-Slime-Block-Bounce-Logic.patch | 28 ++ .../features/0042-Optimize-entity-brain.patch | 70 ++--- .../server/level/ServerPlayer.java.patch | 10 - .../ServerGamePacketListenerImpl.java.patch | 19 -- .../server/players/PlayerList.java.patch | 10 - .../server/rcon/RconConsoleSource.java.patch | 11 - .../stats/ServerStatsCounter.java.patch | 28 -- .../world/entity/LivingEntity.java.patch | 42 --- .../goal/target/HurtByTargetGoal.java.patch | 10 - .../ai/sensing/SecondaryPoiSensor.java.patch | 15 -- .../world/entity/player/Player.java.patch | 14 - .../world/level/BaseCommandBlock.java.patch | 20 -- .../world/level/block/Blocks.java.patch | 10 - .../world/level/block/SlimeBlock.java.patch | 10 - .../world/chunk/LithiumHashPalette.java | 207 +++++++++++++++ ...ch => 0009-Regionized-Chunk-Ticking.patch} | 2 + .../SimpleCriterionTrigger.java.patch | 0 53 files changed, 1349 insertions(+), 305 deletions(-) rename divinemc-server/minecraft-patches/{sources/io/papermc/paper/command/subcommands/FixLightCommand.java.patch => features/0009-Parchment-Make-FixLight-use-action-bar.patch} (67%) rename divinemc-server/minecraft-patches/{sources/net/minecraft/server/dedicated/DedicatedServer.java.patch => features/0010-Pufferfish-SIMD-support.patch} (74%) rename patches/work/server/minecraft/0031-lithium-fast_util.patch => divinemc-server/minecraft-patches/features/0011-lithium-fast_util.patch (96%) create mode 100644 divinemc-server/minecraft-patches/features/0012-lithium-entity.fast_hand_swing-entity.fast_elytra_ch.patch rename divinemc-server/minecraft-patches/{sources/net/minecraft/core/BlockPos.java.patch => features/0013-lithium-cached_iterate_outwards.patch} (66%) create mode 100644 divinemc-server/minecraft-patches/features/0014-C2ME-Reduce-Allocations.patch create mode 100644 divinemc-server/minecraft-patches/features/0015-C2ME-Optimize-world-gen-math.patch rename patches/work/server/minecraft/0023-Re-Fix-MC-117075.patch => divinemc-server/minecraft-patches/features/0016-Re-Fix-MC-117075.patch (92%) create mode 100644 divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch create mode 100644 divinemc-server/minecraft-patches/features/0018-Fix-MC-7569.patch create mode 100644 divinemc-server/minecraft-patches/features/0019-Fix-MC-110386.patch rename divinemc-server/minecraft-patches/{sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch => features/0020-Fix-MC-200418.patch} (56%) create mode 100644 divinemc-server/minecraft-patches/features/0021-Fix-MC-31819.patch create mode 100644 divinemc-server/minecraft-patches/features/0022-Fix-MC-172801.patch rename divinemc-server/minecraft-patches/{sources/net/minecraft/world/level/levelgen/SurfaceRules.java.patch => features/0023-Fix-MC-258859.patch} (71%) create mode 100644 divinemc-server/minecraft-patches/features/0024-SparklyPaper-Clear-dirty-stats-after-copying.patch rename patches/work/server/minecraft/0006-Async-locate-command.patch => divinemc-server/minecraft-patches/features/0025-Async-locate-command.patch (100%) rename patches/work/server/minecraft/0014-Carpet-Fixes-RecipeManager-Optimize.patch => divinemc-server/minecraft-patches/features/0026-Carpet-Fixes-RecipeManager-Optimize.patch (100%) create mode 100644 divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch create mode 100644 divinemc-server/minecraft-patches/features/0028-lithium-skip-useless-secondary-poi-sensor.patch create mode 100644 divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch create mode 100644 divinemc-server/minecraft-patches/features/0030-VMP-store-mob-counts-in-an-array.patch create mode 100644 divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch rename divinemc-server/minecraft-patches/{sources/net/minecraft/advancements/Advancement.java.patch => features/0032-Skip-cloning-advancement-criteria.patch} (56%) create mode 100644 divinemc-server/minecraft-patches/features/0033-Fix-sprint-glitch.patch rename divinemc-server/minecraft-patches/{sources/net/minecraft/world/level/chunk/LevelChunk.java.patch => features/0034-Optimize-block-state-lookup.patch} (56%) rename divinemc-server/minecraft-patches/{sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch => features/0035-Don-t-respond-ping-before-start-fully.patch} (66%) rename divinemc-server/minecraft-patches/{sources/net/minecraft/server/MinecraftServer.java.patch => features/0036-Respawn-players-that-were-dead-on-server-restart.patch} (66%) rename patches/work/server/minecraft/0028-Configurable-MC-67.patch => divinemc-server/minecraft-patches/features/0037-Configurable-MC-67.patch (85%) rename patches/work/server/minecraft/0029-Configurable-MC-59471.patch => divinemc-server/minecraft-patches/features/0038-Configurable-MC-59471.patch (100%) create mode 100644 divinemc-server/minecraft-patches/features/0039-Use-Java-s-Math-functions.patch rename divinemc-server/minecraft-patches/{sources/net/minecraft/world/level/block/LeavesBlock.java.patch => features/0040-Disable-leaf-decay.patch} (68%) create mode 100644 divinemc-server/minecraft-patches/features/0041-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch rename patches/work/server/minecraft/0011-Optimize-entity-stupid-brain.patch => divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch (90%) delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/SlimeBlock.java.patch create mode 100644 divinemc-server/src/main/java/net/caffeinemc/mods/lithium/common/world/chunk/LithiumHashPalette.java rename patches/work/server/minecraft/{0053-Regionized-Chunk-Ticking.patch => 0009-Regionized-Chunk-Ticking.patch} (99%) rename {divinemc-server/minecraft-patches => patches/work/server}/sources/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java.patch (100%) diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index 2920eff..2730a0a 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -18,10 +18,10 @@ index 394443d00e661715439be1e56dddc129947699a4..480ad57a6b7b74e6b83e9c6ceb69ea1f public CrashReport(String title, Throwable exception) { io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index ac0ed2e7261a0d698fafd5b314108ff38a169073..8f32168ff0371a9168bbf9b08b2154200f8131a0 100644 +index 306230339574bc35a309877033fa6012e4596f08..1362f3d2ef75d8b18ac2142194ff5b3f2104ac1e 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1183,6 +1183,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop, AutoCl diff --git a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch index 9807816..67b076a 100644 --- a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch +++ b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch @@ -213,7 +213,7 @@ index 18071dcc69cc28471dddb7de94e803ec1e5fc2e4..aa25f5ebaf7d1b22825b962b02dcae02 } } diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 768e82c5cfd05fae2dd84fc6a37f5984c6ec4865..abfecaf4467092f7baa02e0f5bbfd23d087f2aa3 100644 +index 1362f3d2ef75d8b18ac2142194ff5b3f2104ac1e..ace14db7bfd154b8a9b27af4a6c57630a3868ac0 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -114,19 +114,8 @@ import net.minecraft.util.TimeUtil; @@ -250,7 +250,7 @@ index 768e82c5cfd05fae2dd84fc6a37f5984c6ec4865..abfecaf4467092f7baa02e0f5bbfd23d private ServerConnectionListener connection; public final ChunkProgressListenerFactory progressListenerFactory; @Nullable -@@ -1000,9 +982,6 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && this.tickCount % autosavePeriod == 0; try { this.isSaving = true; -@@ -1599,10 +1563,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop serverPlayer1.connection.suspendFlushing()); this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit // Paper start - optimise Folia entity scheduler -@@ -1715,9 +1671,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Purpur - Ridables @@ -429,7 +429,7 @@ index 768e82c5cfd05fae2dd84fc6a37f5984c6ec4865..abfecaf4467092f7baa02e0f5bbfd23d try { serverLevel.tick(hasTimeLeft); } catch (Throwable var7) { -@@ -1772,34 +1721,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop getAvailableGoals() { diff --git a/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index 3b29cc4e11efe6f27023f52cfde16fd118c310ad..c8e4ccb96a0f162c780066cf4f61b970b49b7703 100644 +index dd1a95111d965bcd7f53be9d4224dd213e4e0705..24dd92449f70144c79f25bf24942ebd666655ed2 100644 --- a/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/net/minecraft/world/entity/ai/navigation/PathNavigation.java @@ -10,8 +10,6 @@ import net.minecraft.core.Vec3i; @@ -5039,7 +5039,7 @@ index 1d3b16d3f60a394fe69e10ef1bb6052bb937070a..d0c4d63320fb5f58c43b38ebc333e9a7 if (this.fire) { diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index 8084b524dc0c10cb801b6d8beccbde89de9c55d2..53c77efe2f86c5dfb5f02fa0b1886e8cda2e3862 100644 +index 7425e8d6b352718f80e1e741329e28c5da80fcce..d11373d6a88f7b3baaf0e04d4f6e0d3837e2ba3b 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -24,8 +24,6 @@ import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; @@ -5051,7 +5051,7 @@ index 8084b524dc0c10cb801b6d8beccbde89de9c55d2..53c77efe2f86c5dfb5f02fa0b1886e8c import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; -@@ -392,12 +390,8 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -385,12 +383,8 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p } if (LightEngine.hasDifferentLightProperties(blockState, state)) { @@ -5064,7 +5064,7 @@ index 8084b524dc0c10cb801b6d8beccbde89de9c55d2..53c77efe2f86c5dfb5f02fa0b1886e8c } boolean flag = !blockState.is(block); -@@ -929,8 +923,6 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -922,8 +916,6 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p BlockPos blockPos = this.blockEntity.getBlockPos(); if (LevelChunk.this.isTicking(blockPos)) { try { @@ -5073,7 +5073,7 @@ index 8084b524dc0c10cb801b6d8beccbde89de9c55d2..53c77efe2f86c5dfb5f02fa0b1886e8c BlockState blockState = LevelChunk.this.getBlockState(blockPos); if (this.blockEntity.getType().isValid(blockState)) { this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity); -@@ -944,8 +936,6 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -937,8 +929,6 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p } // Paper end - Remove the Block Entity if it's invalid } diff --git a/divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch b/divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch index bb87d52..aa010ff 100644 --- a/divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch +++ b/divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Smooth teleport API diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index a1b4720ef128ba5cbe1466a7a584d4fe501a71f8..b75d2d2746c3e7b12f65b0bcb559cd7e0ce7ebf8 100644 +index 890c295d2318767081580e9aabddedd2535388cc..8a8d72fa46f4eff31e06e8b1756d286f7f1b07a6 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -430,6 +430,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc @@ -17,10 +17,10 @@ index a1b4720ef128ba5cbe1466a7a584d4fe501a71f8..b75d2d2746c3e7b12f65b0bcb559cd7e // Paper start - rewrite chunk system private ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader; diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index c70b5ce2dc8cbcdea8715339a63e038f94849bfb..9362bfdf8f5495d237b1e74be4dd925db2452dc0 100644 +index 0a2d1a89722094f7e51c33a364b6999143add0a1..fb1b9f75cffeb15875e6690a0e030f8a4fd8b276 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -748,11 +748,11 @@ public abstract class PlayerList { +@@ -749,11 +749,11 @@ public abstract class PlayerList { byte b = (byte)(keepInventory ? 1 : 0); ServerLevel serverLevel = serverPlayer.level(); LevelData levelData = serverLevel.getLevelData(); @@ -34,7 +34,7 @@ index c70b5ce2dc8cbcdea8715339a63e038f94849bfb..9362bfdf8f5495d237b1e74be4dd925d serverPlayer.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getSharedSpawnPos(), level.getSharedSpawnAngle())); serverPlayer.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); serverPlayer.connection -@@ -839,6 +839,12 @@ public abstract class PlayerList { +@@ -840,6 +840,12 @@ public abstract class PlayerList { return serverPlayer; } diff --git a/divinemc-server/minecraft-patches/sources/io/papermc/paper/command/subcommands/FixLightCommand.java.patch b/divinemc-server/minecraft-patches/features/0009-Parchment-Make-FixLight-use-action-bar.patch similarity index 67% rename from divinemc-server/minecraft-patches/sources/io/papermc/paper/command/subcommands/FixLightCommand.java.patch rename to divinemc-server/minecraft-patches/features/0009-Parchment-Make-FixLight-use-action-bar.patch index 502b179..87d5503 100644 --- a/divinemc-server/minecraft-patches/sources/io/papermc/paper/command/subcommands/FixLightCommand.java.patch +++ b/divinemc-server/minecraft-patches/features/0009-Parchment-Make-FixLight-use-action-bar.patch @@ -1,21 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 01:49:27 +0300 +Subject: [PATCH] Parchment: Make FixLight use action bar + +Original license: GPLv3 +Original project: https://github.com/ProjectEdenGG/Parchment + +diff --git a/io/papermc/paper/command/subcommands/FixLightCommand.java b/io/papermc/paper/command/subcommands/FixLightCommand.java +index 85950a1aa732ab8c01ad28bec9e0de140e1a172e..fbc38577599dd0e606e2d225ce98943ab49e74f7 100644 --- a/io/papermc/paper/command/subcommands/FixLightCommand.java +++ b/io/papermc/paper/command/subcommands/FixLightCommand.java -@@ -95,17 +_,22 @@ +@@ -95,17 +95,23 @@ public final class FixLightCommand implements PaperSubcommand { ((StarLightLightingProvider)lightengine).starlight$serverRelightChunks(chunks, (final ChunkPos chunkPos) -> { ++relitChunks[0]; - sender.getBukkitEntity().sendMessage(text().color(DARK_AQUA).append( - text("Relit chunk ", BLUE), text(chunkPos.toString()), - text(", progress: ", BLUE), text(ONE_DECIMAL_PLACES.get().format(100.0 * (double) (relitChunks[0]) / (double) pending[0]) + "%") -- )); -+ // DivineMC start - Make FixLight use action bar ++ // DivineMC start - Parchment: Make FixLight use action bar + sender.getBukkitEntity().sendActionBar(text().color(DARK_AQUA).append( + text("Relighting Chunks: ", DARK_AQUA), text(chunkPos.toString()), + text(" " + relitChunks[0], net.kyori.adventure.text.format.NamedTextColor.YELLOW), + text("/", DARK_AQUA), + text(pending[0] + " ", net.kyori.adventure.text.format.NamedTextColor.YELLOW), + text("(" + (int) (Math.round(100.0 * (double) (relitChunks[0]) / (double) pending[0])) + "%)", net.kyori.adventure.text.format.NamedTextColor.YELLOW) -+ )); // DivineMC end - Make FixLight use action bar + )); ++ // DivineMC end - Parchment: Make FixLight use action bar }, (final int totalRelit) -> { final long end = System.nanoTime(); @@ -23,10 +33,10 @@ - text("Relit ", BLUE), text(totalRelit), - text(" chunks. Took ", BLUE), text(ONE_DECIMAL_PLACES.get().format(1.0e-6 * (end - start)) + "ms") - )); -+ // DivineMC start - Make FixLight use action bar ++ // DivineMC start - Parchment: Make FixLight use action bar + text("Relit ", DARK_AQUA), text(totalRelit, net.kyori.adventure.text.format.NamedTextColor.YELLOW), + text(" chunks. Took ", DARK_AQUA), text(ONE_DECIMAL_PLACES.get().format(1.0e-6 * (end - start)) + "ms", net.kyori.adventure.text.format.NamedTextColor.YELLOW) -+ )); // DivineMC end - Make FixLight use action bar ++ )); // DivineMC end - Parchment: Make FixLight use action bar if (done != null) { done.run(); } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch similarity index 74% rename from divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch rename to divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch index 93ab0b0..a849a7e 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch +++ b/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch @@ -1,7 +1,17 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:55:43 +0300 +Subject: [PATCH] Pufferfish: SIMD support + +Original license: GPL v3 +Original project: https://github.com/pufferfish-gg/Pufferfish + +diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java +index 7aefb6a81d5f7f5431f3d67a096a93b036bbbd1d..7ac82a49e3c64d1a41a2870c5cf9900812329a57 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -195,6 +_,26 @@ - // Purpur end - Purpur config files +@@ -204,6 +204,26 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + // DivineMC end - Configuration com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now + // DivineMC start - Pufferfish SIMD diff --git a/patches/work/server/minecraft/0031-lithium-fast_util.patch b/divinemc-server/minecraft-patches/features/0011-lithium-fast_util.patch similarity index 96% rename from patches/work/server/minecraft/0031-lithium-fast_util.patch rename to divinemc-server/minecraft-patches/features/0011-lithium-fast_util.patch index 3eb5426..fceb56b 100644 --- a/patches/work/server/minecraft/0031-lithium-fast_util.patch +++ b/divinemc-server/minecraft-patches/features/0011-lithium-fast_util.patch @@ -27,7 +27,7 @@ index 63fd7b45750430b565d599337d3112cbaa7e7550..4275a2e1e29c15cdda75c29c46825563 public static Direction getApproximateNearest(double x, double y, double z) { diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java -index f60c1ab58a2e9adfb01e9bd430b92cd1902e5dbe..37ad60f2be694c22bfef402c38c8206348bf36a5 100644 +index e53398996bbb278c6e06024d8ca945b364a44c10..13678a9c0f9056b4925e4de927ec3cbc01cb114e 100644 --- a/net/minecraft/world/phys/AABB.java +++ b/net/minecraft/world/phys/AABB.java @@ -19,6 +19,15 @@ public class AABB { diff --git a/divinemc-server/minecraft-patches/features/0012-lithium-entity.fast_hand_swing-entity.fast_elytra_ch.patch b/divinemc-server/minecraft-patches/features/0012-lithium-entity.fast_hand_swing-entity.fast_elytra_ch.patch new file mode 100644 index 0000000..48c6d33 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0012-lithium-entity.fast_hand_swing-entity.fast_elytra_ch.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 01:51:12 +0300 +Subject: [PATCH] lithium: entity.fast_hand_swing + entity.fast_elytra_check + +This patch is based on the following mixins: +* "net/caffeinemc/mods/lithium/mixin/entity/fast_elytra_check/LivingEntityMixin.java" +* "net/caffeinemc/mods/lithium/mixin/entity/fast_hand_swing/LivingEntityMixin.java" +By: 2No2Name <2No2Name@web.de> +As part of: Lithium (https://github.com/CaffeineMC/lithium-fabric) +Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html) + +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index a086c44afc5b3cb04641b4b9cfe28690f6ca2d7e..ab2bfe5589547a5e1b7f26ff100609c4464b61c7 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -2757,6 +2757,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin + } + + protected void updateSwingTime() { ++ if (!this.swinging && this.swingTime == 0) return; // DivineMC - lithium: entity.fast_hand_swing + int currentSwingDuration = this.getCurrentSwingDuration(); + if (this.swinging) { + this.swingTime++; +@@ -3703,6 +3704,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin + protected void updateFallFlying() { + this.checkFallDistanceAccumulation(); + if (!this.level().isClientSide) { ++ if (!this.isFallFlying() && this.fallFlyTicks == 0) return; // DivineMC - lithium: entity.fast_elytra_check + if (!this.canGlide()) { + if (this.getSharedFlag(7) != false && !CraftEventFactory.callToggleGlideEvent(this, false).isCancelled()) // CraftBukkit + this.setSharedFlag(7, false); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch b/divinemc-server/minecraft-patches/features/0013-lithium-cached_iterate_outwards.patch similarity index 66% rename from divinemc-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch rename to divinemc-server/minecraft-patches/features/0013-lithium-cached_iterate_outwards.patch index fb2c309..c531d35 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch +++ b/divinemc-server/minecraft-patches/features/0013-lithium-cached_iterate_outwards.patch @@ -1,6 +1,17 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 01:52:18 +0300 +Subject: [PATCH] lithium: cached_iterate_outwards + +By: 2No2Name <2No2Name@web.de> +As part of: Lithium (https://github.com/CaffeineMC/lithium-fabric) +Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html) + +diff --git a/net/minecraft/core/BlockPos.java b/net/minecraft/core/BlockPos.java +index 6518d3fff6daf331b24a7bf5b39fa1920b73711d..0dc73d76c2d86e05bedb3eb4f51d638c17390277 100644 --- a/net/minecraft/core/BlockPos.java +++ b/net/minecraft/core/BlockPos.java -@@ -347,7 +_,18 @@ +@@ -347,7 +347,18 @@ public class BlockPos extends Vec3i { }; } diff --git a/divinemc-server/minecraft-patches/features/0014-C2ME-Reduce-Allocations.patch b/divinemc-server/minecraft-patches/features/0014-C2ME-Reduce-Allocations.patch new file mode 100644 index 0000000..c1550b7 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0014-C2ME-Reduce-Allocations.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 01:53:38 +0300 +Subject: [PATCH] C2ME: Reduce Allocations + +This patch is based on the following mixin: +"com/ishland/c2me/opts/allocs/mixin/object_pooling_caching/MixinOreFeature.java" +By: ishland +As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric) +Licensed under: MIT (https://opensource.org/licenses/MIT) + +diff --git a/net/minecraft/world/level/levelgen/feature/OreFeature.java b/net/minecraft/world/level/levelgen/feature/OreFeature.java +index c7b46efd4f08067e2c9c5c8b0e8b71a94a79823d..45d43707909685d2494f054d4b9e6451af6c2f72 100644 +--- a/net/minecraft/world/level/levelgen/feature/OreFeature.java ++++ b/net/minecraft/world/level/levelgen/feature/OreFeature.java +@@ -69,7 +69,7 @@ public class OreFeature extends Feature { + int height + ) { + int i = 0; +- BitSet bitSet = new BitSet(width * height * width); ++ BitSet bitSet = org.bxteam.divinemc.util.cache.CachedOrNewBitsGetter.getCachedOrNewBitSet(width * height * width); // DivineMC - C2ME: Reduce Allocations + BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + int i1 = config.size; + double[] doubles = new double[i1 * 4]; diff --git a/divinemc-server/minecraft-patches/features/0015-C2ME-Optimize-world-gen-math.patch b/divinemc-server/minecraft-patches/features/0015-C2ME-Optimize-world-gen-math.patch new file mode 100644 index 0000000..4926869 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0015-C2ME-Optimize-world-gen-math.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 01:55:37 +0300 +Subject: [PATCH] C2ME: Optimize world gen math + +This patch is based on following mixins: +* "com/ishland/c2me/opts/math/mixin/MixinChunkPos.java" +* "com/ishland/c2me/opts/worldgen/vanilla/mixin/structure_weight_sampler/MixinStructureWeightSampler.java" +By: ishland +As part of: C2ME-fabric (https://github.com/RelativityMC/C2ME-fabric) +Licensed under: MIT + +diff --git a/net/minecraft/world/level/ChunkPos.java b/net/minecraft/world/level/ChunkPos.java +index 55ce935a2fab7e32904d9ff599867269035d703f..7770e2aacaa7772a1710172f143452f076c6eef2 100644 +--- a/net/minecraft/world/level/ChunkPos.java ++++ b/net/minecraft/world/level/ChunkPos.java +@@ -110,7 +110,12 @@ public class ChunkPos { + + @Override + public boolean equals(Object other) { +- return this == other || other instanceof ChunkPos chunkPos && this.x == chunkPos.x && this.z == chunkPos.z; ++ // DivineMC start - C2ME: Optimize world gen math ++ if (other == this) return true; ++ if (other == null || other.getClass() != this.getClass()) return false; ++ ChunkPos thatPos = (ChunkPos) other; ++ return this.x == thatPos.x && this.z == thatPos.z; ++ // DivineMC end - C2ME: Optimize world gen math + } + + public int getMiddleBlockX() { +diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java +index 74d8202b5c9bb2a3ee832be70f95c0b5cbecb460..86c15d2d90e63d21cb83622a7b29e11151a4f64a 100644 +--- a/net/minecraft/world/level/levelgen/Beardifier.java ++++ b/net/minecraft/world/level/levelgen/Beardifier.java +@@ -131,8 +131,14 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { + } + + private static double getBuryContribution(double x, double y, double z) { +- double len = Mth.length(x, y, z); +- return Mth.clampedMap(len, 0.0, 6.0, 1.0, 0.0); ++ // DivineMC start - C2ME: Optimize world gen math ++ double len = Math.sqrt(x * x + y * y + z * z); ++ if (len > 6.0) { ++ return 0.0; ++ } else { ++ return 1.0 - len / 6.0; ++ } ++ // DivineMC end - C2ME: Optimize world gen math + } + + private static double getBeardContribution(int x, int y, int z, int height) { +diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java +index 65728ef17e63d71833677fdcbd5bb90794b4822b..5716e80ba386f113d02f5d6a4848914d4bf9600f 100644 +--- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java ++++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java +@@ -68,8 +68,10 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { + Aquifer.FluidStatus fluidStatus = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState()); + int seaLevel = settings.seaLevel(); + Aquifer.FluidStatus fluidStatus1 = new Aquifer.FluidStatus(seaLevel, settings.defaultFluid()); +- Aquifer.FluidStatus fluidStatus2 = new Aquifer.FluidStatus(DimensionType.MIN_Y * 2, Blocks.AIR.defaultBlockState()); +- return (x, y, z) -> y < Math.min(-54, seaLevel) ? fluidStatus : fluidStatus1; ++ // DivineMC start - C2ME: Optimize world gen math ++ final int min = Math.min(-54, seaLevel); ++ return (x, y, z) -> y < min ? fluidStatus : fluidStatus1; ++ // DivineMC end - C2ME: Optimize world gen math + } + + @Override diff --git a/patches/work/server/minecraft/0023-Re-Fix-MC-117075.patch b/divinemc-server/minecraft-patches/features/0016-Re-Fix-MC-117075.patch similarity index 92% rename from patches/work/server/minecraft/0023-Re-Fix-MC-117075.patch rename to divinemc-server/minecraft-patches/features/0016-Re-Fix-MC-117075.patch index 57b9536..003704e 100644 --- a/patches/work/server/minecraft/0023-Re-Fix-MC-117075.patch +++ b/divinemc-server/minecraft-patches/features/0016-Re-Fix-MC-117075.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Re-Fix MC-117075 diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 6240f6f0799916f1c95505f3dfaeb00812abea70..6e8075618baf98fcc396f0b5e241a806805b3d94 100644 +index 9625213b7c1295b813071dbedea5366510c7072f..bf38e3bfcb0b96c4529d5e535893043512f52b02 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -104,7 +104,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @@ -17,7 +17,7 @@ index 6240f6f0799916f1c95505f3dfaeb00812abea70..6e8075618baf98fcc396f0b5e241a806 protected final NeighborUpdater neighborUpdater; private final List pendingBlockEntityTickers = Lists.newArrayList(); private boolean tickingBlockEntities; -@@ -1504,13 +1504,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1510,13 +1510,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl boolean runsNormally = this.tickRateManager().runsNormally(); int tickedEntities = 0; // Paper - rewrite chunk system @@ -32,7 +32,7 @@ index 6240f6f0799916f1c95505f3dfaeb00812abea70..6e8075618baf98fcc396f0b5e241a806 } else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) { tickingBlockEntity.tick(); // Paper start - rewrite chunk system -@@ -1520,7 +1518,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1526,7 +1524,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl // Paper end - rewrite chunk system } } diff --git a/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch b/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch new file mode 100644 index 0000000..f333219 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 01:58:51 +0300 +Subject: [PATCH] Fix MC-119417 + +Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-119417 + +diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java +index 8a8d72fa46f4eff31e06e8b1756d286f7f1b07a6..b75d2d2746c3e7b12f65b0bcb559cd7e0ce7ebf8 100644 +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -2218,6 +2218,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, gameMode.getId())); + if (gameMode == GameType.SPECTATOR) { + this.removeEntitiesOnShoulder(); ++ this.stopSleeping(); // DivineMC - Fix MC-119417 + this.stopRiding(); + EnchantmentHelper.stopLocationBasedEffects(this); + } else { diff --git a/divinemc-server/minecraft-patches/features/0018-Fix-MC-7569.patch b/divinemc-server/minecraft-patches/features/0018-Fix-MC-7569.patch new file mode 100644 index 0000000..9f8ffc1 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0018-Fix-MC-7569.patch @@ -0,0 +1,20 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 01:59:43 +0300 +Subject: [PATCH] Fix MC-7569 + +Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-7569 + +diff --git a/net/minecraft/server/rcon/RconConsoleSource.java b/net/minecraft/server/rcon/RconConsoleSource.java +index 1fddeb10c5947c52840e55ca66c50dd4ad5425b9..f50d87c5c4c0c3daa38a70213b8a8af963fff312 100644 +--- a/net/minecraft/server/rcon/RconConsoleSource.java ++++ b/net/minecraft/server/rcon/RconConsoleSource.java +@@ -51,7 +51,7 @@ public class RconConsoleSource implements CommandSource { + + @Override + public void sendSystemMessage(Component component) { +- this.buffer.append(component.getString()); ++ this.buffer.append(component.getString()).append(System.lineSeparator()); // DivineMC - Fix MC-7569 + } + + @Override diff --git a/divinemc-server/minecraft-patches/features/0019-Fix-MC-110386.patch b/divinemc-server/minecraft-patches/features/0019-Fix-MC-110386.patch new file mode 100644 index 0000000..69ce25c --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0019-Fix-MC-110386.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:01:33 +0300 +Subject: [PATCH] Fix MC-110386 + +Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-110386 + +diff --git a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java +index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..6251cfface8d4bedd58271ace3947a1631e61b66 100644 +--- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java ++++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java +@@ -114,6 +114,7 @@ public class HurtByTargetGoal extends TargetGoal { + } + + protected void alertOther(Mob mob, LivingEntity target) { ++ if (mob == target) return; // DivineMC - Fix MC-110386 + mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY); // CraftBukkit - reason + } + } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch b/divinemc-server/minecraft-patches/features/0020-Fix-MC-200418.patch similarity index 56% rename from divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch rename to divinemc-server/minecraft-patches/features/0020-Fix-MC-200418.patch index 1927ea1..28eb299 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch +++ b/divinemc-server/minecraft-patches/features/0020-Fix-MC-200418.patch @@ -1,6 +1,15 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:02:47 +0300 +Subject: [PATCH] Fix MC-200418 + +Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-200418 + +diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java +index e218e5d5f146ec996a6f5ce7e76b1d6506ac1cb9..00af89717bf2459b315baf70a515a0e68267fb9f 100644 --- a/net/minecraft/world/entity/monster/ZombieVillager.java +++ b/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -292,6 +_,12 @@ +@@ -292,6 +292,12 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { if (!this.isSilent()) { level.levelEvent(null, 1027, this.blockPosition(), 0); } diff --git a/divinemc-server/minecraft-patches/features/0021-Fix-MC-31819.patch b/divinemc-server/minecraft-patches/features/0021-Fix-MC-31819.patch new file mode 100644 index 0000000..51d07aa --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0021-Fix-MC-31819.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:03:37 +0300 +Subject: [PATCH] Fix MC-31819 + +Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-31819 + +diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java +index 97b104679bb2b9e466caa10d7b022ee6d597e7e5..18b670a1e6e62c3b79281e529c89f35b16427c69 100644 +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -1818,6 +1818,11 @@ public abstract class Player extends LivingEntity { + } + + public void causeFoodExhaustion(float exhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason reason) { ++ // DivineMC start - Fix MC-31819 ++ if (this.level().getDifficulty() == Difficulty.PEACEFUL) { ++ return; ++ } ++ // DivineMC end - Fix MC-31819 + // CraftBukkit end + if (!this.abilities.invulnerable) { + if (!this.level().isClientSide) { diff --git a/divinemc-server/minecraft-patches/features/0022-Fix-MC-172801.patch b/divinemc-server/minecraft-patches/features/0022-Fix-MC-172801.patch new file mode 100644 index 0000000..e9bde40 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0022-Fix-MC-172801.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:04:33 +0300 +Subject: [PATCH] Fix MC-172801 + +Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-172801 + +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index ab2bfe5589547a5e1b7f26ff100609c4464b61c7..4149e7eb6f583d80ed179b190dcc02acf1144bef 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -3274,7 +3274,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin + } + + protected float getFlyingSpeed() { +- return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : 0.02F; ++ // DivineMC start - Fix MC-172801 ++ float flyingSpeed = 0.02F; ++ if (this.getAttributes().hasAttribute(Attributes.FLYING_SPEED)) { ++ flyingSpeed = (float) (this.getAttribute(Attributes.FLYING_SPEED).getValue() * 0.049999999254942D); ++ } ++ return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : flyingSpeed; ++ // DivineMC end - Fix MC-172801 + } + + public float getSpeed() { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/SurfaceRules.java.patch b/divinemc-server/minecraft-patches/features/0023-Fix-MC-258859.patch similarity index 71% rename from divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/SurfaceRules.java.patch rename to divinemc-server/minecraft-patches/features/0023-Fix-MC-258859.patch index 4dcf4ce..7c01f8c 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/SurfaceRules.java.patch +++ b/divinemc-server/minecraft-patches/features/0023-Fix-MC-258859.patch @@ -1,6 +1,15 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:08:04 +0300 +Subject: [PATCH] Fix MC-258859 + +Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-258859 + +diff --git a/net/minecraft/world/level/levelgen/SurfaceRules.java b/net/minecraft/world/level/levelgen/SurfaceRules.java +index 0948c8db90605a15a043b5c5bc74edecd7f9db1b..32757c6847cf77862a2f1b38cc53e7166e6be492 100644 --- a/net/minecraft/world/level/levelgen/SurfaceRules.java +++ b/net/minecraft/world/level/levelgen/SurfaceRules.java -@@ -397,6 +_,22 @@ +@@ -397,6 +397,22 @@ public class SurfaceRules { @Override protected boolean compute() { diff --git a/divinemc-server/minecraft-patches/features/0024-SparklyPaper-Clear-dirty-stats-after-copying.patch b/divinemc-server/minecraft-patches/features/0024-SparklyPaper-Clear-dirty-stats-after-copying.patch new file mode 100644 index 0000000..68a3fe9 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0024-SparklyPaper-Clear-dirty-stats-after-copying.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:10:59 +0300 +Subject: [PATCH] SparklyPaper: Clear dirty stats after copying + +Original project: https://github.com/SparklyPower/SparklyPaper + +diff --git a/net/minecraft/stats/ServerStatsCounter.java b/net/minecraft/stats/ServerStatsCounter.java +index 16e06085ed3c0f6a0b35c730b63b75824f44a905..b2d8f5d146ec10d34a4e71cbfc975fb68e5a8d04 100644 +--- a/net/minecraft/stats/ServerStatsCounter.java ++++ b/net/minecraft/stats/ServerStatsCounter.java +@@ -98,12 +98,6 @@ public class ServerStatsCounter extends StatsCounter { + this.dirty.add(stat); + } + +- private Set> getDirty() { +- Set> set = Sets.newHashSet(this.dirty); +- this.dirty.clear(); +- return set; +- } +- + public void parseLocal(DataFixer fixerUpper, String json) { + try { + JsonElement jsonElement = StrictJsonParser.parse(json); +@@ -139,10 +133,12 @@ public class ServerStatsCounter extends StatsCounter { + public void sendStats(ServerPlayer player) { + Object2IntMap> map = new Object2IntOpenHashMap<>(); + +- for (Stat stat : this.getDirty()) { ++ for (Stat stat : this.dirty) { // DivineMC - SparklyPaper: Skip dirty stats copy when requesting player stats + map.put(stat, this.getValue(stat)); + } + ++ this.dirty.clear(); // DivineMC - SparklyPaper: Clear dirty stats after copying ++ + player.connection.send(new ClientboundAwardStatsPacket(map)); + } + } diff --git a/patches/work/server/minecraft/0006-Async-locate-command.patch b/divinemc-server/minecraft-patches/features/0025-Async-locate-command.patch similarity index 100% rename from patches/work/server/minecraft/0006-Async-locate-command.patch rename to divinemc-server/minecraft-patches/features/0025-Async-locate-command.patch diff --git a/patches/work/server/minecraft/0014-Carpet-Fixes-RecipeManager-Optimize.patch b/divinemc-server/minecraft-patches/features/0026-Carpet-Fixes-RecipeManager-Optimize.patch similarity index 100% rename from patches/work/server/minecraft/0014-Carpet-Fixes-RecipeManager-Optimize.patch rename to divinemc-server/minecraft-patches/features/0026-Carpet-Fixes-RecipeManager-Optimize.patch diff --git a/divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch b/divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch new file mode 100644 index 0000000..5c05869 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch @@ -0,0 +1,216 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:23:03 +0300 +Subject: [PATCH] lithium: faster chunk serialization + +This patch is based on the following mixins and classes: +* "net/caffeinemc/mods/lithium/common/world/chunk/CompactingPackedIntegerArray.java" +* "net/caffeinemc/mods/lithium/common/world/chunk/LithiumHashPalette.java" +* "net/caffeinemc/mods/lithium/mixin/chunk/serialization/SimpleBitStorageMixin.java" +* "net/caffeinemc/mods/lithium/mixin/chunk/serialization/PalettedContainerMixin.java" +By: Angeline +As part of: Lithium (https://github.com/CaffeineMC/lithium-fabric) +Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html) + +diff --git a/net/minecraft/util/BitStorage.java b/net/minecraft/util/BitStorage.java +index 02502d50f0255f5bbcc0ecb965abb48cc1a112da..a0a0ec8747cf6477df8943d2268dece8e064cb33 100644 +--- a/net/minecraft/util/BitStorage.java ++++ b/net/minecraft/util/BitStorage.java +@@ -38,4 +38,6 @@ public interface BitStorage extends ca.spottedleaf.moonrise.patches.block_counti + return ret; + } + // Paper end - block counting ++ ++ void compact(net.minecraft.world.level.chunk.Palette srcPalette, net.minecraft.world.level.chunk.Palette dstPalette, short[] out); // DivineMC - lithium: faster chunk serialization + } +diff --git a/net/minecraft/util/SimpleBitStorage.java b/net/minecraft/util/SimpleBitStorage.java +index e6306a68c8652d4c5d22d5ecb1416f5f931f76ee..1d8125e23e34a929da6fb4e361eae3ccbaeabce9 100644 +--- a/net/minecraft/util/SimpleBitStorage.java ++++ b/net/minecraft/util/SimpleBitStorage.java +@@ -465,4 +465,44 @@ public class SimpleBitStorage implements BitStorage { + super(message); + } + } ++ ++ // DivineMC start - lithium: faster chunk serialization ++ @Override ++ public void compact(net.minecraft.world.level.chunk.Palette srcPalette, net.minecraft.world.level.chunk.Palette dstPalette, short[] out) { ++ if (this.size >= Short.MAX_VALUE) { ++ throw new IllegalStateException("Array too large"); ++ } ++ ++ if (this.size != out.length) { ++ throw new IllegalStateException("Array size mismatch"); ++ } ++ ++ short[] mappings = new short[(int) (this.mask + 1)]; ++ ++ int idx = 0; ++ ++ for (long word : this.data) { ++ long bits = word; ++ ++ for (int elementIdx = 0; elementIdx < this.valuesPerLong; ++elementIdx) { ++ int value = (int) (bits & this.mask); ++ int remappedId = mappings[value]; ++ ++ if (remappedId == 0) { ++ remappedId = dstPalette.idFor(srcPalette.valueFor(value)) + 1; ++ mappings[value] = (short) remappedId; ++ } ++ ++ out[idx] = (short) (remappedId - 1); ++ bits >>= this.bits; ++ ++ ++idx; ++ ++ if (idx >= this.size) { ++ return; ++ } ++ } ++ } ++ } ++ // DivineMC end - lithium: faster chunk serialization + } +diff --git a/net/minecraft/util/ZeroBitStorage.java b/net/minecraft/util/ZeroBitStorage.java +index 09fd99c9cbd23b5f3c899bfb00c9b89651948ed8..6e264b311894f510112beb996190f5ff6943e5e8 100644 +--- a/net/minecraft/util/ZeroBitStorage.java ++++ b/net/minecraft/util/ZeroBitStorage.java +@@ -80,4 +80,6 @@ public class ZeroBitStorage implements BitStorage { + return ret; + } + // Paper end - block counting ++ ++ @Override public void compact(net.minecraft.world.level.chunk.Palette srcPalette, net.minecraft.world.level.chunk.Palette dstPalette, short[] out) { } // DivineMC - lithium: faster chunk serialization + } +diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java +index baa006132b1fa3d73fd4a14f6bc747a3957d1a0c..be11a87ab1badca64219d74bc7a4f5d51b818a8c 100644 +--- a/net/minecraft/world/level/chunk/PalettedContainer.java ++++ b/net/minecraft/world/level/chunk/PalettedContainer.java +@@ -32,6 +32,23 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + public final PalettedContainer.Strategy strategy; + //private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused + ++ // DivineMC start - lithium: faster chunk serialization ++ private static final ThreadLocal CACHED_ARRAY_4096 = ThreadLocal.withInitial(() -> new short[4096]); ++ private static final ThreadLocal CACHED_ARRAY_64 = ThreadLocal.withInitial(() -> new short[64]); ++ ++ private Optional asOptional(long[] data) { ++ return Optional.of(Arrays.stream(data)); ++ } ++ ++ private short[] getOrCreate(int size) { ++ return switch (size) { ++ case 64 -> CACHED_ARRAY_64.get(); ++ case 4096 -> CACHED_ARRAY_4096.get(); ++ default -> new short[size]; ++ }; ++ } ++ // DivineMC end - lithium: faster chunk serialization ++ + public void acquire() { + // this.threadingDetector.checkAndLock(); // Paper - disable this - use proper synchronization + } +@@ -343,28 +360,49 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + public synchronized PalettedContainerRO.PackedData pack(IdMap registry, PalettedContainer.Strategy strategy) { // Paper - synchronize + this.acquire(); + +- PalettedContainerRO.PackedData var12; ++ // DivineMC start - lithium: faster chunk serialization ++ Optional data = Optional.empty(); ++ List elements = null; + try { +- HashMapPalette hashMapPalette = new HashMapPalette<>(registry, this.data.storage.getBits(), this.dummyPaletteResize); +- int size = strategy.size(); +- int[] ints = new int[size]; +- this.data.storage.unpack(ints); +- swapPalette(ints, id -> hashMapPalette.idFor(this.data.palette.valueFor(id))); +- int i = strategy.calculateBitsForSerialization(registry, hashMapPalette.getSize()); +- Optional optional; +- if (i != 0) { +- SimpleBitStorage simpleBitStorage = new SimpleBitStorage(i, size, ints); +- optional = Optional.of(Arrays.stream(simpleBitStorage.getRaw())); +- } else { +- optional = Optional.empty(); ++ net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette hashPalette = null; ++ ++ final Palette palette = this.data.palette(); ++ final BitStorage storage = this.data.storage(); ++ if (storage instanceof ZeroBitStorage || palette.getSize() == 1) { ++ elements = List.of(palette.valueFor(0)); ++ } else if (palette instanceof net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette lithiumHashPalette) { ++ hashPalette = lithiumHashPalette; + } + +- var12 = new PalettedContainerRO.PackedData<>(hashMapPalette.getEntries(), optional); ++ if (elements == null) { ++ net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette compactedPalette = new net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette<>(registry, storage.getBits(), this.dummyPaletteResize); ++ short[] array = this.getOrCreate(strategy.size()); ++ ++ storage.compact(this.data.palette(), compactedPalette, array); ++ ++ if (hashPalette != null && hashPalette.getSize() == compactedPalette.getSize() && storage.getBits() == strategy.calculateBitsForSerialization(registry, hashPalette.getSize())) { // paletteSize can de-sync from palette - see https://github.com/CaffeineMC/lithium-fabric/issues/279 ++ data = this.asOptional(storage.getRaw().clone()); ++ elements = hashPalette.getElements(); ++ } else { ++ int bits = strategy.calculateBitsForSerialization(registry, compactedPalette.getSize()); ++ if (bits != 0) { ++ SimpleBitStorage copy = new SimpleBitStorage(bits, array.length); ++ for (int i = 0; i < array.length; ++i) { ++ copy.set(i, array[i]); ++ } ++ ++ data = this.asOptional(copy.getRaw()); ++ } ++ ++ elements = compactedPalette.getElements(); ++ } ++ } + } finally { + this.release(); + } + +- return var12; ++ return new PalettedContainerRO.PackedData<>(elements, data); ++ // DivineMC end - lithium: faster chunk serialization + } + + private static void swapPalette(int[] bits, IntUnaryOperator operator) { +@@ -404,13 +442,31 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + + @Override + public void count(PalettedContainer.CountConsumer countConsumer) { +- if (this.data.palette.getSize() == 1) { +- countConsumer.accept(this.data.palette.valueFor(0), this.data.storage.getSize()); +- } else { +- Int2IntOpenHashMap map = new Int2IntOpenHashMap(); +- this.data.storage.getAll(id -> map.addTo(id, 1)); +- map.int2IntEntrySet().forEach(idEntry -> countConsumer.accept(this.data.palette.valueFor(idEntry.getIntKey()), idEntry.getIntValue())); ++ // DivineMC start - lithium: faster chunk serialization ++ int len = this.data.palette().getSize(); ++ ++ if (len > 4096) { ++ if (this.data.palette.getSize() == 1) { ++ countConsumer.accept(this.data.palette.valueFor(0), this.data.storage.getSize()); ++ } else { ++ Int2IntOpenHashMap map = new Int2IntOpenHashMap(); ++ this.data.storage.getAll(id -> map.addTo(id, 1)); ++ map.int2IntEntrySet().forEach(idEntry -> countConsumer.accept(this.data.palette.valueFor(idEntry.getIntKey()), idEntry.getIntValue())); ++ } ++ } ++ ++ short[] counts = new short[len]; ++ ++ this.data.storage().getAll(i -> counts[i]++); ++ ++ for (int i = 0; i < counts.length; i++) { ++ T obj = this.data.palette().valueFor(i); ++ ++ if (obj != null) { ++ countConsumer.accept(obj, counts[i]); ++ } + } ++ // DivineMC end - lithium: faster chunk serialization + } + + record Configuration(Palette.Factory factory, int bits) { diff --git a/divinemc-server/minecraft-patches/features/0028-lithium-skip-useless-secondary-poi-sensor.patch b/divinemc-server/minecraft-patches/features/0028-lithium-skip-useless-secondary-poi-sensor.patch new file mode 100644 index 0000000..f128993 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0028-lithium-skip-useless-secondary-poi-sensor.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:26:11 +0300 +Subject: [PATCH] lithium: skip useless secondary poi sensor + +This patch is based on the following mixin: +"net/caffeinemc/mods/lithium/mixin/ai/sensor/secondary_poi/SecondaryPoiSensorMixin.java" +By: 2No2Name <2No2Name@web.de> +As part of: Lithium (https://github.com/CaffeineMC/lithium-fabric) +Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html) + +Lithium description: + +villagers that have no secondary POI (farmland) do not search for it + +diff --git a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java +index dc4a9ddb8479e9d0c4895b19d7d677cdd8ad3faa..c3911232667ae9e1f70397f6ff5e7608694248fa 100644 +--- a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java ++++ b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java +@@ -22,6 +22,12 @@ public class SecondaryPoiSensor extends Sensor { + + @Override + protected void doTick(ServerLevel level, Villager entity) { ++ // DivineMC start - lithium: skip useless secondary poi sensor ++ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.skipUselessSecondaryPoiSensor && entity.getVillagerData().profession().value().secondaryPoi().isEmpty()) { ++ entity.getBrain().eraseMemory(MemoryModuleType.SECONDARY_JOB_SITE); ++ return; ++ } ++ // DivineMC end - lithium: skip useless secondary poi sensor + // Purpur start - Option for Villager Clerics to farm Nether Wart - make sure clerics don't wander to soul sand when the option is off + Brain brain = entity.getBrain(); + if (!level.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().profession().is(net.minecraft.world.entity.npc.VillagerProfession.CLERIC)) { diff --git a/divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch b/divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch new file mode 100644 index 0000000..c6e254d --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:30:53 +0300 +Subject: [PATCH] VMP: skip entity move if movement is zero + +This patch is based on the following mixin: +"com/ishland/vmp/mixins/entity/move_zero_velocity/MixinEntity.java" +By: ishland +As part of: VMP (https://github.com/RelativityMC/VMP-fabric) +Licensed under: MIT (https://opensource.org/licenses/MIT) + +diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java +index f8b37b4ce54afd61a72e9d18ac323540431c655d..54307d5795d3cf36c3a39ff7fd21c92b46626c17 100644 +--- a/net/minecraft/world/entity/Entity.java ++++ b/net/minecraft/world/entity/Entity.java +@@ -372,6 +372,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public boolean isTemporarilyActive; + public long activatedImmunityTick = Integer.MIN_VALUE; + public @Nullable Boolean immuneToFire = null; // Purpur - Fire immune API ++ private boolean boundingBoxChanged = false; // DivineMC - VMP: skip entity move if movement is zero + + public void inactiveTick() { + } +@@ -1119,6 +1120,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + // Paper end - detailed watchdog information + + public void move(MoverType type, Vec3 movement) { ++ if (!this.boundingBoxChanged && movement.equals(Vec3.ZERO)) return; // DivineMC - VMP: skip entity move if movement is zero + final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity + // Paper start - detailed watchdog information + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); +@@ -4426,6 +4428,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public final void setBoundingBox(AABB bb) { ++ if (!this.bb.equals(bb)) this.boundingBoxChanged = true; // DivineMC - VMP: skip entity move if movement is zero + // CraftBukkit start - block invalid bounding boxes + double minX = bb.minX, + minY = bb.minY, diff --git a/divinemc-server/minecraft-patches/features/0030-VMP-store-mob-counts-in-an-array.patch b/divinemc-server/minecraft-patches/features/0030-VMP-store-mob-counts-in-an-array.patch new file mode 100644 index 0000000..aa8fb34 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0030-VMP-store-mob-counts-in-an-array.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:33:29 +0300 +Subject: [PATCH] VMP: store mob counts in an array + +This patch is based on the following mixin: +"com/ishland/vmp/mixins/general/spawn_density_cap/MixinSpawnDensityCapperDensityCap.java" +By: ishland +As part of: VMP (https://github.com/RelativityMC/VMP-fabric) +Licensed under: MIT (https://opensource.org/licenses/MIT) + +diff --git a/net/minecraft/world/level/LocalMobCapCalculator.java b/net/minecraft/world/level/LocalMobCapCalculator.java +index 9641219c190261dea0db5f95f040a705ba0a3ff9..d9fe183dbf072f82afae63792967d6e7953d7151 100644 +--- a/net/minecraft/world/level/LocalMobCapCalculator.java ++++ b/net/minecraft/world/level/LocalMobCapCalculator.java +@@ -42,14 +42,14 @@ public class LocalMobCapCalculator { + } + + static class MobCounts { +- private final Object2IntMap counts = new Object2IntOpenHashMap<>(MobCategory.values().length); ++ private final int[] counts = new int[MobCategory.values().length]; // DivineMC - VMP: store mob counts in an array + + public void add(MobCategory category) { +- this.counts.computeInt(category, (key, value) -> value == null ? 1 : value + 1); ++ this.counts[category.ordinal()]++; // DivineMC - VMP: store mob counts in an array + } + + public boolean canSpawn(MobCategory category) { +- return this.counts.getOrDefault(category, 0) < category.getMaxInstancesPerChunk(); ++ return this.counts[category.ordinal()] < category.getMaxInstancesPerChunk(); // DivineMC - VMP: store mob counts in an array + } + } + } diff --git a/divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch b/divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch new file mode 100644 index 0000000..dd47d8c --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch @@ -0,0 +1,245 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:38:39 +0300 +Subject: [PATCH] C2ME: optimize noise generation + +This patch is based on the following mixins: +* "com/ishland/c2me/opts/math/mixin/MixinOctavePerlinNoiseSampler.java" +* "com/ishland/c2me/opts/math/mixin/MixinPerlinNoiseSampler.java" +By: ishland +As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric) +Licensed under: MIT (https://opensource.org/licenses/MIT) + +diff --git a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java +index 46e98a99442523614284150964ba528d0c91493f..55ae29a5e846bb2a6d6991ce071aefe6a8113ebb 100644 +--- a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java ++++ b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java +@@ -11,6 +11,27 @@ public final class ImprovedNoise { + public final double yo; + public final double zo; + ++ // DivineMC start - C2ME: optimize noise generation ++ private static final double[] FLAT_SIMPLEX_GRAD = new double[]{ ++ 1, 1, 0, 0, ++ -1, 1, 0, 0, ++ 1, -1, 0, 0, ++ -1, -1, 0, 0, ++ 1, 0, 1, 0, ++ -1, 0, 1, 0, ++ 1, 0, -1, 0, ++ -1, 0, -1, 0, ++ 0, 1, 1, 0, ++ 0, -1, 1, 0, ++ 0, 1, -1, 0, ++ 0, -1, -1, 0, ++ 1, 1, 0, 0, ++ 0, -1, 1, 0, ++ -1, 1, 0, 0, ++ 0, -1, -1, 0, ++ }; ++ // DivineMC end - C2ME: optimize noise generation ++ + public ImprovedNoise(RandomSource random) { + this.xo = random.nextDouble() * 256.0; + this.yo = random.nextDouble() * 256.0; +@@ -38,9 +59,11 @@ public final class ImprovedNoise { + double d = x + this.xo; + double d1 = y + this.yo; + double d2 = z + this.zo; +- int floor = Mth.floor(d); +- int floor1 = Mth.floor(d1); +- int floor2 = Mth.floor(d2); ++ // DivineMC start - C2ME: optimize noise generation ++ double floor = Math.floor(d); ++ double floor1 = Math.floor(d1); ++ double floor2 = Math.floor(d2); ++ // DivineMC end - C2ME: optimize noise generation + double d3 = d - floor; + double d4 = d1 - floor1; + double d5 = d2 - floor2; +@@ -53,25 +76,27 @@ public final class ImprovedNoise { + d6 = d4; + } + +- d7 = Mth.floor(d6 / yScale + 1.0E-7F) * yScale; ++ d7 = Math.floor(d6 / yScale + 1.0E-7F) * yScale; // DivineMC - C2ME: optimize noise generation + } else { + d7 = 0.0; + } + +- return this.sampleAndLerp(floor, floor1, floor2, d3, d4 - d7, d5, d4); ++ return this.sampleAndLerp((int) floor, (int) floor1, (int) floor2, d3, d4 - d7, d5, d4); // DivineMC - C2ME: optimize noise generation + } + + public double noiseWithDerivative(double x, double y, double z, double[] values) { + double d = x + this.xo; + double d1 = y + this.yo; + double d2 = z + this.zo; +- int floor = Mth.floor(d); +- int floor1 = Mth.floor(d1); +- int floor2 = Mth.floor(d2); ++ // DivineMC start - C2ME: optimize noise generation ++ double floor = Math.floor(d); ++ double floor1 = Math.floor(d1); ++ double floor2 = Math.floor(d2); ++ // DivineMC end - C2ME: optimize noise generation + double d3 = d - floor; + double d4 = d1 - floor1; + double d5 = d2 - floor2; +- return this.sampleWithDerivative(floor, floor1, floor2, d3, d4, d5, values); ++ return this.sampleWithDerivative((int) floor, (int) floor1, (int) floor2, d3, d4, d5, values); // DivineMC - C2ME: optimize noise generation + } + + private static double gradDot(int gradIndex, double xFactor, double yFactor, double zFactor) { +@@ -83,24 +108,69 @@ public final class ImprovedNoise { + } + + private double sampleAndLerp(int gridX, int gridY, int gridZ, double deltaX, double weirdDeltaY, double deltaZ, double deltaY) { +- int i = this.p(gridX); +- int i1 = this.p(gridX + 1); +- int i2 = this.p(i + gridY); +- int i3 = this.p(i + gridY + 1); +- int i4 = this.p(i1 + gridY); +- int i5 = this.p(i1 + gridY + 1); +- double d = gradDot(this.p(i2 + gridZ), deltaX, weirdDeltaY, deltaZ); +- double d1 = gradDot(this.p(i4 + gridZ), deltaX - 1.0, weirdDeltaY, deltaZ); +- double d2 = gradDot(this.p(i3 + gridZ), deltaX, weirdDeltaY - 1.0, deltaZ); +- double d3 = gradDot(this.p(i5 + gridZ), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ); +- double d4 = gradDot(this.p(i2 + gridZ + 1), deltaX, weirdDeltaY, deltaZ - 1.0); +- double d5 = gradDot(this.p(i4 + gridZ + 1), deltaX - 1.0, weirdDeltaY, deltaZ - 1.0); +- double d6 = gradDot(this.p(i3 + gridZ + 1), deltaX, weirdDeltaY - 1.0, deltaZ - 1.0); +- double d7 = gradDot(this.p(i5 + gridZ + 1), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ - 1.0); +- double d8 = Mth.smoothstep(deltaX); +- double d9 = Mth.smoothstep(deltaY); +- double d10 = Mth.smoothstep(deltaZ); +- return Mth.lerp3(d8, d9, d10, d, d1, d2, d3, d4, d5, d6, d7); ++ // DivineMC start - C2ME: optimize noise generation ++ final int var0 = gridX & 0xFF; ++ final int var1 = (gridX + 1) & 0xFF; ++ final int var2 = this.p[var0] & 0xFF; ++ final int var3 = this.p[var1] & 0xFF; ++ final int var4 = (var2 + gridY) & 0xFF; ++ final int var5 = (var3 + gridY) & 0xFF; ++ final int var6 = (var2 + gridY + 1) & 0xFF; ++ final int var7 = (var3 + gridY + 1) & 0xFF; ++ final int var8 = this.p[var4] & 0xFF; ++ final int var9 = this.p[var5] & 0xFF; ++ final int var10 = this.p[var6] & 0xFF; ++ final int var11 = this.p[var7] & 0xFF; ++ ++ final int var12 = (var8 + gridZ) & 0xFF; ++ final int var13 = (var9 + gridZ) & 0xFF; ++ final int var14 = (var10 + gridZ) & 0xFF; ++ final int var15 = (var11 + gridZ) & 0xFF; ++ final int var16 = (var8 + gridZ + 1) & 0xFF; ++ final int var17 = (var9 + gridZ + 1) & 0xFF; ++ final int var18 = (var10 + gridZ + 1) & 0xFF; ++ final int var19 = (var11 + gridZ + 1) & 0xFF; ++ final int var20 = (this.p[var12] & 15) << 2; ++ final int var21 = (this.p[var13] & 15) << 2; ++ final int var22 = (this.p[var14] & 15) << 2; ++ final int var23 = (this.p[var15] & 15) << 2; ++ final int var24 = (this.p[var16] & 15) << 2; ++ final int var25 = (this.p[var17] & 15) << 2; ++ final int var26 = (this.p[var18] & 15) << 2; ++ final int var27 = (this.p[var19] & 15) << 2; ++ final double var60 = deltaX - 1.0; ++ final double var61 = weirdDeltaY - 1.0; ++ final double var62 = deltaZ - 1.0; ++ final double var87 = FLAT_SIMPLEX_GRAD[(var20) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var20) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var20) | 2] * deltaZ; ++ final double var88 = FLAT_SIMPLEX_GRAD[(var21) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var21) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var21) | 2] * deltaZ; ++ final double var89 = FLAT_SIMPLEX_GRAD[(var22) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var22) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var22) | 2] * deltaZ; ++ final double var90 = FLAT_SIMPLEX_GRAD[(var23) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var23) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var23) | 2] * deltaZ; ++ final double var91 = FLAT_SIMPLEX_GRAD[(var24) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var24) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var24) | 2] * var62; ++ final double var92 = FLAT_SIMPLEX_GRAD[(var25) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var25) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var25) | 2] * var62; ++ final double var93 = FLAT_SIMPLEX_GRAD[(var26) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var26) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var26) | 2] * var62; ++ final double var94 = FLAT_SIMPLEX_GRAD[(var27) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var27) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var27) | 2] * var62; ++ ++ final double var95 = deltaX * 6.0 - 15.0; ++ final double var96 = deltaY * 6.0 - 15.0; ++ final double var97 = deltaZ * 6.0 - 15.0; ++ final double var98 = deltaX * var95 + 10.0; ++ final double var99 = deltaY * var96 + 10.0; ++ final double var100 = deltaZ * var97 + 10.0; ++ final double var101 = deltaX * deltaX * deltaX * var98; ++ final double var102 = deltaY * deltaY * deltaY * var99; ++ final double var103 = deltaZ * deltaZ * deltaZ * var100; ++ ++ final double var113 = var87 + var101 * (var88 - var87); ++ final double var114 = var93 + var101 * (var94 - var93); ++ final double var115 = var91 + var101 * (var92 - var91); ++ final double var116 = var89 + var101 * (var90 - var89); ++ final double var117 = var114 - var115; ++ final double var118 = var102 * (var116 - var113); ++ final double var119 = var102 * var117; ++ final double var120 = var113 + var118; ++ final double var121 = var115 + var119; ++ return var120 + (var103 * (var121 - var120)); ++ // DivineMC end - C2ME: optimize noise generation + } + + private double sampleWithDerivative(int gridX, int gridY, int gridZ, double deltaX, double deltaY, double deltaZ, double[] noiseValues) { +diff --git a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java +index ffac5b7b1eb1364ab8442d7145a7b4ebde68ee10..667d464e61aea2aa7f7b7f1ed082daadc17f723b 100644 +--- a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java ++++ b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java +@@ -26,6 +26,10 @@ public class PerlinNoise { + public final double lowestFreqValueFactor; + public final double lowestFreqInputFactor; + private final double maxValue; ++ // DivineMC start - C2ME: optimize noise generation ++ private final int octaveSamplersCount; ++ private final double [] amplitudesArray; ++ // DivineMC end - C2ME: optimize noise generation + + @Deprecated + public static PerlinNoise createLegacyForBlendedNoise(RandomSource random, IntStream octaves) { +@@ -127,6 +131,10 @@ public class PerlinNoise { + this.lowestFreqInputFactor = Math.pow(2.0, -i); + this.lowestFreqValueFactor = Math.pow(2.0, size - 1) / (Math.pow(2.0, size) - 1.0); + this.maxValue = this.edgeValue(2.0); ++ // DivineMC start - C2ME: optimize noise generation ++ this.octaveSamplersCount = this.noiseLevels.length; ++ this.amplitudesArray = this.amplitudes.toDoubleArray(); ++ // DivineMC end - C2ME: optimize noise generation + } + + protected double maxValue() { +@@ -138,7 +146,27 @@ public class PerlinNoise { + } + + public double getValue(double x, double y, double z) { +- return this.getValue(x, y, z, 0.0, 0.0, false); ++ // DivineMC start - C2ME: optimize noise generation ++ double d = 0.0; ++ double e = this.lowestFreqInputFactor; ++ double f = this.lowestFreqValueFactor; ++ ++ for (int i = 0; i < this.octaveSamplersCount; ++i) { ++ ImprovedNoise perlinNoiseSampler = this.noiseLevels[i]; ++ if (perlinNoiseSampler != null) { ++ @SuppressWarnings("deprecation") ++ double g = perlinNoiseSampler.noise( ++ wrap(x * e), wrap(y * e), wrap(z * e), 0.0, 0.0 ++ ); ++ d += this.amplitudesArray[i] * g * f; ++ } ++ ++ e *= 2.0; ++ f /= 2.0; ++ } ++ ++ return d; ++ // DivineMC end - C2ME: optimize noise generation + } + + @Deprecated +@@ -187,7 +215,7 @@ public class PerlinNoise { + } + + public static double wrap(double value) { +- return value - Mth.lfloor(value / 3.3554432E7 + 0.5) * 3.3554432E7; ++ return value - Math.floor(value / 3.3554432E7 + 0.5) * 3.3554432E7; // DivineMC - C2ME: optimize noise generation + } + + protected int firstOctave() { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/advancements/Advancement.java.patch b/divinemc-server/minecraft-patches/features/0032-Skip-cloning-advancement-criteria.patch similarity index 56% rename from divinemc-server/minecraft-patches/sources/net/minecraft/advancements/Advancement.java.patch rename to divinemc-server/minecraft-patches/features/0032-Skip-cloning-advancement-criteria.patch index fc813cb..ed20d09 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/advancements/Advancement.java.patch +++ b/divinemc-server/minecraft-patches/features/0032-Skip-cloning-advancement-criteria.patch @@ -1,6 +1,14 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:42:57 +0300 +Subject: [PATCH] Skip cloning advancement criteria + + +diff --git a/net/minecraft/advancements/Advancement.java b/net/minecraft/advancements/Advancement.java +index ac6a85ddf6eb326b3fd53341a4a5db7bd00b7ce2..52a285db9557b2e44d2dcae9fabdb0d78d3e7ec6 100644 --- a/net/minecraft/advancements/Advancement.java +++ b/net/minecraft/advancements/Advancement.java -@@ -61,7 +_,7 @@ +@@ -61,7 +61,7 @@ public record Advancement( AdvancementRequirements requirements, boolean sendsTelemetryEvent ) { diff --git a/divinemc-server/minecraft-patches/features/0033-Fix-sprint-glitch.patch b/divinemc-server/minecraft-patches/features/0033-Fix-sprint-glitch.patch new file mode 100644 index 0000000..a6746ed --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0033-Fix-sprint-glitch.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:43:50 +0300 +Subject: [PATCH] Fix sprint glitch + + +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index 4149e7eb6f583d80ed179b190dcc02acf1144bef..9a000a4df5df6e36ae25e6d54bfe7cd725df51dd 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -1420,7 +1420,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin + player.setRealHealth(health); + } + +- player.updateScaledHealth(false); ++ this.entityData.set(LivingEntity.DATA_HEALTH_ID, player.getScaledHealth()); // DivineMC - Fix sprint glitch + return; + } + // CraftBukkit end diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch b/divinemc-server/minecraft-patches/features/0034-Optimize-block-state-lookup.patch similarity index 56% rename from divinemc-server/minecraft-patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch rename to divinemc-server/minecraft-patches/features/0034-Optimize-block-state-lookup.patch index eca174e..09ca985 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch +++ b/divinemc-server/minecraft-patches/features/0034-Optimize-block-state-lookup.patch @@ -1,18 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:47:58 +0300 +Subject: [PATCH] Optimize block state lookup + + +diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java +index d11373d6a88f7b3baaf0e04d4f6e0d3837e2ba3b..6d9274f0da9507d0152611d6b7785e0524dedb2d 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -272,11 +_,18 @@ +@@ -270,11 +270,18 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p public BlockState getBlockStateFinal(final int x, final int y, final int z) { // Copied and modified from below final int sectionIndex = this.getSectionIndex(y); - if (sectionIndex < 0 || sectionIndex >= this.sections.length - || this.sections[sectionIndex].nonEmptyBlockCount == 0) { -- return Blocks.AIR.defaultBlockState(); -- } -- return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15); -+ // DivineMC start - optimize block state lookup ++ // DivineMC start - Optimize block state lookup + if (sectionIndex < 0 || sectionIndex >= this.sections.length) { -+ return Blocks.AIR.defaultBlockState(); -+ } + return Blocks.AIR.defaultBlockState(); + } +- return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15); + + final LevelChunkSection section = this.sections[sectionIndex]; + if (section.nonEmptyBlockCount == 0) { @@ -20,7 +26,7 @@ + } + + return section.states.get((y & 15) << 8 | (z & 15) << 4 | (x & 15)); -+ // DivineMC end - optimize block state lookup ++ // DivineMC end - Optimize block state lookup } @Override diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch b/divinemc-server/minecraft-patches/features/0035-Don-t-respond-ping-before-start-fully.patch similarity index 66% rename from divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch rename to divinemc-server/minecraft-patches/features/0035-Don-t-respond-ping-before-start-fully.patch index 8db46a9..c48b23c 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch +++ b/divinemc-server/minecraft-patches/features/0035-Don-t-respond-ping-before-start-fully.patch @@ -1,6 +1,15 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:48:57 +0300 +Subject: [PATCH] Don't respond ping before start fully + +This is rewritten Purpur patch, to make this configurable + +diff --git a/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/net/minecraft/server/network/ServerStatusPacketListenerImpl.java +index 1b966dc52b067cd9d1fa9f500b692e3f75f1cc90..ff4857522fc9bd5cdd01e3d0161418eef88886fc 100644 --- a/net/minecraft/server/network/ServerStatusPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerStatusPacketListenerImpl.java -@@ -37,7 +_,10 @@ +@@ -37,7 +37,10 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene } else { this.hasRequestedStatus = true; // this.connection.send(new ClientboundStatusResponsePacket(this.status)); // Paper diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch b/divinemc-server/minecraft-patches/features/0036-Respawn-players-that-were-dead-on-server-restart.patch similarity index 66% rename from divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch rename to divinemc-server/minecraft-patches/features/0036-Respawn-players-that-were-dead-on-server-restart.patch index fdc4137..bd66eda 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/divinemc-server/minecraft-patches/features/0036-Respawn-players-that-were-dead-on-server-restart.patch @@ -1,6 +1,14 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 02:50:15 +0300 +Subject: [PATCH] Respawn players that were dead on server restart + + +diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java +index ace14db7bfd154b8a9b27af4a6c57630a3868ac0..abfecaf4467092f7baa02e0f5bbfd23d087f2aa3 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -989,6 +_,13 @@ +@@ -971,6 +971,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Sun, 6 Jul 2025 02:59:37 +0300 +Subject: [PATCH] Use Java's Math functions + + +diff --git a/net/minecraft/util/Mth.java b/net/minecraft/util/Mth.java +index e2602c6d817794616eb05a471077447804b835a1..c4d55514a44939c3e6006d9e23b6097b6360853e 100644 +--- a/net/minecraft/util/Mth.java ++++ b/net/minecraft/util/Mth.java +@@ -58,18 +58,15 @@ public class Mth { + } + + public static int floor(float value) { +- int i = (int)value; +- return value < i ? i - 1 : i; ++ return (int) Math.floor(value); // DivineMC - Use Java's Math functions + } + + public static int floor(double value) { +- int i = (int)value; +- return value < i ? i - 1 : i; ++ return (int) Math.floor(value); // DivineMC - Use Java's Math functions + } + + public static long lfloor(double value) { +- long l = (long)value; +- return value < l ? l - 1L : l; ++ return (long) Math.floor(value); // DivineMC - Use Java's Math functions + } + + public static float abs(float value) { +@@ -81,13 +78,11 @@ public class Mth { + } + + public static int ceil(float value) { +- int i = (int)value; +- return value > i ? i + 1 : i; ++ return (int) Math.ceil(value); // DivineMC - Use Java's Math functions + } + + public static int ceil(double value) { +- int i = (int)value; +- return value > i ? i + 1 : i; ++ return (int) Math.ceil(value); // DivineMC - Use Java's Math functions + } + + public static int clamp(int value, int min, int max) { +@@ -123,15 +118,7 @@ public class Mth { + } + + public static double absMax(double x, double y) { +- if (x < 0.0) { +- x = -x; +- } +- +- if (y < 0.0) { +- y = -y; +- } +- +- return Math.max(x, y); ++ return Math.max(Math.abs(x), Math.abs(y)); // DivineMC - Use Java's Math functions + } + + public static int floorDiv(int dividend, int divisor) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/LeavesBlock.java.patch b/divinemc-server/minecraft-patches/features/0040-Disable-leaf-decay.patch similarity index 68% rename from divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/LeavesBlock.java.patch rename to divinemc-server/minecraft-patches/features/0040-Disable-leaf-decay.patch index 238c940..8194ced 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/LeavesBlock.java.patch +++ b/divinemc-server/minecraft-patches/features/0040-Disable-leaf-decay.patch @@ -1,6 +1,14 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 03:03:04 +0300 +Subject: [PATCH] Disable leaf decay + + +diff --git a/net/minecraft/world/level/block/LeavesBlock.java b/net/minecraft/world/level/block/LeavesBlock.java +index 010e9814490ffaa153df5b7865da17e2a84c7e82..f43dbc0fc05f549521490595fe594c424b2e8a87 100644 --- a/net/minecraft/world/level/block/LeavesBlock.java +++ b/net/minecraft/world/level/block/LeavesBlock.java -@@ -70,12 +_,29 @@ +@@ -70,12 +70,29 @@ public abstract class LeavesBlock extends Block implements SimpleWaterloggedBloc } protected boolean decaying(BlockState state) { @@ -11,7 +19,7 @@ @Override protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - level.setBlock(pos, updateDistance(state, level, pos), 3); -+ // DivineMC start - Make leaves not suffocate the server ++ // DivineMC start - Disable leaf decay + if (org.bxteam.divinemc.config.DivineConfig.FixesCategory.disableLeafDecay) return; // DivineMC - Disable leaf decay + int newValue = 7; + int oldValue = state.getValue(DISTANCE); @@ -28,7 +36,7 @@ + if (newValue != oldValue) { + level.setBlock(pos, state.setValue(DISTANCE, newValue), 3); + } -+ // DivineMC end - Make leaves not suffocate the server ++ // DivineMC end - Disable leaf decay } @Override diff --git a/divinemc-server/minecraft-patches/features/0041-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch b/divinemc-server/minecraft-patches/features/0041-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch new file mode 100644 index 0000000..879c556 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0041-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 03:04:04 +0300 +Subject: [PATCH] Carpet-Fixes: Fix Slime Block Bounce Logic + +This patch is based on the following mixins: +* "carpetfixes/mixins/blockFixes/SlimeBlock_incorrectLogicMixin.java" +By: fxmorin <28154542+fxmorin@users.noreply.github.com> +As part of: carpet-fixes (https://github.com/fxmorin/carpet-fixes) +Licensed under: MIT (https://opensource.org/licenses/MIT) + +Patch description: +Fixes incorrect logic in the slimeblock bounce code which prevents some entities from bouncing. +This bug in the slime code is due to onGround reversing the velocity, the best way to fix this issue is by +setting onGround to true, only once the Y velocity is smaller than -0.15 + +diff --git a/net/minecraft/world/level/block/SlimeBlock.java b/net/minecraft/world/level/block/SlimeBlock.java +index f26c3100d0aad0227f016bfa4c86ac647e13485a..59c9e63e6d5634973cc4927eac479463cc486a4a 100644 +--- a/net/minecraft/world/level/block/SlimeBlock.java ++++ b/net/minecraft/world/level/block/SlimeBlock.java +@@ -42,6 +42,7 @@ public class SlimeBlock extends HalfTransparentBlock { + Vec3 deltaMovement = entity.getDeltaMovement(); + if (deltaMovement.y < 0.0) { + double d = entity instanceof LivingEntity ? 1.0 : 0.8; ++ if (org.bxteam.divinemc.config.DivineConfig.FixesCategory.fixIncorrectBounceLogic) entity.setOnGround(deltaMovement.y > -0.15); // DivineMC - Carpet-Fixes: Fix Slime Block Bounce Logic + entity.setDeltaMovement(deltaMovement.x, -deltaMovement.y * d, deltaMovement.z); + } + } diff --git a/patches/work/server/minecraft/0011-Optimize-entity-stupid-brain.patch b/divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch similarity index 90% rename from patches/work/server/minecraft/0011-Optimize-entity-stupid-brain.patch rename to divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch index b5c5131..cd63311 100644 --- a/patches/work/server/minecraft/0011-Optimize-entity-stupid-brain.patch +++ b/divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch @@ -1,18 +1,18 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 1 Feb 2025 16:05:57 +0300 -Subject: [PATCH] Optimize entity stupid brain +Subject: [PATCH] Optimize entity brain diff --git a/net/minecraft/world/entity/AgeableMob.java b/net/minecraft/world/entity/AgeableMob.java -index 04875840085541ebfc7014868beec49bb7ab9976..bd7e8fa315ca67fcf03d34added45b649d7aaebb 100644 +index 04875840085541ebfc7014868beec49bb7ab9976..bbfb1de1a03c4208406feb803a2f378db9910556 100644 --- a/net/minecraft/world/entity/AgeableMob.java +++ b/net/minecraft/world/entity/AgeableMob.java @@ -125,6 +125,16 @@ public abstract class AgeableMob extends PathfinderMob { public void onSyncedDataUpdated(EntityDataAccessor key) { if (DATA_BABY_ID.equals(key)) { this.refreshDimensions(); -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain + if (isBaby()) { + org.bxteam.divinemc.util.entity.SensorHelper.enableSensor(this, net.minecraft.world.entity.ai.sensing.SensorType.NEAREST_ADULT, true); + } else { @@ -21,12 +21,12 @@ index 04875840085541ebfc7014868beec49bb7ab9976..bd7e8fa315ca67fcf03d34added45b64 + this.getBrain().setMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.NEAREST_VISIBLE_ADULT, java.util.Optional.empty()); + } + } -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain } super.onSyncedDataUpdated(key); diff --git a/net/minecraft/world/entity/ai/Brain.java b/net/minecraft/world/entity/ai/Brain.java -index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca387289be7c 100644 +index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e985deecd05 100644 --- a/net/minecraft/world/entity/ai/Brain.java +++ b/net/minecraft/world/entity/ai/Brain.java @@ -45,16 +45,73 @@ public class Brain { @@ -47,7 +47,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 private final Set activeActivities = Sets.newHashSet(); private Activity defaultActivity = Activity.IDLE; private long lastScheduleUpdate = -9999L; -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain + private java.util.ArrayList> possibleTasks; + private org.bxteam.divinemc.util.collections.MaskedList> runningTasks; + @@ -103,7 +103,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 + } + this.runningTasks = list; + } -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain public static Brain.Provider provider( Collection> memoryTypes, Collection>> sensorTypes @@ -111,12 +111,12 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 for (Brain.MemoryValue memoryValue : memoryValues) { memoryValue.setMemoryInternal(this); } -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain + this.onTasksChanged(); + this.memories = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(this.memories); + this.sensors = new it.unimi.dsi.fastutil.objects.Reference2ReferenceLinkedOpenHashMap<>(this.sensors); + this.activityRequirements = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.activityRequirements); -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain } public DataResult serializeStart(DynamicOps ops) { @@ -132,7 +132,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 this.setMemoryInternal(memoryType, memory.map(ExpirableValue::of)); } -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain void setMemoryInternal(MemoryModuleType memoryType, Optional> memory) { + if (memory.isPresent() && this.isEmptyCollection(memory.get().getValue())) { + this.eraseMemory(memoryType); @@ -162,7 +162,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 + } + return oldValue; + } -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain + public Optional getMemory(MemoryModuleType type) { Optional> optional = this.memories.get(type); @@ -184,7 +184,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 - } - - return list; -+ return this.getCurrentlyRunningTasks(); // DivineMC - Optimize entity stupid brain ++ return this.getCurrentlyRunningTasks(); // DivineMC - Optimize entity brain } public void useDefaultActivity() { @@ -192,7 +192,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 this.activeActivities.clear(); this.activeActivities.addAll(this.coreActivities); this.activeActivities.add(activity); -+ this.onPossibleActivitiesChanged(); // DivineMC - Optimize entity stupid brain ++ this.onPossibleActivitiesChanged(); // DivineMC - Optimize entity brain } } @@ -200,13 +200,13 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 .computeIfAbsent(activity, activity1 -> Sets.newLinkedHashSet()) .add((BehaviorControl)pair.getSecond()); } -+ this.onTasksChanged(); // DivineMC - Optimize entity stupid brain ++ this.onTasksChanged(); // DivineMC - Optimize entity brain } @VisibleForTesting public void removeAllBehaviors() { this.availableBehaviorsByPriority.clear(); -+ this.onTasksChanged(); // DivineMC - Optimize entity stupid brain ++ this.onTasksChanged(); // DivineMC - Optimize entity brain } public boolean isActive(Activity activity) { @@ -214,7 +214,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 } } -+ brain.memoryModCount = this.memoryModCount + 1; // DivineMC - Optimize entity stupid brain ++ brain.memoryModCount = this.memoryModCount + 1; // DivineMC - Optimize entity brain return brain; } @@ -222,15 +222,15 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 for (BehaviorControl behaviorControl : this.getRunningBehaviors()) { behaviorControl.doStop(level, owner, gameTime); -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain + if (this.runningTasks != null) { + this.runningTasks.setVisible(behaviorControl, false); + } -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain } } -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain private void startEachNonRunningBehavior(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - @@ -253,33 +253,33 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..572415b91152756a246eca242eeaca38 } } } -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain private void tickEachRunningBehavior(ServerLevel level, E entity) { long gameTime = level.getGameTime(); for (BehaviorControl behaviorControl : this.getRunningBehaviors()) { behaviorControl.tickOrStop(level, entity, gameTime); -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain + if (this.runningTasks != null && behaviorControl.getStatus() != Behavior.Status.RUNNING) { + this.runningTasks.setVisible(behaviorControl, false); + } -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain } } diff --git a/net/minecraft/world/entity/ai/behavior/Behavior.java b/net/minecraft/world/entity/ai/behavior/Behavior.java -index 5b0cadd2544fb2a627822e645ff32fec2e9cfda9..253b9ad671cf0932bb17d468f8b91a15a86ff77a 100644 +index 5b0cadd2544fb2a627822e645ff32fec2e9cfda9..f367012ebcc4d06ac868bbc1733bee39ad2d67b1 100644 --- a/net/minecraft/world/entity/ai/behavior/Behavior.java +++ b/net/minecraft/world/entity/ai/behavior/Behavior.java @@ -14,6 +14,10 @@ public abstract class Behavior implements BehaviorContro private long endTimestamp; private final int minDuration; private final int maxDuration; -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain + private long cachedMemoryModCount = -1; + private boolean cachedHasRequiredMemoryState; -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain private final String configKey; // Paper - configurable behavior tick rate and timings public Behavior(Map, MemoryStatus> entryCondition) { @@ -288,7 +288,7 @@ index 5b0cadd2544fb2a627822e645ff32fec2e9cfda9..253b9ad671cf0932bb17d468f8b91a15 this.minDuration = minDuration; this.maxDuration = maxDuration; - this.entryCondition = entryCondition; -+ this.entryCondition = new it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap<>(entryCondition); // DivineMC - Optimize entity stupid brain - Use fastutil ++ this.entryCondition = new it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap<>(entryCondition); // DivineMC - Optimize entity brain - Use fastutil // Paper start - configurable behavior tick rate and timings String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName(); int lastSeparator = key.lastIndexOf('.'); @@ -302,7 +302,7 @@ index 5b0cadd2544fb2a627822e645ff32fec2e9cfda9..253b9ad671cf0932bb17d468f8b91a15 - MemoryStatus memoryStatus = entry.getValue(); - if (!owner.getBrain().checkMemory(memoryModuleType, memoryStatus)) { - return false; -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain + public boolean hasRequiredMemories(E entity) { + net.minecraft.world.entity.ai.Brain brain = entity.getBrain(); + long modCount = brain.getMemoryModCount(); @@ -322,24 +322,24 @@ index 5b0cadd2544fb2a627822e645ff32fec2e9cfda9..253b9ad671cf0932bb17d468f8b91a15 - return true; + return this.cachedHasRequiredMemoryState = true; } -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain public static enum Status { STOPPED, diff --git a/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java b/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java -index 977afa268838304abdb34be253ca36ac1c22e99f..55a20253d139bc997d2b5d0c0d928fe67df2da32 100644 +index 977afa268838304abdb34be253ca36ac1c22e99f..ff04ea295b70583137deb8babe5e75ebc755f697 100644 --- a/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java +++ b/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java @@ -119,6 +119,12 @@ public class LongJumpToRandomPos extends Behavior { int x = blockPos.getX(); int y = blockPos.getY(); int z = blockPos.getZ(); -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain + if (this.maxLongJumpWidth < 128 && this.maxLongJumpHeight < 128) { + this.jumpCandidates = org.bxteam.divinemc.util.collections.LongJumpChoiceList.forCenter(blockPos, (byte) this.maxLongJumpWidth, (byte) this.maxLongJumpHeight); + return; + } -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain this.jumpCandidates = BlockPos.betweenClosedStream( x - this.maxLongJumpWidth, y - this.maxLongJumpHeight, @@ -347,7 +347,7 @@ index 977afa268838304abdb34be253ca36ac1c22e99f..55a20253d139bc997d2b5d0c0d928fe6 } } -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain protected Optional getJumpCandidate(ServerLevel level) { - Optional randomItem = WeightedRandom.getRandomItem( - level.random, this.jumpCandidates, LongJumpToRandomPos.PossibleJump::weight @@ -403,20 +403,20 @@ index 24d1928445b5571e040a2b12d5c82e77a880d9bd..dac0a23aebf2dea1972c07d5c82079da private boolean isVillagerBaby(LivingEntity livingEntity) { return livingEntity.getType() == EntityType.VILLAGER && livingEntity.isBaby(); diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java -index 70b32e0d06f9b8b7999df5fdfd773c09394e23fb..36fcc913385afec8bb66c1664b902e4d6868f11d 100644 +index 70b32e0d06f9b8b7999df5fdfd773c09394e23fb..997cff138d5c99b1be9224cb3c96bdfeeb79915a 100644 --- a/net/minecraft/world/entity/animal/goat/Goat.java +++ b/net/minecraft/world/entity/animal/goat/Goat.java @@ -100,6 +100,13 @@ public class Goat extends Animal { this.getNavigation().setCanFloat(true); this.setPathfindingMalus(PathType.POWDER_SNOW, -1.0F); this.setPathfindingMalus(PathType.DANGER_POWDER_SNOW, -1.0F); -+ // DivineMC start - Optimize entity stupid brain ++ // DivineMC start - Optimize entity brain + if (!this.getBrain().hasMemoryValue(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM)) { + org.bxteam.divinemc.util.entity.SensorHelper.disableSensor(this, SensorType.NEAREST_ITEMS); + } else if (net.minecraft.SharedConstants.IS_RUNNING_IN_IDE) { + throw new IllegalStateException("Goat Entity has a nearest visible wanted item memory module! This patch(Optimize-Brain, Goat.java changes) should probably be removed permanently!"); + } -+ // DivineMC end - Optimize entity stupid brain ++ // DivineMC end - Optimize entity brain } public ItemStack createHorn() { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch deleted file mode 100644 index ead6666..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/net/minecraft/server/level/ServerPlayer.java -+++ b/net/minecraft/server/level/ServerPlayer.java -@@ -2224,6 +_,7 @@ - this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, gameMode.getId())); - if (gameMode == GameType.SPECTATOR) { - this.removeEntitiesOnShoulder(); -+ this.stopSleeping(); // DivineMC - Fix MC-119417 - this.stopRiding(); - EnchantmentHelper.stopLocationBasedEffects(this); - } else { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch deleted file mode 100644 index 2650c35..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ /dev/null @@ -1,19 +0,0 @@ ---- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -754,8 +_,14 @@ - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); - if (packet.getId() == this.awaitingTeleport) { - if (this.awaitingPositionFromClient == null) { -- ServerGamePacketListenerImpl.LOGGER.warn("Disconnected on accept teleport packet. Was not expecting position data from client at this time"); // Purpur - Add more logger output for invalid movement kicks -- this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause -+ // DivineMC start - Graceful teleport handling -+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.gracefulTeleportHandling) { -+ LOGGER.info("Was not expecting position data from client at this time, gracefully returning instead of disconnect."); -+ } else { -+ ServerGamePacketListenerImpl.LOGGER.warn("Disconnected on accept teleport packet. Was not expecting position data from client at this time"); // Purpur - Add more logger output for invalid movement kicks -+ this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause -+ } -+ // DivineMC end - Graceful teleport handling - return; - } - diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch deleted file mode 100644 index d0171c4..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/net/minecraft/server/players/PlayerList.java -+++ b/net/minecraft/server/players/PlayerList.java -@@ -678,7 +_,6 @@ - } - - public ServerPlayer respawn(ServerPlayer player, boolean keepInventory, Entity.RemovalReason reason, @Nullable org.bukkit.event.player.PlayerRespawnEvent.RespawnReason eventReason, @Nullable org.bukkit.Location location) { -- player.stopRiding(); // CraftBukkit - this.players.remove(player); - this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot - player.level().removePlayerImmediately(player, reason); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch deleted file mode 100644 index 8711080..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/server/rcon/RconConsoleSource.java -+++ b/net/minecraft/server/rcon/RconConsoleSource.java -@@ -51,7 +_,7 @@ - - @Override - public void sendSystemMessage(Component component) { -- this.buffer.append(component.getString()); -+ this.buffer.append(component.getString()).append(System.lineSeparator()); // DivineMC - Fix MC-7569 - } - - @Override diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch deleted file mode 100644 index 3197eab..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- a/net/minecraft/stats/ServerStatsCounter.java -+++ b/net/minecraft/stats/ServerStatsCounter.java -@@ -98,12 +_,6 @@ - this.dirty.add(stat); - } - -- private Set> getDirty() { -- Set> set = Sets.newHashSet(this.dirty); -- this.dirty.clear(); -- return set; -- } -- - public void parseLocal(DataFixer fixerUpper, String json) { - try { - JsonElement jsonElement = StrictJsonParser.parse(json); -@@ -139,9 +_,11 @@ - public void sendStats(ServerPlayer player) { - Object2IntMap> map = new Object2IntOpenHashMap<>(); - -- for (Stat stat : this.getDirty()) { -+ for (Stat stat : this.dirty) { // DivineMC - Skip dirty stats copy when requesting player stats - map.put(stat, this.getValue(stat)); - } -+ -+ this.dirty.clear(); // DivineMC - Skip dirty stats copy when requesting player stats - - player.connection.send(new ClientboundAwardStatsPacket(map)); - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch deleted file mode 100644 index 27fed65..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ /dev/null @@ -1,42 +0,0 @@ ---- a/net/minecraft/world/entity/LivingEntity.java -+++ b/net/minecraft/world/entity/LivingEntity.java -@@ -1425,7 +_,7 @@ - player.setRealHealth(health); - } - -- player.updateScaledHealth(false); -+ this.entityData.set(LivingEntity.DATA_HEALTH_ID, player.getScaledHealth()); // DivineMC - Fix sprint glitch - return; - } - // CraftBukkit end -@@ -2762,6 +_,7 @@ - } - - protected void updateSwingTime() { -+ if (!this.swinging && this.swingTime == 0) return; // DivineMC - lithium: entity.fast_hand_swing - int currentSwingDuration = this.getCurrentSwingDuration(); - if (this.swinging) { - this.swingTime++; -@@ -3278,7 +_,13 @@ - } - - protected float getFlyingSpeed() { -- return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : 0.02F; -+ // DivineMC start - Fix MC-172801 -+ float flyingSpeed = 0.02F; -+ if (this.getAttributes().hasAttribute(Attributes.FLYING_SPEED)) { -+ flyingSpeed = (float) (this.getAttribute(Attributes.FLYING_SPEED).getValue() * 0.049999999254942D); -+ } -+ return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : flyingSpeed; -+ // DivineMC end - Fix MC-172801 - } - - public float getSpeed() { -@@ -3727,6 +_,7 @@ - protected void updateFallFlying() { - this.checkFallDistanceAccumulation(); - if (!this.level().isClientSide) { -+ if (!this.isFallFlying() && this.fallFlyTicks == 0) return; // DivineMC - lithium: entity.fast_elytra_check - if (!this.canGlide()) { - if (this.getSharedFlag(7) != false && !CraftEventFactory.callToggleGlideEvent(this, false).isCancelled()) // CraftBukkit - this.setSharedFlag(7, false); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch deleted file mode 100644 index e825eb7..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java -+++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java -@@ -114,6 +_,7 @@ - } - - protected void alertOther(Mob mob, LivingEntity target) { -+ if (mob == target) return; // DivineMC - Fix MC-110386 - mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY); // CraftBukkit - reason - } - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java.patch deleted file mode 100644 index 58c8ef6..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java -+++ b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java -@@ -22,6 +_,12 @@ - - @Override - protected void doTick(ServerLevel level, Villager entity) { -+ // DivineMC start - skip useless secondary poi sensor -+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.skipUselessSecondaryPoiSensor && entity.getVillagerData().profession().value().secondaryPoi().isEmpty()) { -+ entity.getBrain().eraseMemory(MemoryModuleType.SECONDARY_JOB_SITE); -+ return; -+ } -+ // DivineMC end - skip useless secondary poi sensor - // Purpur start - Option for Villager Clerics to farm Nether Wart - make sure clerics don't wander to soul sand when the option is off - Brain brain = entity.getBrain(); - if (!level.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().profession().is(net.minecraft.world.entity.npc.VillagerProfession.CLERIC)) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch deleted file mode 100644 index 760724e..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/net/minecraft/world/entity/player/Player.java -+++ b/net/minecraft/world/entity/player/Player.java -@@ -1818,6 +_,11 @@ - } - - public void causeFoodExhaustion(float exhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason reason) { -+ // DivineMC start - Fix MC-31819 -+ if (this.level().getDifficulty() == Difficulty.PEACEFUL) { -+ return; -+ } -+ // DivineMC end - Fix MC-31819 - // CraftBukkit end - if (!this.abilities.invulnerable) { - if (!this.level().isClientSide) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch deleted file mode 100644 index fdec8a3..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/net/minecraft/world/level/BaseCommandBlock.java -+++ b/net/minecraft/world/level/BaseCommandBlock.java -@@ -22,7 +_,7 @@ - import net.minecraft.world.phys.Vec3; - - public abstract class BaseCommandBlock implements CommandSource { -- private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss"); -+ private static final ThreadLocal TIME_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss")); // DivineMC - Make it thread safe - private static final Component DEFAULT_NAME = Component.literal("@"); - private static final int NO_LAST_EXECUTION = -1; - private long lastExecution = -1L; -@@ -156,7 +_,7 @@ - public void sendSystemMessage(Component component) { - if (this.trackOutput) { - org.spigotmc.AsyncCatcher.catchOp("sendSystemMessage to a command block"); // Paper - Don't broadcast messages to command blocks -- this.lastOutput = Component.literal("[" + TIME_FORMAT.format(new Date()) + "] ").append(component); -+ this.lastOutput = Component.literal("[" + TIME_FORMAT.get().format(new Date()) + "] ").append(component); // DivineMC - Make it thread safe - this.onUpdated(); - } - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch deleted file mode 100644 index c4a7f26..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/net/minecraft/world/level/block/Blocks.java -+++ b/net/minecraft/world/level/block/Blocks.java -@@ -6732,6 +_,7 @@ - .mapColor(MapColor.COLOR_ORANGE) - .instrument(NoteBlockInstrument.BASEDRUM) - .requiresCorrectToolForDrops() -+ .sound(SoundType.COPPER) // DivineMC - Fix MC-223153 - .strength(5.0F, 6.0F) - ); - public static final Block RAW_GOLD_BLOCK = register( diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/SlimeBlock.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/SlimeBlock.java.patch deleted file mode 100644 index 07460b9..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/SlimeBlock.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/net/minecraft/world/level/block/SlimeBlock.java -+++ b/net/minecraft/world/level/block/SlimeBlock.java -@@ -42,6 +_,7 @@ - Vec3 deltaMovement = entity.getDeltaMovement(); - if (deltaMovement.y < 0.0) { - double d = entity instanceof LivingEntity ? 1.0 : 0.8; -+ if (org.bxteam.divinemc.config.DivineConfig.FixesCategory.fixIncorrectBounceLogic) entity.setOnGround(deltaMovement.y > -0.15); // DivineMC - Carpet-Fixes: Fix Slime Block Bounce Logic - entity.setDeltaMovement(deltaMovement.x, -deltaMovement.y * d, deltaMovement.z); - } - } diff --git a/divinemc-server/src/main/java/net/caffeinemc/mods/lithium/common/world/chunk/LithiumHashPalette.java b/divinemc-server/src/main/java/net/caffeinemc/mods/lithium/common/world/chunk/LithiumHashPalette.java new file mode 100644 index 0000000..ea53ef3 --- /dev/null +++ b/divinemc-server/src/main/java/net/caffeinemc/mods/lithium/common/world/chunk/LithiumHashPalette.java @@ -0,0 +1,207 @@ +package net.caffeinemc.mods.lithium.common.world.chunk; + +import it.unimi.dsi.fastutil.HashCommon; +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; +import net.minecraft.core.IdMap; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.VarInt; +import net.minecraft.world.level.chunk.MissingPaletteEntryException; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PaletteResize; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +import static it.unimi.dsi.fastutil.Hash.FAST_LOAD_FACTOR; + +/** + * Generally provides better performance over the vanilla {@link net.minecraft.world.level.chunk.HashMapPalette} when calling + * {@link LithiumHashPalette#idFor(Object)} through using a faster backing map and reducing pointer chasing. + */ +public class LithiumHashPalette implements Palette { + private static final int ABSENT_VALUE = -1; + + private final IdMap idList; + private final PaletteResize resizeHandler; + private final int indexBits; + + private final Reference2IntOpenHashMap table; + private T[] entries; + private int size = 0; + + private LithiumHashPalette(IdMap idList, PaletteResize resizeHandler, int indexBits, T[] entries, Reference2IntOpenHashMap table, int size) { + this.idList = idList; + this.resizeHandler = resizeHandler; + this.indexBits = indexBits; + this.entries = entries; + this.table = table; + this.size = size; + } + + public LithiumHashPalette(IdMap idList, int bits, PaletteResize resizeHandler, List list) { + this(idList, bits, resizeHandler); + + for (T t : list) { + this.addEntry(t); + } + } + + @SuppressWarnings("unchecked") + public LithiumHashPalette(IdMap idList, int bits, PaletteResize resizeHandler) { + this.idList = idList; + this.indexBits = bits; + this.resizeHandler = resizeHandler; + + int capacity = 1 << bits; + + this.entries = (T[]) new Object[capacity]; + this.table = new Reference2IntOpenHashMap<>(capacity, FAST_LOAD_FACTOR); + this.table.defaultReturnValue(ABSENT_VALUE); + } + + @Override + public int idFor(@NotNull T obj) { + int id = this.table.getInt(obj); + + if (id == ABSENT_VALUE) { + id = this.computeEntry(obj); + } + + return id; + } + + @Override + public boolean maybeHas(@NotNull Predicate predicate) { + for (int i = 0; i < this.size; ++i) { + if (predicate.test(this.entries[i])) { + return true; + } + } + + return false; + } + + private int computeEntry(T obj) { + int id = this.addEntry(obj); + + if (id >= 1 << this.indexBits) { + if (this.resizeHandler == null) { + throw new IllegalStateException("Cannot grow"); + } else { + id = this.resizeHandler.onResize(this.indexBits + 1, obj); + } + } + + return id; + } + + private int addEntry(T obj) { + int nextId = this.size; + + if (nextId >= this.entries.length) { + this.resize(this.size); + } + + this.table.put(obj, nextId); + this.entries[nextId] = obj; + + this.size++; + + return nextId; + } + + private void resize(int neededCapacity) { + this.entries = Arrays.copyOf(this.entries, HashCommon.nextPowerOfTwo(neededCapacity + 1)); + } + + @Override + public @NotNull T valueFor(int id) { + T[] entries = this.entries; + + T entry = null; + if (id >= 0 && id < entries.length) { + entry = entries[id]; + } + + if (entry != null) { + return entry; + } else { + throw this.missingPaletteEntryCrash(id); + } + } + + private ReportedException missingPaletteEntryCrash(int id) { + try { + throw new MissingPaletteEntryException(id); + } catch (MissingPaletteEntryException e) { + CrashReport crashReport = CrashReport.forThrowable(e, "[Lithium] Getting Palette Entry"); + CrashReportCategory crashReportCategory = crashReport.addCategory("Chunk section"); + crashReportCategory.setDetail("IndexBits", this.indexBits); + crashReportCategory.setDetail("Entries", this.entries.length + " Elements: " + Arrays.toString(this.entries)); + crashReportCategory.setDetail("Table", this.table.size() + " Elements: " + this.table); + return new ReportedException(crashReport); + } + } + + @Override + public void read(FriendlyByteBuf buf) { + this.clear(); + + int entryCount = buf.readVarInt(); + + for (int i = 0; i < entryCount; ++i) { + this.addEntry(this.idList.byIdOrThrow(buf.readVarInt())); + } + } + + @Override + public void write(FriendlyByteBuf buf) { + int size = this.size; + buf.writeVarInt(size); + + for (int i = 0; i < size; ++i) { + buf.writeVarInt(this.idList.getId(this.valueFor(i))); + } + } + + @Override + public int getSerializedSize() { + int size = VarInt.getByteSize(this.size); + + for (int i = 0; i < this.size; ++i) { + size += VarInt.getByteSize(this.idList.getId(this.valueFor(i))); + } + + return size; + } + + @Override + public int getSize() { + return this.size; + } + + @Override + public @NotNull Palette copy(@NotNull PaletteResize resizeHandler) { + return new LithiumHashPalette<>(this.idList, resizeHandler, this.indexBits, this.entries.clone(), this.table.clone(), this.size); + } + + private void clear() { + Arrays.fill(this.entries, null); + this.table.clear(); + this.size = 0; + } + + public List getElements() { + T[] copy = Arrays.copyOf(this.entries, this.size); + return Arrays.asList(copy); + } + + public static Palette create(int bits, IdMap idList, PaletteResize listener, List list) { + return new LithiumHashPalette<>(idList, bits, listener, list); + } +} diff --git a/patches/work/server/minecraft/0053-Regionized-Chunk-Ticking.patch b/patches/work/server/minecraft/0009-Regionized-Chunk-Ticking.patch similarity index 99% rename from patches/work/server/minecraft/0053-Regionized-Chunk-Ticking.patch rename to patches/work/server/minecraft/0009-Regionized-Chunk-Ticking.patch index 8751889..a6fd509 100644 --- a/patches/work/server/minecraft/0053-Regionized-Chunk-Ticking.patch +++ b/patches/work/server/minecraft/0009-Regionized-Chunk-Ticking.patch @@ -7,6 +7,8 @@ This patch adds regionized chunk ticking feature, by grouping adjacent chunks in Original idea by Dueris, modified by NONPLAYT and heavily optimized by dan28000 +TODO: switchable VT + diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java index cdacbfa64bda461d4f24c2a85db9feae7766b597..07370cb7bc0bb5a8abfd0062df999ed24c936113 100644 --- a/net/minecraft/network/Connection.java diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java.patch b/patches/work/server/sources/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java.patch similarity index 100% rename from divinemc-server/minecraft-patches/sources/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java.patch rename to patches/work/server/sources/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java.patch From d747da3f7c2f1a258a3e30dc0900e3161fc73a2f Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Mon, 7 Jul 2025 03:02:18 +0300 Subject: [PATCH 04/67] another patch split --- .../features/0001-Rebrand.patch | 32 +++++ ...p-distanceToSqr-call-in-ServerEntity.patch | 12 +- ...rpet-Fixes-Optimized-getBiome-method.patch | 119 ++++++++++++++++++ .../0021-Verify-Minecraft-EULA-earlier.patch | 38 ------ 4 files changed, 160 insertions(+), 41 deletions(-) rename patches/work/server/minecraft/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch => divinemc-server/minecraft-patches/features/0043-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch (84%) create mode 100644 divinemc-server/minecraft-patches/features/0044-Carpet-Fixes-Optimized-getBiome-method.patch delete mode 100644 patches/work/server/minecraft/0021-Verify-Minecraft-EULA-earlier.patch diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index 2730a0a..6aa2336 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -17,6 +17,38 @@ index 394443d00e661715439be1e56dddc129947699a4..480ad57a6b7b74e6b83e9c6ceb69ea1f public CrashReport(String title, Throwable exception) { io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper +diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java +index bc3209d3cbe971af74b7856caa6300b59b0bb6bc..9a19c36074b9d8eb291b15b080687e47bcd5d007 100644 +--- a/net/minecraft/server/Main.java ++++ b/net/minecraft/server/Main.java +@@ -124,7 +124,6 @@ public class Main { + dedicatedServerSettings.forceSave(); + RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression); + Path path2 = Paths.get("eula.txt"); +- Eula eula = new Eula(path2); + // Paper start - load config files early for access below if needed + 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")); +@@ -147,19 +146,6 @@ public class Main { + return; + } + +- // Spigot start +- boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree"); +- if (eulaAgreed) { +- LOGGER.error("You have used the Spigot command line EULA agreement flag."); +- LOGGER.error("By using this setting you are indicating your agreement to Mojang's EULA (https://aka.ms/MinecraftEULA)."); +- LOGGER.error("If you do not agree to the above EULA please stop your server and remove this flag immediately."); +- } +- if (!eula.hasAgreedToEULA() && !eulaAgreed) { +- // Spigot end +- LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info."); +- return; +- } +- + // Paper start - Detect headless JRE + String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck(); + if (awtException != null) { diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java index 306230339574bc35a309877033fa6012e4596f08..1362f3d2ef75d8b18ac2142194ff5b3f2104ac1e 100644 --- a/net/minecraft/server/MinecraftServer.java diff --git a/patches/work/server/minecraft/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch b/divinemc-server/minecraft-patches/features/0043-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch similarity index 84% rename from patches/work/server/minecraft/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch rename to divinemc-server/minecraft-patches/features/0043-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch index 2b5363e..8bb2e69 100644 --- a/patches/work/server/minecraft/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch +++ b/divinemc-server/minecraft-patches/features/0043-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch @@ -1,12 +1,18 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 1 Feb 2025 19:50:02 +0300 -Subject: [PATCH] Skip distanceToSqr call in ServerEntity#sendChanges if the - delta movement hasn't changed +Subject: [PATCH] SparklyPaper: Skip distanceToSqr call in + ServerEntity#sendChanges if the delta movement hasn't changed +Original project: https://github.com/SparklyPower/SparklyPaper + +Patch description: + +The "distanceToSqr" call is a bit expensive, so avoiding it is pretty nice, around ~15% calls are skipped with this check +We could also check if the x,y,z coordinates are equal, but for now, let's just keep the identity check, which also helps us since Minecraft's code does reuse the original delta movement Vec3 object diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java -index fa0fd2a7f15a076ac981f85f4f249a15a4ab512e..ff2f1e31633749da89cfc0779004ac1ef104470d 100644 +index e96d4dee14c05f2fa329bfb1588ec795d4e3d730..0868189fee30d40dfb82ae39592a65b510e96b54 100644 --- a/net/minecraft/server/level/ServerEntity.java +++ b/net/minecraft/server/level/ServerEntity.java @@ -209,23 +209,27 @@ public class ServerEntity { diff --git a/divinemc-server/minecraft-patches/features/0044-Carpet-Fixes-Optimized-getBiome-method.patch b/divinemc-server/minecraft-patches/features/0044-Carpet-Fixes-Optimized-getBiome-method.patch new file mode 100644 index 0000000..16d76d0 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0044-Carpet-Fixes-Optimized-getBiome-method.patch @@ -0,0 +1,119 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 6 Jul 2025 03:24:48 +0300 +Subject: [PATCH] Carpet-Fixes: Optimized getBiome method + +Original license: MIT +Original project: https://github.com/fxmorin/carpet-fixes + +diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java +index 73962e79a0f3d892e3155443a1b84508b0f4042e..c5fa1d7613410593f5b430968398c4ab1b40a98b 100644 +--- a/net/minecraft/world/level/biome/BiomeManager.java ++++ b/net/minecraft/world/level/biome/BiomeManager.java +@@ -14,6 +14,7 @@ public class BiomeManager { + private static final int ZOOM_MASK = 3; + private final BiomeManager.NoiseBiomeSource noiseBiomeSource; + private final long biomeZoomSeed; ++ private static final double maxOffset = 0.4500000001D; // DivineMC - Carpet-Fixes: Optimized getBiome method + + public BiomeManager(BiomeManager.NoiseBiomeSource noiseBiomeSource, long biomeZoomSeed) { + this.noiseBiomeSource = noiseBiomeSource; +@@ -29,39 +30,68 @@ public class BiomeManager { + } + + public Holder getBiome(BlockPos pos) { +- int i = pos.getX() - 2; +- int i1 = pos.getY() - 2; +- int i2 = pos.getZ() - 2; +- int i3 = i >> 2; +- int i4 = i1 >> 2; +- int i5 = i2 >> 2; +- double d = (i & 3) / 4.0; +- double d1 = (i1 & 3) / 4.0; +- double d2 = (i2 & 3) / 4.0; +- int i6 = 0; +- double d3 = Double.POSITIVE_INFINITY; +- +- for (int i7 = 0; i7 < 8; i7++) { +- boolean flag = (i7 & 4) == 0; +- boolean flag1 = (i7 & 2) == 0; +- boolean flag2 = (i7 & 1) == 0; +- int i8 = flag ? i3 : i3 + 1; +- int i9 = flag1 ? i4 : i4 + 1; +- int i10 = flag2 ? i5 : i5 + 1; +- double d4 = flag ? d : d - 1.0; +- double d5 = flag1 ? d1 : d1 - 1.0; +- double d6 = flag2 ? d2 : d2 - 1.0; +- double fiddledDistance = getFiddledDistance(this.biomeZoomSeed, i8, i9, i10, d4, d5, d6); +- if (d3 > fiddledDistance) { +- i6 = i7; +- d3 = fiddledDistance; ++ // DivineMC start - Carpet-Fixes: Optimized getBiome method ++ int xMinus2 = pos.getX() - 2; ++ int yMinus2 = pos.getY() - 2; ++ int zMinus2 = pos.getZ() - 2; ++ int x = xMinus2 >> 2; ++ int y = yMinus2 >> 2; ++ int z = zMinus2 >> 2; ++ double quartX = (double) (xMinus2 & 3) / 4.0; ++ double quartY = (double) (yMinus2 & 3) / 4.0; ++ double quartZ = (double) (zMinus2 & 3) / 4.0; ++ int smallestX = 0; ++ double smallestDist = Double.POSITIVE_INFINITY; ++ ++ for (int biomeX = 0; biomeX < 8; ++biomeX) { ++ boolean everyOtherQuad = (biomeX & 4) == 0; ++ boolean everyOtherPair = (biomeX & 2) == 0; ++ boolean everyOther = (biomeX & 1) == 0; ++ double quartXX = everyOtherQuad ? quartX : quartX - 1.0; ++ double quartYY = everyOtherPair ? quartY : quartY - 1.0; ++ double quartZZ = everyOther ? quartZ : quartZ - 1.0; ++ ++ double maxQuartYY = 0.0, maxQuartZZ = 0.0; ++ if (biomeX != 0) { ++ maxQuartYY = Mth.square(Math.max(quartYY + maxOffset, Math.abs(quartYY - maxOffset))); ++ maxQuartZZ = Mth.square(Math.max(quartZZ + maxOffset, Math.abs(quartZZ - maxOffset))); ++ double maxQuartXX = Mth.square(Math.max(quartXX + maxOffset, Math.abs(quartXX - maxOffset))); ++ if (smallestDist < maxQuartXX + maxQuartYY + maxQuartZZ) continue; ++ } ++ ++ int xx = everyOtherQuad ? x : x + 1; ++ int yy = everyOtherPair ? y : y + 1; ++ int zz = everyOther ? z : z + 1; ++ ++ long seed = LinearCongruentialGenerator.next(this.biomeZoomSeed, xx); ++ seed = LinearCongruentialGenerator.next(seed, yy); ++ seed = LinearCongruentialGenerator.next(seed, zz); ++ seed = LinearCongruentialGenerator.next(seed, xx); ++ seed = LinearCongruentialGenerator.next(seed, yy); ++ seed = LinearCongruentialGenerator.next(seed, zz); ++ double offsetX = getFiddle(seed); ++ double sqrX = Mth.square(quartXX + offsetX); ++ if (biomeX != 0 && smallestDist < sqrX + maxQuartYY + maxQuartZZ) continue; ++ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed); ++ double offsetY = getFiddle(seed); ++ double sqrY = Mth.square(quartYY + offsetY); ++ if (biomeX != 0 && smallestDist < sqrX + sqrY + maxQuartZZ) continue; ++ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed); ++ double offsetZ = getFiddle(seed); ++ double biomeDist = sqrX + sqrY + Mth.square(quartZZ + offsetZ); ++ ++ if (smallestDist > biomeDist) { ++ smallestX = biomeX; ++ smallestDist = biomeDist; + } + } + +- int i7x = (i6 & 4) == 0 ? i3 : i3 + 1; +- int i11 = (i6 & 2) == 0 ? i4 : i4 + 1; +- int i12 = (i6 & 1) == 0 ? i5 : i5 + 1; +- return this.noiseBiomeSource.getNoiseBiome(i7x, i11, i12); ++ return this.noiseBiomeSource.getNoiseBiome( ++ (smallestX & 4) == 0 ? x : x + 1, ++ (smallestX & 2) == 0 ? y : y + 1, ++ (smallestX & 1) == 0 ? z : z + 1 ++ ); ++ // DivineMC end - Carpet-Fixes: Optimized getBiome method + } + + public Holder getNoiseBiomeAtPosition(double x, double y, double z) { diff --git a/patches/work/server/minecraft/0021-Verify-Minecraft-EULA-earlier.patch b/patches/work/server/minecraft/0021-Verify-Minecraft-EULA-earlier.patch deleted file mode 100644 index 67a1e22..0000000 --- a/patches/work/server/minecraft/0021-Verify-Minecraft-EULA-earlier.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Wed, 5 Feb 2025 17:48:56 +0300 -Subject: [PATCH] Verify Minecraft EULA earlier - - -diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java -index bc3209d3cbe971af74b7856caa6300b59b0bb6bc..9a19c36074b9d8eb291b15b080687e47bcd5d007 100644 ---- a/net/minecraft/server/Main.java -+++ b/net/minecraft/server/Main.java -@@ -124,7 +124,6 @@ public class Main { - dedicatedServerSettings.forceSave(); - RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression); - Path path2 = Paths.get("eula.txt"); -- Eula eula = new Eula(path2); - // Paper start - load config files early for access below if needed - 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")); -@@ -147,19 +146,6 @@ public class Main { - return; - } - -- // Spigot start -- boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree"); -- if (eulaAgreed) { -- LOGGER.error("You have used the Spigot command line EULA agreement flag."); -- LOGGER.error("By using this setting you are indicating your agreement to Mojang's EULA (https://aka.ms/MinecraftEULA)."); -- LOGGER.error("If you do not agree to the above EULA please stop your server and remove this flag immediately."); -- } -- if (!eula.hasAgreedToEULA() && !eulaAgreed) { -- // Spigot end -- LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info."); -- return; -- } -- - // Paper start - Detect headless JRE - String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck(); - if (awtException != null) { From 5d8e197e8fbfe24e9f511a3d67033eb7f451e45b Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Mon, 7 Jul 2025 03:26:40 +0300 Subject: [PATCH 05/67] some fix --- ...003-Completely-remove-Mojang-profiler.patch | 18 +++++++++--------- .../ServerGamePacketListenerImpl.java.patch | 0 2 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch diff --git a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch index cffdebc..ca48538 100644 --- a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch +++ b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch @@ -213,7 +213,7 @@ index 18071dcc69cc28471dddb7de94e803ec1e5fc2e4..aa25f5ebaf7d1b22825b962b02dcae02 } } diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index ea40b39a90aacceedabf2637049968137d495132..7a3775185d5c80f43456a595f22a9ebf19760bd6 100644 +index 3b6d2cf670caefd42536de896d3e13c96ebf87b1..16635681a7ed6c6db8434fc14f9ac7c9243fd4a8 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -114,19 +114,8 @@ import net.minecraft.util.TimeUtil; @@ -401,7 +401,7 @@ index ea40b39a90aacceedabf2637049968137d495132..7a3775185d5c80f43456a595f22a9ebf this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing()); this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit // Paper start - optimise Folia entity scheduler -@@ -1716,9 +1672,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Purpur - Ridables @@ -429,7 +429,7 @@ index ea40b39a90aacceedabf2637049968137d495132..7a3775185d5c80f43456a595f22a9ebf try { serverLevel.tick(hasTimeLeft); } catch (Throwable var7) { -@@ -1773,34 +1722,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop Date: Mon, 7 Jul 2025 03:49:44 +0300 Subject: [PATCH 06/67] bunch of applies --- ...ow-throttling-hopper-checks-if-the-t.patch | 2 +- ...0046-Carpet-Fixes-Sheep-Optimization.patch | 2 +- ...MS-Addition-Optimized-dragon-respawn.patch | 7 + .../0048-ModernFix-compact_bit_storage.patch | 4 +- .../0049-Block-Log4Shell-exploit.patch | 6 +- ...50-Option-to-disable-disconnect.spam.patch | 12 +- ...able-saving-of-snowball-and-firework.patch | 4 +- .../0052-Snowball-and-Egg-knockback.patch | 2 +- .../features/0053-Optimize-suffocation.patch | 2 +- .../0054-Reduce-chunk-loading-lookups.patch | 0 ...igurable-movement-speed-for-entities.patch | 2 +- ...et-dirty-flag-when-loading-maps-from.patch | 25 +++ .../minecraft/0015-Optimize-explosions.patch | 192 ------------------ 13 files changed, 50 insertions(+), 210 deletions(-) rename patches/work/server/minecraft/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch => divinemc-server/minecraft-patches/features/0045-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch (94%) rename patches/work/server/minecraft/0043-Carpet-Fixes-Sheep-Optimization.patch => divinemc-server/minecraft-patches/features/0046-Carpet-Fixes-Sheep-Optimization.patch (98%) rename patches/work/server/minecraft/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch => divinemc-server/minecraft-patches/features/0047-Carpet-AMS-Addition-Optimized-dragon-respawn.patch (92%) rename patches/work/server/minecraft/0030-ModernFix-compact_bit_storage.patch => divinemc-server/minecraft-patches/features/0048-ModernFix-compact_bit_storage.patch (93%) rename patches/work/server/minecraft/0018-Block-Log4Shell-exploit.patch => divinemc-server/minecraft-patches/features/0049-Block-Log4Shell-exploit.patch (88%) rename patches/work/server/minecraft/0026-Option-to-disable-disconnect.spam.patch => divinemc-server/minecraft-patches/features/0050-Option-to-disable-disconnect.spam.patch (91%) rename patches/work/server/minecraft/0022-Option-to-disable-saving-of-snowball-and-firework.patch => divinemc-server/minecraft-patches/features/0051-Option-to-disable-saving-of-snowball-and-firework.patch (91%) rename patches/work/server/minecraft/0017-Snowball-and-Egg-knockback.patch => divinemc-server/minecraft-patches/features/0052-Snowball-and-Egg-knockback.patch (96%) rename patches/work/server/minecraft/0050-Optimize-suffocation.patch => divinemc-server/minecraft-patches/features/0053-Optimize-suffocation.patch (95%) rename patches/work/server/minecraft/0051-Reduce-chunk-loading-lookups.patch => divinemc-server/minecraft-patches/features/0054-Reduce-chunk-loading-lookups.patch (100%) rename patches/work/server/minecraft/0035-Configurable-movement-speed-for-entities.patch => divinemc-server/minecraft-patches/features/0055-Configurable-movement-speed-for-entities.patch (98%) create mode 100644 divinemc-server/minecraft-patches/features/0056-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch delete mode 100644 patches/work/server/minecraft/0015-Optimize-explosions.patch diff --git a/patches/work/server/minecraft/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch b/divinemc-server/minecraft-patches/features/0045-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch similarity index 94% rename from patches/work/server/minecraft/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch rename to divinemc-server/minecraft-patches/features/0045-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch index ab5afea..a98f5f5 100644 --- a/patches/work/server/minecraft/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch +++ b/divinemc-server/minecraft-patches/features/0045-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch @@ -7,7 +7,7 @@ Subject: [PATCH] SparklyPaper: Allow throttling hopper checks if the target Original project: https://github.com/SparklyPower/SparklyPaper diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index 15d4f60942c0cc612c1468b4c0fda886867a67cb..f0d53f83f7d3b4d8aa7d21bd7e3627a7052535aa 100644 +index 800b7e78ae989868ed0b9e060c80dcd002759412..3c9843979baff7ed419d4ae2124d7ccf47b95b5b 100644 --- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java +++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java @@ -423,6 +423,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen diff --git a/patches/work/server/minecraft/0043-Carpet-Fixes-Sheep-Optimization.patch b/divinemc-server/minecraft-patches/features/0046-Carpet-Fixes-Sheep-Optimization.patch similarity index 98% rename from patches/work/server/minecraft/0043-Carpet-Fixes-Sheep-Optimization.patch rename to divinemc-server/minecraft-patches/features/0046-Carpet-Fixes-Sheep-Optimization.patch index 1cc505c..89d49de 100644 --- a/patches/work/server/minecraft/0043-Carpet-Fixes-Sheep-Optimization.patch +++ b/divinemc-server/minecraft-patches/features/0046-Carpet-Fixes-Sheep-Optimization.patch @@ -19,7 +19,7 @@ we used a prebaked list of all the possible colors and combinations, however thi datapack to change it. diff --git a/net/minecraft/world/item/DyeColor.java b/net/minecraft/world/item/DyeColor.java -index 6bac07817d2916c64f703586599a2cab226872e6..d8ad2d56d4f0d6e5a58ec0359cecdde384db93e8 100644 +index c9cde255117b46690b2b6670d009a00b051af016..2c9f513e6ccd75959484f29a375671e21aab9590 100644 --- a/net/minecraft/world/item/DyeColor.java +++ b/net/minecraft/world/item/DyeColor.java @@ -112,6 +112,15 @@ public enum DyeColor implements StringRepresentable { diff --git a/patches/work/server/minecraft/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch b/divinemc-server/minecraft-patches/features/0047-Carpet-AMS-Addition-Optimized-dragon-respawn.patch similarity index 92% rename from patches/work/server/minecraft/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch rename to divinemc-server/minecraft-patches/features/0047-Carpet-AMS-Addition-Optimized-dragon-respawn.patch index 4d360ca..e9188d5 100644 --- a/patches/work/server/minecraft/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch +++ b/divinemc-server/minecraft-patches/features/0047-Carpet-AMS-Addition-Optimized-dragon-respawn.patch @@ -3,6 +3,13 @@ From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 11 Jun 2025 19:33:13 +0300 Subject: [PATCH] Carpet-AMS-Addition: Optimized dragon respawn +This patch is based on the following mixins and classes: +* "club/mcams/carpet/mixin/rule/optimizedDragonRespawn/BlockPatternMixin.java" +* "club/mcams/carpet/mixin/rule/optimizedDragonRespawn/EnderDragonFightMixin.java" +* "club/mcams/carpet/helpers/rule/optimizedDragonRespawn/BlockPatternHelper.java" +By: 1024-byteeeee +As part of: Carpet-AMS-Addition (https://github.com/Minecraft-AMS/Carpet-AMS-Addition) +Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html) diff --git a/net/minecraft/world/level/block/state/pattern/BlockPattern.java b/net/minecraft/world/level/block/state/pattern/BlockPattern.java index f7bb979f08634a7e1b77c59040f59fb5e11aafa5..e0eca73d9e8a77b2a4972db61001394c6bf1d2c4 100644 diff --git a/patches/work/server/minecraft/0030-ModernFix-compact_bit_storage.patch b/divinemc-server/minecraft-patches/features/0048-ModernFix-compact_bit_storage.patch similarity index 93% rename from patches/work/server/minecraft/0030-ModernFix-compact_bit_storage.patch rename to divinemc-server/minecraft-patches/features/0048-ModernFix-compact_bit_storage.patch index 690edd7..eb9ec79 100644 --- a/patches/work/server/minecraft/0030-ModernFix-compact_bit_storage.patch +++ b/divinemc-server/minecraft-patches/features/0048-ModernFix-compact_bit_storage.patch @@ -10,10 +10,10 @@ As part of: ModernFix (https://github.com/embeddedt/ModernFix) Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java -index ce41cd702a61d96552567b310cf59b22d9363eeb..4c02444001ce772cad0f9eb28ce147cd3cc08b8d 100644 +index be11a87ab1badca64219d74bc7a4f5d51b818a8c..a87689919a5fd4774eaff534ca85243feb505e84 100644 --- a/net/minecraft/world/level/chunk/PalettedContainer.java +++ b/net/minecraft/world/level/chunk/PalettedContainer.java -@@ -274,6 +274,28 @@ public class PalettedContainer implements PaletteResize, PalettedContainer +@@ -291,6 +291,28 @@ public class PalettedContainer implements PaletteResize, PalettedContainer data.palette.read(buffer); buffer.readFixedSizeLongArray(data.storage.getRaw()); this.data = data; diff --git a/patches/work/server/minecraft/0018-Block-Log4Shell-exploit.patch b/divinemc-server/minecraft-patches/features/0049-Block-Log4Shell-exploit.patch similarity index 88% rename from patches/work/server/minecraft/0018-Block-Log4Shell-exploit.patch rename to divinemc-server/minecraft-patches/features/0049-Block-Log4Shell-exploit.patch index b8a518f..439bf2c 100644 --- a/patches/work/server/minecraft/0018-Block-Log4Shell-exploit.patch +++ b/divinemc-server/minecraft-patches/features/0049-Block-Log4Shell-exploit.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Block Log4Shell exploit diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index b0bd45b8f53d4b9617680d7fb92d324c3713d960..89eddabc1a01f78b6945f1b8b8d32cede7e3cd9d 100644 +index a8b2c19cc9803058b421b07c739166afdf291e47..3a27b544da8227511b546c55963e7112df0a9f63 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2525,6 +2525,7 @@ public class ServerGamePacketListenerImpl +@@ -2515,6 +2515,7 @@ public class ServerGamePacketListenerImpl } private void tryHandleChat(String message, Runnable handler, boolean sync) { // CraftBukkit @@ -16,7 +16,7 @@ index b0bd45b8f53d4b9617680d7fb92d324c3713d960..89eddabc1a01f78b6945f1b8b8d32ced if (isChatMessageIllegal(message)) { this.disconnectAsync(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - add proper async disconnect } else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales -@@ -2557,6 +2558,15 @@ public class ServerGamePacketListenerImpl +@@ -2547,6 +2548,15 @@ public class ServerGamePacketListenerImpl } } diff --git a/patches/work/server/minecraft/0026-Option-to-disable-disconnect.spam.patch b/divinemc-server/minecraft-patches/features/0050-Option-to-disable-disconnect.spam.patch similarity index 91% rename from patches/work/server/minecraft/0026-Option-to-disable-disconnect.spam.patch rename to divinemc-server/minecraft-patches/features/0050-Option-to-disable-disconnect.spam.patch index 43a3cb7..1982ee1 100644 --- a/patches/work/server/minecraft/0026-Option-to-disable-disconnect.spam.patch +++ b/divinemc-server/minecraft-patches/features/0050-Option-to-disable-disconnect.spam.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Option to disable disconnect.spam diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 83aa3dc2f8d54e9fc89d809495c9b51f81d4f8e4..eef35b07324f33d7528cd8dc9ffc63c2815e5881 100644 +index 3a27b544da8227511b546c55963e7112df0a9f63..d5ed595bce6846590230634f8887e1f8e9b0a062 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -853,7 +853,7 @@ public class ServerGamePacketListenerImpl +@@ -844,7 +844,7 @@ public class ServerGamePacketListenerImpl public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) { // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); // Paper - AsyncTabCompleteEvent; run this async // CraftBukkit start @@ -17,7 +17,7 @@ index 83aa3dc2f8d54e9fc89d809495c9b51f81d4f8e4..eef35b07324f33d7528cd8dc9ffc63c2 this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause // Paper - add proper async disconnect return; } -@@ -865,7 +865,7 @@ public class ServerGamePacketListenerImpl +@@ -856,7 +856,7 @@ public class ServerGamePacketListenerImpl // Paper end - Don't suggest if tab-complete is disabled // Paper start final int index; @@ -26,7 +26,7 @@ index 83aa3dc2f8d54e9fc89d809495c9b51f81d4f8e4..eef35b07324f33d7528cd8dc9ffc63c2 this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - add proper async disconnect return; } -@@ -925,6 +925,7 @@ public class ServerGamePacketListenerImpl +@@ -916,6 +916,7 @@ public class ServerGamePacketListenerImpl ParseResults parseResults = this.server.getCommands().getDispatcher().parse(stringReader, this.player.createCommandSourceStack()); // Paper start - Handle non-recoverable exceptions if (!parseResults.getExceptions().isEmpty() @@ -34,7 +34,7 @@ index 83aa3dc2f8d54e9fc89d809495c9b51f81d4f8e4..eef35b07324f33d7528cd8dc9ffc63c2 && parseResults.getExceptions().values().stream().anyMatch(e -> e instanceof io.papermc.paper.brigadier.TagParseCommandSyntaxException)) { this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); return; -@@ -2652,6 +2653,7 @@ public class ServerGamePacketListenerImpl +@@ -2639,6 +2640,7 @@ public class ServerGamePacketListenerImpl // this.chatSpamThrottler.increment(); if (!this.chatSpamThrottler.isIncrementAndUnderThreshold() // CraftBukkit end @@ -42,7 +42,7 @@ index 83aa3dc2f8d54e9fc89d809495c9b51f81d4f8e4..eef35b07324f33d7528cd8dc9ffc63c2 && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause & add proper async disconnect -@@ -3409,7 +3411,7 @@ public class ServerGamePacketListenerImpl +@@ -3396,7 +3398,7 @@ public class ServerGamePacketListenerImpl public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { // Paper start - auto recipe limit if (!org.bukkit.Bukkit.isPrimaryThread()) { diff --git a/patches/work/server/minecraft/0022-Option-to-disable-saving-of-snowball-and-firework.patch b/divinemc-server/minecraft-patches/features/0051-Option-to-disable-saving-of-snowball-and-firework.patch similarity index 91% rename from patches/work/server/minecraft/0022-Option-to-disable-saving-of-snowball-and-firework.patch rename to divinemc-server/minecraft-patches/features/0051-Option-to-disable-saving-of-snowball-and-firework.patch index 01c4c74..25a6e5c 100644 --- a/patches/work/server/minecraft/0022-Option-to-disable-saving-of-snowball-and-firework.patch +++ b/divinemc-server/minecraft-patches/features/0051-Option-to-disable-saving-of-snowball-and-firework.patch @@ -24,10 +24,10 @@ index d8dc196ef92e97f831cf97cd1536a46f81f9d5d1..ed8c50f67f5a6deda74845e4bce9fd9a + // DivineMC end - Option to disable saving firework } diff --git a/net/minecraft/world/entity/projectile/Snowball.java b/net/minecraft/world/entity/projectile/Snowball.java -index 86e75722b37eaa02858fa4313d8bcc2a72c0f7f6..0f611169a4ed2a059b9231bedf94a903600b73f0 100644 +index d8f9fb603fd2e3e5c1dfc05face7f42b4844daf4..42b2be469972e02671fa5a02aeecfb4e5be405c3 100644 --- a/net/minecraft/world/entity/projectile/Snowball.java +++ b/net/minecraft/world/entity/projectile/Snowball.java -@@ -100,4 +100,14 @@ public class Snowball extends ThrowableItemProjectile { +@@ -94,4 +94,14 @@ public class Snowball extends ThrowableItemProjectile { this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } } diff --git a/patches/work/server/minecraft/0017-Snowball-and-Egg-knockback.patch b/divinemc-server/minecraft-patches/features/0052-Snowball-and-Egg-knockback.patch similarity index 96% rename from patches/work/server/minecraft/0017-Snowball-and-Egg-knockback.patch rename to divinemc-server/minecraft-patches/features/0052-Snowball-and-Egg-knockback.patch index 0606edb..9c2869c 100644 --- a/patches/work/server/minecraft/0017-Snowball-and-Egg-knockback.patch +++ b/divinemc-server/minecraft-patches/features/0052-Snowball-and-Egg-knockback.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Snowball and Egg knockback diff --git a/net/minecraft/world/entity/projectile/Snowball.java b/net/minecraft/world/entity/projectile/Snowball.java -index d8f9fb603fd2e3e5c1dfc05face7f42b4844daf4..86e75722b37eaa02858fa4313d8bcc2a72c0f7f6 100644 +index 42b2be469972e02671fa5a02aeecfb4e5be405c3..0f611169a4ed2a059b9231bedf94a903600b73f0 100644 --- a/net/minecraft/world/entity/projectile/Snowball.java +++ b/net/minecraft/world/entity/projectile/Snowball.java @@ -54,6 +54,12 @@ public class Snowball extends ThrowableItemProjectile { diff --git a/patches/work/server/minecraft/0050-Optimize-suffocation.patch b/divinemc-server/minecraft-patches/features/0053-Optimize-suffocation.patch similarity index 95% rename from patches/work/server/minecraft/0050-Optimize-suffocation.patch rename to divinemc-server/minecraft-patches/features/0053-Optimize-suffocation.patch index 5d1232a..13dfed4 100644 --- a/patches/work/server/minecraft/0050-Optimize-suffocation.patch +++ b/divinemc-server/minecraft-patches/features/0053-Optimize-suffocation.patch @@ -7,7 +7,7 @@ Original license: GPL v3 Original project: https://github.com/pufferfish-gg/Pufferfish diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index 16a3cd813997456ca67a382a8277eca02dc6662f..3cf377f87e8b7f672ea247728365eb61f47bc3ac 100644 +index d382a9760c0379f3d1c3bc65303d1de250858343..49cb64c6dd0941eab8f7531e0c182a79e4ec1da6 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java @@ -420,6 +420,12 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin diff --git a/patches/work/server/minecraft/0051-Reduce-chunk-loading-lookups.patch b/divinemc-server/minecraft-patches/features/0054-Reduce-chunk-loading-lookups.patch similarity index 100% rename from patches/work/server/minecraft/0051-Reduce-chunk-loading-lookups.patch rename to divinemc-server/minecraft-patches/features/0054-Reduce-chunk-loading-lookups.patch diff --git a/patches/work/server/minecraft/0035-Configurable-movement-speed-for-entities.patch b/divinemc-server/minecraft-patches/features/0055-Configurable-movement-speed-for-entities.patch similarity index 98% rename from patches/work/server/minecraft/0035-Configurable-movement-speed-for-entities.patch rename to divinemc-server/minecraft-patches/features/0055-Configurable-movement-speed-for-entities.patch index d05e2f6..07c5710 100644 --- a/patches/work/server/minecraft/0035-Configurable-movement-speed-for-entities.patch +++ b/divinemc-server/minecraft-patches/features/0055-Configurable-movement-speed-for-entities.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Configurable movement speed for entities diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java -index edcb20935f58e78fa4ef2c11a7dcc6a7857341c2..d4e7fc0a5bda4f44bcfed3d1adae7cdaf815784b 100644 +index 2e6d0f035a01277aa28bbe912d5df8dc4cf04547..2a13332ebabf2e63a8f51a5d794fab3d66c7a1db 100644 --- a/net/minecraft/world/entity/monster/Drowned.java +++ b/net/minecraft/world/entity/monster/Drowned.java @@ -98,6 +98,7 @@ public class Drowned extends Zombie implements RangedAttackMob { diff --git a/divinemc-server/minecraft-patches/features/0056-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch b/divinemc-server/minecraft-patches/features/0056-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch new file mode 100644 index 0000000..7b40fd4 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0056-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 7 Jul 2025 03:44:35 +0300 +Subject: [PATCH] SparklyPaper: Reset dirty flag when loading maps from the + disk + +Original project: https://github.com/SparklyPower/SparklyPaper + +Patch description: + +By default, the server will start rewriting all map datas to the disk after loading it, even if the map didn't have any changes +This also slows down world saving a lot if you have a lot of maps + +diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +index 7bbeed6c998c91e68376d3f17a510d68e3cd0b27..ebb0b7e5047efa65e8b6986f12dd5a7d6c0e9613 100644 +--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java ++++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +@@ -160,6 +160,7 @@ public class MapItemSavedData extends SavedData { + } + + this.vanillaRender.buffer = colors.array(); // Paper - Use Vanilla map renderer when possible ++ this.setDirty(false); // DivineMC - SparklyPaper: Reset dirty flag when loading maps from the disk + } + + public static MapItemSavedData createFresh( diff --git a/patches/work/server/minecraft/0015-Optimize-explosions.patch b/patches/work/server/minecraft/0015-Optimize-explosions.patch deleted file mode 100644 index 42c3906..0000000 --- a/patches/work/server/minecraft/0015-Optimize-explosions.patch +++ /dev/null @@ -1,192 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 1 Feb 2025 16:57:01 +0300 -Subject: [PATCH] Optimize explosions - - -diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index d0c4d63320fb5f58c43b38ebc333e9a7be487a5d..24648c6447774ac6aa8f76b078d923fface15c3f 100644 ---- a/net/minecraft/world/level/ServerExplosion.java -+++ b/net/minecraft/world/level/ServerExplosion.java -@@ -375,6 +375,11 @@ public class ServerExplosion implements Explosion { - } - - private List calculateExplodedPositions() { -+ // DivineMC start - Optimize explosions -+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableFasterTntOptimization && !level.isClientSide && !(getIndirectSourceEntity() instanceof net.minecraft.world.entity.monster.breeze.Breeze)) { -+ return doExplosionA(this); -+ } -+ // DivineMC end - Optimize explosions - // Paper start - collision optimisations - final ObjectArrayList ret = new ObjectArrayList<>(); - -@@ -473,6 +478,157 @@ public class ServerExplosion implements Explosion { - // Paper end - collision optimisations - } - -+ // DivineMC start - Optimize explosions -+ private static final it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap> densityCache = new it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap<>(); -+ private static final it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap stateCache = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); -+ private static final it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap fluidCache = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); -+ private static final BlockPos.MutableBlockPos posMutable = new BlockPos.MutableBlockPos(0, 0, 0); -+ private static final it.unimi.dsi.fastutil.objects.ObjectOpenHashSet affectedBlockPositionsSet = new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(); -+ private static boolean firstRay; -+ private static boolean rayCalcDone; -+ -+ public static @org.jetbrains.annotations.NotNull List doExplosionA(ServerExplosion e) { -+ List toBlow; -+ -+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.explosionNoBlockDamage && e.damageSource != null) { -+ rayCalcDone = false; -+ firstRay = true; -+ getAffectedPositionsOnPlaneY(e, 0, 0, 15, 0, 15); // bottom -+ getAffectedPositionsOnPlaneY(e, 15, 0, 15, 0, 15); // top -+ getAffectedPositionsOnPlaneX(e, 0, 1, 14, 0, 15); // west -+ getAffectedPositionsOnPlaneX(e, 15, 1, 14, 0, 15); // east -+ getAffectedPositionsOnPlaneZ(e, 0, 1, 14, 1, 14); // north -+ getAffectedPositionsOnPlaneZ(e, 15, 1, 14, 1, 14); // south -+ stateCache.clear(); -+ fluidCache.clear(); -+ -+ toBlow = new ArrayList<>(affectedBlockPositionsSet); -+ affectedBlockPositionsSet.clear(); -+ } else { -+ toBlow = java.util.Collections.emptyList(); -+ } -+ densityCache.clear(); -+ -+ return toBlow; -+ } -+ -+ private static void getAffectedPositionsOnPlaneX(Explosion e, int x, int yStart, int yEnd, int zStart, int zEnd) { -+ if (!rayCalcDone) { -+ final double xRel = (double) x / 15.0D * 2.0D - 1.0D; -+ -+ for (int z = zStart; z <= zEnd; ++z) { -+ double zRel = (double) z / 15.0D * 2.0D - 1.0D; -+ -+ for (int y = yStart; y <= yEnd; ++y) { -+ double yRel = (double) y / 15.0D * 2.0D - 1.0D; -+ -+ if (checkAffectedPosition((ServerExplosion) e, xRel, yRel, zRel)) { -+ return; -+ } -+ } -+ } -+ } -+ } -+ -+ private static void getAffectedPositionsOnPlaneY(Explosion e, int y, int xStart, int xEnd, int zStart, int zEnd) { -+ if (!rayCalcDone) { -+ final double yRel = (double) y / 15.0D * 2.0D - 1.0D; -+ -+ for (int z = zStart; z <= zEnd; ++z) { -+ double zRel = (double) z / 15.0D * 2.0D - 1.0D; -+ -+ for (int x = xStart; x <= xEnd; ++x) { -+ double xRel = (double) x / 15.0D * 2.0D - 1.0D; -+ -+ if (checkAffectedPosition((ServerExplosion) e, xRel, yRel, zRel)) { -+ return; -+ } -+ } -+ } -+ } -+ } -+ -+ private static void getAffectedPositionsOnPlaneZ(Explosion e, int z, int xStart, int xEnd, int yStart, int yEnd) { -+ if (!rayCalcDone) { -+ final double zRel = (double) z / 15.0D * 2.0D - 1.0D; -+ -+ for (int x = xStart; x <= xEnd; ++x) { -+ double xRel = (double) x / 15.0D * 2.0D - 1.0D; -+ -+ for (int y = yStart; y <= yEnd; ++y) { -+ double yRel = (double) y / 15.0D * 2.0D - 1.0D; -+ -+ if (checkAffectedPosition((ServerExplosion) e, xRel, yRel, zRel)) { -+ return; -+ } -+ } -+ } -+ } -+ } -+ -+ private static boolean checkAffectedPosition(ServerExplosion e, double xRel, double yRel, double zRel) { -+ double len = Math.sqrt(xRel * xRel + yRel * yRel + zRel * zRel); -+ double xInc = (xRel / len) * 0.3; -+ double yInc = (yRel / len) * 0.3; -+ double zInc = (zRel / len) * 0.3; -+ float rand = e.level().random.nextFloat(); -+ float sizeRand = (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.tntRandomRange >= 0 ? (float) org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.tntRandomRange : rand); -+ float size = e.radius() * (0.7F + sizeRand * 0.6F); -+ Vec3 vec3 = e.center(); -+ double posX = vec3.x; -+ double posY = vec3.y; -+ double posZ = vec3.z; -+ -+ for (float f1 = 0.3F; size > 0.0F; size -= 0.22500001F) { -+ posMutable.set(posX, posY, posZ); -+ -+ // Don't query already cached positions again from the world -+ BlockState state = stateCache.get(posMutable); -+ FluidState fluid = fluidCache.get(posMutable); -+ BlockPos posImmutable = null; -+ -+ if (state == null) { -+ posImmutable = posMutable.immutable(); -+ state = e.level().getBlockState(posImmutable); -+ stateCache.put(posImmutable, state); -+ fluid = e.level().getFluidState(posImmutable); -+ fluidCache.put(posImmutable, fluid); -+ } -+ -+ if (!state.isAir()) { -+ float resistance = Math.max(state.getBlock().getExplosionResistance(), fluid.getExplosionResistance()); -+ -+ if (e.source != null) { -+ resistance = e.source.getBlockExplosionResistance(e, e.level(), posMutable, state, fluid, resistance); -+ } -+ -+ size -= (resistance + 0.3F) * 0.3F; -+ } -+ -+ if (size > 0.0F) { -+ if ((e.source == null || e.source.shouldBlockExplode(e, e.level(), posMutable, state, size))) -+ affectedBlockPositionsSet.add(posImmutable != null ? posImmutable : posMutable.immutable()); -+ } else if (firstRay) { -+ rayCalcDone = true; -+ return true; -+ } -+ -+ firstRay = false; -+ -+ posX += xInc; -+ posY += yInc; -+ posZ += zInc; -+ } -+ -+ return false; -+ } -+ -+ private Optional noBlockCalcsWithNoBLockDamage(final ExplosionDamageCalculator instance, final Explosion explosion, final BlockGetter blockGetter, final BlockPos blockPos, final BlockState blockState, final FluidState fluidState) { -+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.explosionNoBlockDamage) return Optional.of(net.minecraft.world.level.block.Blocks.BEDROCK.getExplosionResistance()); -+ return instance.getBlockExplosionResistance(explosion, blockGetter, blockPos, blockState, fluidState); -+ } -+ // DivineMC end - Optimize explosions -+ - private void hurtEntities() { - float f = this.radius * 2.0F; - int floor = Mth.floor(this.center.x - f - 1.0); -@@ -562,6 +718,11 @@ public class ServerExplosion implements Explosion { - } - - private void interactWithBlocks(List blocks) { -+ // DivineMC start - Optimize explosions -+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.explosionNoBlockDamage) { -+ blocks.clear(); -+ } -+ // DivineMC end - Optimize explosions - List list = new ArrayList<>(); - Util.shuffle(blocks, this.level.random); - From 41f2b1c6a3fa143ce5d4b6b0ac61672e0b46fb14 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Mon, 7 Jul 2025 04:01:50 +0300 Subject: [PATCH 07/67] final mini applies for minecraft --- ...-BlockEntity-ticking-isRemoved-check.patch | 9 ++++-- ...weird-movement-and-disable-teleporti.patch | 6 ++-- .../features/0059-Optimize-Raids.patch | 10 +++---- ...-SparklyPaper-Optimize-canSee-checks.patch | 28 +++++++++++++++++++ ...-SparklyPaper-Optimize-canSee-checks.patch | 25 +++++++++++------ .../0020-Optimize-canSee-checks.patch | 19 ------------- 6 files changed, 59 insertions(+), 38 deletions(-) rename patches/work/server/minecraft/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch => divinemc-server/minecraft-patches/features/0057-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch (84%) rename patches/work/server/minecraft/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch => divinemc-server/minecraft-patches/features/0058-Option-to-allow-weird-movement-and-disable-teleporti.patch (96%) rename patches/work/server/minecraft/0047-Optimize-Raids.patch => divinemc-server/minecraft-patches/features/0059-Optimize-Raids.patch (92%) create mode 100644 divinemc-server/minecraft-patches/features/0060-SparklyPaper-Optimize-canSee-checks.patch rename patches/work/server/paper/0007-Optimize-canSee-checks.patch => divinemc-server/paper-patches/features/0011-SparklyPaper-Optimize-canSee-checks.patch (59%) delete mode 100644 patches/work/server/minecraft/0020-Optimize-canSee-checks.patch diff --git a/patches/work/server/minecraft/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch b/divinemc-server/minecraft-patches/features/0057-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch similarity index 84% rename from patches/work/server/minecraft/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch rename to divinemc-server/minecraft-patches/features/0057-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch index 442f4fa..236f9a5 100644 --- a/patches/work/server/minecraft/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch +++ b/divinemc-server/minecraft-patches/features/0057-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch @@ -3,12 +3,15 @@ From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 26 Mar 2025 01:46:49 +0300 Subject: [PATCH] Leaf: Improve BlockEntity ticking isRemoved check +Original project: https://github.com/Winds-Studio/Leaf + +This should help for massive hopper chains or hopper matrix. diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index df086a2580ee41f88a00fb78b50b87f22539b833..868881e2b8567d1a03eee4f4a9f611bbc36c66d0 100644 +index 6d9274f0da9507d0152611d6b7785e0524dedb2d..a2b21970841a0f7f2b4b469c7b8737440041ebaa 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -999,13 +999,26 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -982,13 +982,26 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p public static class RebindableTickingBlockEntityWrapper implements TickingBlockEntity { public TickingBlockEntity ticker; @@ -35,7 +38,7 @@ index df086a2580ee41f88a00fb78b50b87f22539b833..868881e2b8567d1a03eee4f4a9f611bb } @Override -@@ -1015,6 +1028,12 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -998,6 +1011,12 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @Override public boolean isRemoved() { diff --git a/patches/work/server/minecraft/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch b/divinemc-server/minecraft-patches/features/0058-Option-to-allow-weird-movement-and-disable-teleporti.patch similarity index 96% rename from patches/work/server/minecraft/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch rename to divinemc-server/minecraft-patches/features/0058-Option-to-allow-weird-movement-and-disable-teleporti.patch index d0a5ce6..3d91505 100644 --- a/patches/work/server/minecraft/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch +++ b/divinemc-server/minecraft-patches/features/0058-Option-to-allow-weird-movement-and-disable-teleporti.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Option to allow weird movement and disable teleporting diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 649b01c00ec01eea1514676e424d88acbfa26184..b0bd45b8f53d4b9617680d7fb92d324c3713d960 100644 +index d5ed595bce6846590230634f8887e1f8e9b0a062..798482a332c4be045d5c409a20cd120c12b3460e 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -607,7 +607,7 @@ public class ServerGamePacketListenerImpl @@ -27,7 +27,7 @@ index 649b01c00ec01eea1514676e424d88acbfa26184..b0bd45b8f53d4b9617680d7fb92d324c flag1 = true; // Paper - diff on change, this should be moved wrongly LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7)); } -@@ -1560,20 +1560,24 @@ public class ServerGamePacketListenerImpl +@@ -1555,20 +1555,24 @@ public class ServerGamePacketListenerImpl if (this.shouldCheckPlayerMovement(isFallFlying)) { float f2 = isFallFlying ? 300.0F : 100.0F; if (d7 - d6 > Math.max(f2, Mth.square(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed))) { @@ -63,7 +63,7 @@ index 649b01c00ec01eea1514676e424d88acbfa26184..b0bd45b8f53d4b9617680d7fb92d324c } } } -@@ -1634,6 +1638,7 @@ public class ServerGamePacketListenerImpl +@@ -1629,6 +1633,7 @@ public class ServerGamePacketListenerImpl d7 = d3 * d3 + d4 * d4 + d5 * d5; boolean movedWrongly = false; // Paper - Add fail move event; rename if (!this.player.isChangingDimension() diff --git a/patches/work/server/minecraft/0047-Optimize-Raids.patch b/divinemc-server/minecraft-patches/features/0059-Optimize-Raids.patch similarity index 92% rename from patches/work/server/minecraft/0047-Optimize-Raids.patch rename to divinemc-server/minecraft-patches/features/0059-Optimize-Raids.patch index 88c3277..6880e0a 100644 --- a/patches/work/server/minecraft/0047-Optimize-Raids.patch +++ b/divinemc-server/minecraft-patches/features/0059-Optimize-Raids.patch @@ -5,20 +5,20 @@ Subject: [PATCH] Optimize Raids diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index adac2dd1530c21c610f6dced12a80ab726fe3a98..d39d15dcb6964aed0bf9c2f64952d229d64cff62 100644 +index 5f2c27800f047f128857044493a6d9325ffd759b..4a2cace22512fe06c1713bc8735e775e3012f3bc 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -218,6 +218,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -215,6 +215,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current) public boolean hasRidableMoveEvent = false; // Purpur - Ridables - public org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag Compensation + public net.minecraft.world.item.ItemStack ominousBanner; // DivineMC - Optimize Raids @Override public @Nullable LevelChunk getChunkIfLoaded(int x, int z) { -@@ -706,6 +707,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -694,6 +695,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // Paper end - rewrite chunk system this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit - this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new org.bxteam.divinemc.server.ServerLevelTickExecutorThreadFactory(getWorld().getName())); // DivineMC - Parallel world ticking this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle + this.ominousBanner = Objects.requireNonNullElse(this.registryAccess(), net.minecraft.core.RegistryAccess.EMPTY).lookup(Registries.BANNER_PATTERN).map(Raid::getOminousBannerInstance).orElse(null); // DivineMC - Optimize Raids } diff --git a/divinemc-server/minecraft-patches/features/0060-SparklyPaper-Optimize-canSee-checks.patch b/divinemc-server/minecraft-patches/features/0060-SparklyPaper-Optimize-canSee-checks.patch new file mode 100644 index 0000000..c0914ed --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0060-SparklyPaper-Optimize-canSee-checks.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sat, 1 Feb 2025 19:52:39 +0300 +Subject: [PATCH] SparklyPaper: Optimize "canSee" checks + +Original project: https://github.com/SparklyPower/SparklyPaper + +Patch description: + +The "canSee" checks is in a hot path, invoked by each entity for each player on the server if they are in tracking range, so optimizing it is pretty nice +First, we change the original "HashMap" to fastutil's "Object2ObjectOpenHashMap", because the containsKey throughput is better +Then, we add a "isEmpty()" check before attempting to check if the map contains something +This seems stupid, but it does seem that it improves the performance a bit, and it makes sense, "containsKey(...)" does not attempt to check the map size before attempting to check if the map contains the key +We also create a "canSee" method tailored for "ChunkMap#updatePlayer()", a method without the equals check (the "updatePlayer()" already checks if the entity is the same entity) because the CraftPlayer's `equals()` check is a *bit* expensive compared to only checking the object's identity, and because the identity has already been check, we don't need to check it twice. + +diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java +index edda52a8430386238be4963e8ea2406f0c2d4df3..c0d996fb99f053863ce623889add3feb70d7137d 100644 +--- a/net/minecraft/server/level/ChunkMap.java ++++ b/net/minecraft/server/level/ChunkMap.java +@@ -1295,7 +1295,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); + // Paper end - Configurable entity tracking range by Y + // CraftBukkit start - respect vanish API +- if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits ++ if (flag && !player.getBukkitEntity().canSeeChunkMapUpdatePlayer(this.entity.getBukkitEntity())) { // Paper - only consider hits // DivineMC - SparklyPaper: Optimize "canSee" checks + flag = false; + } + // CraftBukkit end diff --git a/patches/work/server/paper/0007-Optimize-canSee-checks.patch b/divinemc-server/paper-patches/features/0011-SparklyPaper-Optimize-canSee-checks.patch similarity index 59% rename from patches/work/server/paper/0007-Optimize-canSee-checks.patch rename to divinemc-server/paper-patches/features/0011-SparklyPaper-Optimize-canSee-checks.patch index d936f22..ddac190 100644 --- a/patches/work/server/paper/0007-Optimize-canSee-checks.patch +++ b/divinemc-server/paper-patches/features/0011-SparklyPaper-Optimize-canSee-checks.patch @@ -1,11 +1,20 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 1 Feb 2025 19:52:39 +0300 -Subject: [PATCH] Optimize canSee checks +Subject: [PATCH] SparklyPaper: Optimize "canSee" checks +Original project: https://github.com/SparklyPower/SparklyPaper + +Patch description: + +The "canSee" checks is in a hot path, invoked by each entity for each player on the server if they are in tracking range, so optimizing it is pretty nice +First, we change the original "HashMap" to fastutil's "Object2ObjectOpenHashMap", because the containsKey throughput is better +Then, we add a "isEmpty()" check before attempting to check if the map contains something +This seems stupid, but it does seem that it improves the performance a bit, and it makes sense, "containsKey(...)" does not attempt to check the map size before attempting to check if the map contains the key +We also create a "canSee" method tailored for "ChunkMap#updatePlayer()", a method without the equals check (the "updatePlayer()" already checks if the entity is the same entity) because the CraftPlayer's `equals()` check is a *bit* expensive compared to only checking the object's identity, and because the identity has already been check, we don't need to check it twice. diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index ab454a7c53b074c8c60bab38c0544aa3b69d5c6d..acd3b4f8b3e9c40253bacb3d16017fb7102c071c 100644 +index c22d489e3584e0a938e2f8afd3e201987c92b8f2..4913ac7d0426025689c8aee3790d87f7ac0131fd 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -217,7 +217,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa @@ -13,23 +22,23 @@ index ab454a7c53b074c8c60bab38c0544aa3b69d5c6d..acd3b4f8b3e9c40253bacb3d16017fb7 private static final net.kyori.adventure.text.Component DEFAULT_KICK_COMPONENT = net.kyori.adventure.text.Component.translatable("multiplayer.disconnect.kicked"); private final ConversationTracker conversationTracker = new ConversationTracker(); - private final Map>> invertedVisibilityEntities = new HashMap<>(); -+ private final Map>> invertedVisibilityEntities = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); // DivineMC - optimize canSee checks ++ private final Map>> invertedVisibilityEntities = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); // DivineMC - SparklyPaper: Optimize "canSee" checks private final Set unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus; // Paper - more resource pack API private long firstPlayed = 0; -@@ -2343,9 +2343,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa +@@ -2354,9 +2354,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa @Override public boolean canSee(org.bukkit.entity.Entity entity) { - return this.equals(entity) || entity.isVisibleByDefault() ^ this.invertedVisibilityEntities.containsKey(entity.getUniqueId()); // SPIGOT-7312: Can always see self -+ return this.equals(entity) || entity.isVisibleByDefault() ^ (!invertedVisibilityEntities.isEmpty() && this.invertedVisibilityEntities.containsKey(entity.getUniqueId())); // SPIGOT-7312: Can always see self // DivineMC - optimize canSee checks ++ return this.equals(entity) || entity.isVisibleByDefault() ^ (!invertedVisibilityEntities.isEmpty() && this.invertedVisibilityEntities.containsKey(entity.getUniqueId())); // SPIGOT-7312: Can always see self // DivineMC - SparklyPaper: Optimize "canSee" checks } -+ // DivineMC start - optimize canSee checks ++ // DivineMC start - SparklyPaper: Optimize "canSee" checks + public boolean canSeeChunkMapUpdatePlayer(org.bukkit.entity.Entity entity) { -+ return entity.isVisibleByDefault() ^ (!invertedVisibilityEntities.isEmpty() && this.invertedVisibilityEntities.containsKey(entity.getUniqueId())); // SPIGOT-7312: Can always see self // SparklyPaper - optimize canSee checks ++ return entity.isVisibleByDefault() ^ (!invertedVisibilityEntities.isEmpty() && this.invertedVisibilityEntities.containsKey(entity.getUniqueId())); + } -+ // DivineMC end - optimize canSee checks ++ // DivineMC end - SparklyPaper: Optimize "canSee" checks + public boolean canSeePlayer(UUID uuid) { org.bukkit.entity.Entity entity = this.getServer().getPlayer(uuid); diff --git a/patches/work/server/minecraft/0020-Optimize-canSee-checks.patch b/patches/work/server/minecraft/0020-Optimize-canSee-checks.patch deleted file mode 100644 index b3b3c90..0000000 --- a/patches/work/server/minecraft/0020-Optimize-canSee-checks.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 1 Feb 2025 19:52:39 +0300 -Subject: [PATCH] Optimize canSee checks - - -diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index 7ebaf03342e8802948b4f412c3f7120927f7b3b3..c47b38a9ef01c9f9d58d64b2662d1b0e51353c0d 100644 ---- a/net/minecraft/server/level/ChunkMap.java -+++ b/net/minecraft/server/level/ChunkMap.java -@@ -1417,7 +1417,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); - // Paper end - Configurable entity tracking range by Y - // CraftBukkit start - respect vanish API -- if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits -+ if (flag && !player.getBukkitEntity().canSeeChunkMapUpdatePlayer(this.entity.getBukkitEntity())) { // Paper - only consider hits // DivineMC - optimize canSee checks - flag = false; - } - // CraftBukkit end From b533ad43f7d2498ef86ef959899e2aab997f959f Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Mon, 7 Jul 2025 04:09:16 +0300 Subject: [PATCH 08/67] switch from paper files to features --- .../features/0003-Delete-timings.patch | 6 +++--- .../0012-Skip-event-if-no-listeners.patch} | 15 ++++++++++--- .../0013-Force-Minecraft-command.patch} | 10 ++++++++- ...ver-getWorlds-ArrayList-with-a-fastu.patch | 21 +++++++++++++++++++ .../bukkit/craftbukkit/CraftServer.java.patch | 11 ---------- 5 files changed, 45 insertions(+), 18 deletions(-) rename divinemc-server/paper-patches/{files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch => features/0012-Skip-event-if-no-listeners.patch} (68%) rename divinemc-server/paper-patches/{files/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java.patch => features/0013-Force-Minecraft-command.patch} (61%) create mode 100644 divinemc-server/paper-patches/features/0014-Replace-CraftServer-getWorlds-ArrayList-with-a-fastu.patch delete mode 100644 divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch diff --git a/divinemc-server/paper-patches/features/0003-Delete-timings.patch b/divinemc-server/paper-patches/features/0003-Delete-timings.patch index 95875e7..986ad86 100644 --- a/divinemc-server/paper-patches/features/0003-Delete-timings.patch +++ b/divinemc-server/paper-patches/features/0003-Delete-timings.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Delete timings diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java -index e989053b703fddfbffc3e4ed9381594aaaa0df41..d7398b1ecf2660c29fb7d106b48fe02d3736603e 100644 +index 7ce9ebba8ce304d1f3f21d4f15ee5f3560d7700b..11e5b9ebafa562e5a93643d954839e86d0b731f0 100644 --- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java @@ -1,6 +1,5 @@ @@ -15,7 +15,7 @@ index e989053b703fddfbffc3e4ed9381594aaaa0df41..d7398b1ecf2660c29fb7d106b48fe02d import com.destroystokyo.paper.event.server.ServerExceptionEvent; import com.destroystokyo.paper.exception.ServerEventException; import com.google.common.collect.Sets; -@@ -96,7 +95,6 @@ class PaperEventManager { +@@ -95,7 +94,6 @@ class PaperEventManager { throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled"); } @@ -23,7 +23,7 @@ index e989053b703fddfbffc3e4ed9381594aaaa0df41..d7398b1ecf2660c29fb7d106b48fe02d this.getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled)); } -@@ -183,7 +181,7 @@ class PaperEventManager { +@@ -182,7 +180,7 @@ class PaperEventManager { } } diff --git a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch b/divinemc-server/paper-patches/features/0012-Skip-event-if-no-listeners.patch similarity index 68% rename from divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch rename to divinemc-server/paper-patches/features/0012-Skip-event-if-no-listeners.patch index 9138b72..6cf7bfc 100644 --- a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch +++ b/divinemc-server/paper-patches/features/0012-Skip-event-if-no-listeners.patch @@ -1,6 +1,14 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 7 Jul 2025 04:04:20 +0300 +Subject: [PATCH] Skip event if no listeners + + +diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +index 11e5b9ebafa562e5a93643d954839e86d0b731f0..d7398b1ecf2660c29fb7d106b48fe02d3736603e 100644 --- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java -@@ -36,14 +_,15 @@ +@@ -35,15 +35,16 @@ class PaperEventManager { // SimplePluginManager public void callEvent(@NotNull Event event) { @@ -13,9 +21,10 @@ } else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) { throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); } -- + - HandlerList handlers = event.getHandlers(); - RegisteredListener[] listeners = handlers.getRegisteredListeners(); - +- for (RegisteredListener registration : listeners) { if (!registration.getPlugin().isEnabled()) { + continue; diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java.patch b/divinemc-server/paper-patches/features/0013-Force-Minecraft-command.patch similarity index 61% rename from divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java.patch rename to divinemc-server/paper-patches/features/0013-Force-Minecraft-command.patch index b7b1a06..c3c3276 100644 --- a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java.patch +++ b/divinemc-server/paper-patches/features/0013-Force-Minecraft-command.patch @@ -1,6 +1,14 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 7 Jul 2025 04:05:08 +0300 +Subject: [PATCH] Force Minecraft command + + +diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java b/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java +index 90ed57a7fbcd0625b64084347460e9864216f610..138f37bf12f39152af97b14515007e9ca485967f 100644 --- a/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java +++ b/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java -@@ -14,4 +_,18 @@ +@@ -14,4 +14,18 @@ public class CraftCommandMap extends SimpleCommandMap { public Map getKnownCommands() { return this.knownCommands; } diff --git a/divinemc-server/paper-patches/features/0014-Replace-CraftServer-getWorlds-ArrayList-with-a-fastu.patch b/divinemc-server/paper-patches/features/0014-Replace-CraftServer-getWorlds-ArrayList-with-a-fastu.patch new file mode 100644 index 0000000..7038f60 --- /dev/null +++ b/divinemc-server/paper-patches/features/0014-Replace-CraftServer-getWorlds-ArrayList-with-a-fastu.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 7 Jul 2025 04:06:32 +0300 +Subject: [PATCH] Replace CraftServer#getWorlds ArrayList with a fastutil + ObjectArrayList + +CraftServer#getWorlds is frequently used in some plugins, so replacing ArrayList with fastutil ObjectArrayList will give some performance boost + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 17022a57cb06b0ddd0df94075c0d92b68137d901..414fdc6ca7a2979124a7fbf529bff60f993c005a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -974,7 +974,7 @@ public final class CraftServer implements Server { + + @Override + public List getWorlds() { +- return new ArrayList(this.worlds.values()); ++ return new it.unimi.dsi.fastutil.objects.ObjectArrayList(this.worlds.values()); // DivineMC - Replace CraftServer#getWorlds ArrayList with a fastutil ObjectArrayList + } + + @Override diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch deleted file mode 100644 index b52c47f..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -974,7 +_,7 @@ - - @Override - public List getWorlds() { -- return new ArrayList(this.worlds.values()); -+ return new it.unimi.dsi.fastutil.objects.ObjectArrayList(this.worlds.values()); // DivineMC - optimize getWorlds - } - - @Override From 54033bb593a7b68a38d47d5330bd02be48ec224b Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Mon, 7 Jul 2025 04:23:37 +0300 Subject: [PATCH 09/67] optimize LinearPalette; remove useless log4shell patch --- .../0049-Block-Log4Shell-exploit.patch | 34 ---------- ...9-Option-to-disable-disconnect.spam.patch} | 6 +- ...ble-saving-of-snowball-and-firework.patch} | 0 ... => 0051-Snowball-and-Egg-knockback.patch} | 0 ....patch => 0052-Optimize-suffocation.patch} | 0 ...> 0053-Reduce-chunk-loading-lookups.patch} | 0 ...gurable-movement-speed-for-entities.patch} | 0 ...t-dirty-flag-when-loading-maps-from.patch} | 0 ...BlockEntity-ticking-isRemoved-check.patch} | 0 ...eird-movement-and-disable-teleporti.patch} | 2 +- ...-Raids.patch => 0058-Optimize-Raids.patch} | 0 ...SparklyPaper-Optimize-canSee-checks.patch} | 0 ...-Small-optimization-to-LinearPalette.patch | 63 +++++++++++++++++++ 13 files changed, 67 insertions(+), 38 deletions(-) delete mode 100644 divinemc-server/minecraft-patches/features/0049-Block-Log4Shell-exploit.patch rename divinemc-server/minecraft-patches/features/{0050-Option-to-disable-disconnect.spam.patch => 0049-Option-to-disable-disconnect.spam.patch} (95%) rename divinemc-server/minecraft-patches/features/{0051-Option-to-disable-saving-of-snowball-and-firework.patch => 0050-Option-to-disable-saving-of-snowball-and-firework.patch} (100%) rename divinemc-server/minecraft-patches/features/{0052-Snowball-and-Egg-knockback.patch => 0051-Snowball-and-Egg-knockback.patch} (100%) rename divinemc-server/minecraft-patches/features/{0053-Optimize-suffocation.patch => 0052-Optimize-suffocation.patch} (100%) rename divinemc-server/minecraft-patches/features/{0054-Reduce-chunk-loading-lookups.patch => 0053-Reduce-chunk-loading-lookups.patch} (100%) rename divinemc-server/minecraft-patches/features/{0055-Configurable-movement-speed-for-entities.patch => 0054-Configurable-movement-speed-for-entities.patch} (100%) rename divinemc-server/minecraft-patches/features/{0056-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch => 0055-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch} (100%) rename divinemc-server/minecraft-patches/features/{0057-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch => 0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch} (100%) rename divinemc-server/minecraft-patches/features/{0058-Option-to-allow-weird-movement-and-disable-teleporti.patch => 0057-Option-to-allow-weird-movement-and-disable-teleporti.patch} (98%) rename divinemc-server/minecraft-patches/features/{0059-Optimize-Raids.patch => 0058-Optimize-Raids.patch} (100%) rename divinemc-server/minecraft-patches/features/{0060-SparklyPaper-Optimize-canSee-checks.patch => 0059-SparklyPaper-Optimize-canSee-checks.patch} (100%) create mode 100644 divinemc-server/minecraft-patches/features/0060-Small-optimization-to-LinearPalette.patch diff --git a/divinemc-server/minecraft-patches/features/0049-Block-Log4Shell-exploit.patch b/divinemc-server/minecraft-patches/features/0049-Block-Log4Shell-exploit.patch deleted file mode 100644 index 439bf2c..0000000 --- a/divinemc-server/minecraft-patches/features/0049-Block-Log4Shell-exploit.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 1 Feb 2025 19:28:34 +0300 -Subject: [PATCH] Block Log4Shell exploit - - -diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index a8b2c19cc9803058b421b07c739166afdf291e47..3a27b544da8227511b546c55963e7112df0a9f63 100644 ---- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2515,6 +2515,7 @@ public class ServerGamePacketListenerImpl - } - - private void tryHandleChat(String message, Runnable handler, boolean sync) { // CraftBukkit -+ if (ServerGamePacketListenerImpl.isLog4ShellExploit(message)) return; // DivineMC - Block Log4Shell exploit - if (isChatMessageIllegal(message)) { - this.disconnectAsync(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - add proper async disconnect - } else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales -@@ -2547,6 +2548,15 @@ public class ServerGamePacketListenerImpl - } - } - -+ // DivineMC start - Block Log4Shell exploit -+ public static boolean isLog4ShellExploit(String message) { -+ java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(".*\\$\\{[^}]*}.*"); -+ java.util.regex.Matcher matcher = pattern.matcher(message); -+ -+ return matcher.find(); -+ } -+ // DivineMC end - Block Log4Shell exploit -+ - public static boolean isChatMessageIllegal(String message) { - for (int i = 0; i < message.length(); i++) { - if (!StringUtil.isAllowedChatCharacter(message.charAt(i))) { diff --git a/divinemc-server/minecraft-patches/features/0050-Option-to-disable-disconnect.spam.patch b/divinemc-server/minecraft-patches/features/0049-Option-to-disable-disconnect.spam.patch similarity index 95% rename from divinemc-server/minecraft-patches/features/0050-Option-to-disable-disconnect.spam.patch rename to divinemc-server/minecraft-patches/features/0049-Option-to-disable-disconnect.spam.patch index 1982ee1..b962f45 100644 --- a/divinemc-server/minecraft-patches/features/0050-Option-to-disable-disconnect.spam.patch +++ b/divinemc-server/minecraft-patches/features/0049-Option-to-disable-disconnect.spam.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Option to disable disconnect.spam diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 3a27b544da8227511b546c55963e7112df0a9f63..d5ed595bce6846590230634f8887e1f8e9b0a062 100644 +index a8b2c19cc9803058b421b07c739166afdf291e47..8f4bca6a99b35e869e34f0fa216c13189cd7b384 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -844,7 +844,7 @@ public class ServerGamePacketListenerImpl @@ -34,7 +34,7 @@ index 3a27b544da8227511b546c55963e7112df0a9f63..d5ed595bce6846590230634f8887e1f8 && parseResults.getExceptions().values().stream().anyMatch(e -> e instanceof io.papermc.paper.brigadier.TagParseCommandSyntaxException)) { this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); return; -@@ -2639,6 +2640,7 @@ public class ServerGamePacketListenerImpl +@@ -2629,6 +2630,7 @@ public class ServerGamePacketListenerImpl // this.chatSpamThrottler.increment(); if (!this.chatSpamThrottler.isIncrementAndUnderThreshold() // CraftBukkit end @@ -42,7 +42,7 @@ index 3a27b544da8227511b546c55963e7112df0a9f63..d5ed595bce6846590230634f8887e1f8 && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause & add proper async disconnect -@@ -3396,7 +3398,7 @@ public class ServerGamePacketListenerImpl +@@ -3386,7 +3388,7 @@ public class ServerGamePacketListenerImpl public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { // Paper start - auto recipe limit if (!org.bukkit.Bukkit.isPrimaryThread()) { diff --git a/divinemc-server/minecraft-patches/features/0051-Option-to-disable-saving-of-snowball-and-firework.patch b/divinemc-server/minecraft-patches/features/0050-Option-to-disable-saving-of-snowball-and-firework.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0051-Option-to-disable-saving-of-snowball-and-firework.patch rename to divinemc-server/minecraft-patches/features/0050-Option-to-disable-saving-of-snowball-and-firework.patch diff --git a/divinemc-server/minecraft-patches/features/0052-Snowball-and-Egg-knockback.patch b/divinemc-server/minecraft-patches/features/0051-Snowball-and-Egg-knockback.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0052-Snowball-and-Egg-knockback.patch rename to divinemc-server/minecraft-patches/features/0051-Snowball-and-Egg-knockback.patch diff --git a/divinemc-server/minecraft-patches/features/0053-Optimize-suffocation.patch b/divinemc-server/minecraft-patches/features/0052-Optimize-suffocation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0053-Optimize-suffocation.patch rename to divinemc-server/minecraft-patches/features/0052-Optimize-suffocation.patch diff --git a/divinemc-server/minecraft-patches/features/0054-Reduce-chunk-loading-lookups.patch b/divinemc-server/minecraft-patches/features/0053-Reduce-chunk-loading-lookups.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0054-Reduce-chunk-loading-lookups.patch rename to divinemc-server/minecraft-patches/features/0053-Reduce-chunk-loading-lookups.patch diff --git a/divinemc-server/minecraft-patches/features/0055-Configurable-movement-speed-for-entities.patch b/divinemc-server/minecraft-patches/features/0054-Configurable-movement-speed-for-entities.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0055-Configurable-movement-speed-for-entities.patch rename to divinemc-server/minecraft-patches/features/0054-Configurable-movement-speed-for-entities.patch diff --git a/divinemc-server/minecraft-patches/features/0056-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch b/divinemc-server/minecraft-patches/features/0055-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0056-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch rename to divinemc-server/minecraft-patches/features/0055-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch diff --git a/divinemc-server/minecraft-patches/features/0057-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch b/divinemc-server/minecraft-patches/features/0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0057-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch rename to divinemc-server/minecraft-patches/features/0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch diff --git a/divinemc-server/minecraft-patches/features/0058-Option-to-allow-weird-movement-and-disable-teleporti.patch b/divinemc-server/minecraft-patches/features/0057-Option-to-allow-weird-movement-and-disable-teleporti.patch similarity index 98% rename from divinemc-server/minecraft-patches/features/0058-Option-to-allow-weird-movement-and-disable-teleporti.patch rename to divinemc-server/minecraft-patches/features/0057-Option-to-allow-weird-movement-and-disable-teleporti.patch index 3d91505..b73178f 100644 --- a/divinemc-server/minecraft-patches/features/0058-Option-to-allow-weird-movement-and-disable-teleporti.patch +++ b/divinemc-server/minecraft-patches/features/0057-Option-to-allow-weird-movement-and-disable-teleporti.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Option to allow weird movement and disable teleporting diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index d5ed595bce6846590230634f8887e1f8e9b0a062..798482a332c4be045d5c409a20cd120c12b3460e 100644 +index 8f4bca6a99b35e869e34f0fa216c13189cd7b384..3ba558634558b4524245a2b29786237f5e38ef42 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -607,7 +607,7 @@ public class ServerGamePacketListenerImpl diff --git a/divinemc-server/minecraft-patches/features/0059-Optimize-Raids.patch b/divinemc-server/minecraft-patches/features/0058-Optimize-Raids.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0059-Optimize-Raids.patch rename to divinemc-server/minecraft-patches/features/0058-Optimize-Raids.patch diff --git a/divinemc-server/minecraft-patches/features/0060-SparklyPaper-Optimize-canSee-checks.patch b/divinemc-server/minecraft-patches/features/0059-SparklyPaper-Optimize-canSee-checks.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0060-SparklyPaper-Optimize-canSee-checks.patch rename to divinemc-server/minecraft-patches/features/0059-SparklyPaper-Optimize-canSee-checks.patch diff --git a/divinemc-server/minecraft-patches/features/0060-Small-optimization-to-LinearPalette.patch b/divinemc-server/minecraft-patches/features/0060-Small-optimization-to-LinearPalette.patch new file mode 100644 index 0000000..b876143 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0060-Small-optimization-to-LinearPalette.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 7 Jul 2025 04:21:38 +0300 +Subject: [PATCH] Small optimization to LinearPalette + + +diff --git a/net/minecraft/world/level/chunk/LinearPalette.java b/net/minecraft/world/level/chunk/LinearPalette.java +index 2073f6ff41aa570102621d183ee890b076267d54..93cb815032fada7b8abc7301a7005114eea8384d 100644 +--- a/net/minecraft/world/level/chunk/LinearPalette.java ++++ b/net/minecraft/world/level/chunk/LinearPalette.java +@@ -12,7 +12,7 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat + private final T[] values; + private final PaletteResize resizeHandler; + private final int bits; +- private int size; ++ private volatile int size; // DivineMC - Small optimization to LinearPalette + + // Paper start - optimise palette reads + @Override +@@ -49,11 +49,14 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat + + @Override + public int idFor(T state) { +- for (int i = 0; i < this.size; i++) { +- if (this.values[i] == state) { ++ // DivineMC start - Small optimization to LinearPalette ++ final T[] values = this.values; ++ for (int i = 0; i < values.length; i++) { ++ if (values[i] == state) { + return i; + } + } ++ // DivineMC end - Small optimization to LinearPalette + + int ix = this.size; + if (ix < this.values.length) { +@@ -67,17 +70,23 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat + + @Override + public boolean maybeHas(Predicate filter) { +- for (int i = 0; i < this.size; i++) { +- if (filter.test(this.values[i])) { ++ // DivineMC start - Small optimization to LinearPalette ++ final T[] values = this.values; ++ final int currentSize = this.size; ++ ++ for (int i = 0; i < currentSize; i++) { ++ T value = values[i]; ++ if (value != null && filter.test(value)) { + return true; + } + } ++ // DivineMC end - Small optimization to LinearPalette + + return false; + } + + @Override +- public T valueFor(int id) { ++ public synchronized T valueFor(int id) { // DivineMC - Small optimization to LinearPalette + if (id >= 0 && id < this.size) { + return this.values[id]; + } else { From 86763bcff405a3abca6dc71823efcf108df85b59 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 9 Jul 2025 03:03:03 +0300 Subject: [PATCH 10/67] another patch applies --- .../0061-Use-switch-for-VarInt-write.patch | 68 ++ .../features/0062-Optimize-Fluids.patch | 0 .../0063-Optimize-Structure-Generation.patch | 16 +- .../0064-Implement-NoChatReports.patch | 4 +- .../features/0065-Lag-compensation.patch | 18 +- .../features/0066-Virtual-Threads.patch | 4 +- .../features/0067-Async-Chunk-Sending.patch | 6 +- ...-Command-block-parse-results-caching.patch | 2 +- .../0069-Player-ProfileResult-caching.patch | 0 .../features/0070-Implement-Secure-Seed.patch | 12 +- .../0071-Dynamic-Activation-of-Brain.patch | 10 +- .../0072-Petal-Async-Pathfinding.patch | 18 +- .../0073-Petal-Multithreaded-Tracker.patch | 40 +- ...074-Pufferfish-Optimize-mob-spawning.patch | 109 +-- .../features/0015-Implement-Secure-Seed.patch | 2 +- .../0016-Petal-Multithreaded-Tracker.patch | 18 +- ...017-Pufferfish-Optimize-mob-spawning.patch | 59 ++ .../pufferfish/util/IterableWrapper.java | 13 + .../minecraft/0008-Misc-Optimizations.patch | 741 ------------------ ...08-Configurable-thread-pool-priority.patch | 18 - .../server/paper/0009-Virtual-Threads.patch | 59 -- 21 files changed, 257 insertions(+), 960 deletions(-) create mode 100644 divinemc-server/minecraft-patches/features/0061-Use-switch-for-VarInt-write.patch rename patches/work/server/minecraft/0009-Optimize-Fluids.patch => divinemc-server/minecraft-patches/features/0062-Optimize-Fluids.patch (100%) rename patches/work/server/minecraft/0025-Optimize-Structure-Generation.patch => divinemc-server/minecraft-patches/features/0063-Optimize-Structure-Generation.patch (97%) rename patches/work/server/minecraft/0013-Implement-NoChatReports.patch => divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch (99%) rename patches/work/server/minecraft/0012-Lag-compensation.patch => divinemc-server/minecraft-patches/features/0065-Lag-compensation.patch (95%) rename patches/work/server/minecraft/0024-Virtual-Threads.patch => divinemc-server/minecraft-patches/features/0066-Virtual-Threads.patch (98%) rename patches/work/server/minecraft/0027-Async-Chunk-Sending.patch => divinemc-server/minecraft-patches/features/0067-Async-Chunk-Sending.patch (95%) rename patches/work/server/minecraft/0032-Command-block-parse-results-caching.patch => divinemc-server/minecraft-patches/features/0068-Command-block-parse-results-caching.patch (98%) rename patches/work/server/minecraft/0040-Player-ProfileResult-caching.patch => divinemc-server/minecraft-patches/features/0069-Player-ProfileResult-caching.patch (100%) rename patches/work/server/minecraft/0004-Implement-Secure-Seed.patch => divinemc-server/minecraft-patches/features/0070-Implement-Secure-Seed.patch (98%) rename patches/work/server/minecraft/0037-Dynamic-Activation-of-Brain.patch => divinemc-server/minecraft-patches/features/0071-Dynamic-Activation-of-Brain.patch (98%) rename patches/work/server/minecraft/0005-Async-Pathfinding.patch => divinemc-server/minecraft-patches/features/0072-Petal-Async-Pathfinding.patch (98%) rename patches/work/server/minecraft/0007-Multithreaded-Tracker.patch => divinemc-server/minecraft-patches/features/0073-Petal-Multithreaded-Tracker.patch (95%) rename patches/work/server/minecraft/0041-Async-mob-spawning.patch => divinemc-server/minecraft-patches/features/0074-Pufferfish-Optimize-mob-spawning.patch (66%) rename patches/work/server/paper/0005-Implement-Secure-Seed.patch => divinemc-server/paper-patches/features/0015-Implement-Secure-Seed.patch (96%) rename patches/work/server/paper/0010-Multithreaded-Tracker.patch => divinemc-server/paper-patches/features/0016-Petal-Multithreaded-Tracker.patch (85%) create mode 100644 divinemc-server/paper-patches/features/0017-Pufferfish-Optimize-mob-spawning.patch create mode 100644 divinemc-server/src/main/java/gg/pufferfish/pufferfish/util/IterableWrapper.java delete mode 100644 patches/work/server/minecraft/0008-Misc-Optimizations.patch delete mode 100644 patches/work/server/paper/0008-Configurable-thread-pool-priority.patch delete mode 100644 patches/work/server/paper/0009-Virtual-Threads.patch diff --git a/divinemc-server/minecraft-patches/features/0061-Use-switch-for-VarInt-write.patch b/divinemc-server/minecraft-patches/features/0061-Use-switch-for-VarInt-write.patch new file mode 100644 index 0000000..6421a49 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0061-Use-switch-for-VarInt-write.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 9 Jul 2025 02:08:35 +0300 +Subject: [PATCH] Use switch for VarInt#write + + +diff --git a/net/minecraft/network/VarInt.java b/net/minecraft/network/VarInt.java +index 4897ff4648083ebe737ae5b32bae344af27357e4..dddabc57f5415077b905cb59c5b47db1a621807f 100644 +--- a/net/minecraft/network/VarInt.java ++++ b/net/minecraft/network/VarInt.java +@@ -51,21 +51,46 @@ public class VarInt { + } + + public static ByteBuf write(ByteBuf buffer, int value) { +- // Paper start - Optimize VarInts +- // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes +- // that the proxy will write, to improve inlining. +- if ((value & (0xFFFFFFFF << 7)) == 0) { +- buffer.writeByte(value); +- } else if ((value & (0xFFFFFFFF << 14)) == 0) { +- int w = (value & 0x7F | 0x80) << 8 | (value >>> 7); +- buffer.writeShort(w); +- } else { +- writeOld(buffer, value); ++ // DivineMC start - Use switch for VarInt#write ++ int bytesNeeded = getByteSize(value); ++ ++ switch (bytesNeeded) { ++ case 1: ++ buffer.writeByte(value); ++ break; ++ case 2: ++ int w2 = ((value & 0x7F) << 8) | (value >>> 7) | 0x00008000; ++ buffer.writeShort(w2); ++ break; ++ case 3: ++ int w3 = (value & 0x7F) << 16 ++ | (value & 0x3F80) << 1 ++ | (value >>> 14) ++ | 0x00808000; ++ buffer.writeMedium(w3); ++ break; ++ case 4: ++ int w4 = (value & 0x7F) << 24 ++ | ((value & 0x3F80) << 9) ++ | (value & 0x1FC000) >> 6 ++ | (value >>> 21) ++ | 0x80808000; ++ buffer.writeInt(w4); ++ break; ++ case 5: ++ int w5 = (value & 0x7F) << 24 ++ | (value & 0x3F80) << 9 ++ | (value & 0x1FC000) >> 6 ++ | ((value >>> 21) & 0x7F) ++ | 0x80808080; ++ buffer.writeInt(w5); ++ buffer.writeByte(value >>> 28); ++ break; + } ++ // DivineMC end - Use switch for VarInt#write + return buffer; + } + public static ByteBuf writeOld(ByteBuf buffer, int value) { +- // Paper end - Optimize VarInts + while ((value & -128) != 0) { + buffer.writeByte(value & 127 | 128); + value >>>= 7; diff --git a/patches/work/server/minecraft/0009-Optimize-Fluids.patch b/divinemc-server/minecraft-patches/features/0062-Optimize-Fluids.patch similarity index 100% rename from patches/work/server/minecraft/0009-Optimize-Fluids.patch rename to divinemc-server/minecraft-patches/features/0062-Optimize-Fluids.patch diff --git a/patches/work/server/minecraft/0025-Optimize-Structure-Generation.patch b/divinemc-server/minecraft-patches/features/0063-Optimize-Structure-Generation.patch similarity index 97% rename from patches/work/server/minecraft/0025-Optimize-Structure-Generation.patch rename to divinemc-server/minecraft-patches/features/0063-Optimize-Structure-Generation.patch index 813d35a..ee3655c 100644 --- a/patches/work/server/minecraft/0025-Optimize-Structure-Generation.patch +++ b/divinemc-server/minecraft-patches/features/0063-Optimize-Structure-Generation.patch @@ -3,9 +3,11 @@ From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Tue, 4 Feb 2025 19:52:24 +0300 Subject: [PATCH] Optimize Structure Generation +Original project: https://github.com/TelepathicGrunt/StructureLayoutOptimizer +Original license: MIT diff --git a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java -index 86a54586112b84b7c2026a4cbdad99cdf1c6ef81..e4ca880b5d16ae30676ec25c39c3d5b5f6cb3c24 100644 +index 1cfa0fcd28685736fcdce4aef817e4d4cc4061cb..cd3b24a760053dcd650a1a263b3c0093a0cbb175 100644 --- a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java +++ b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java @@ -4,6 +4,8 @@ import com.google.common.collect.Lists; @@ -17,7 +19,7 @@ index 86a54586112b84b7c2026a4cbdad99cdf1c6ef81..e4ca880b5d16ae30676ec25c39c3d5b5 import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; -@@ -292,6 +294,108 @@ public class JigsawPlacement { +@@ -288,6 +290,108 @@ public class JigsawPlacement { this.random = random; } @@ -126,7 +128,7 @@ index 86a54586112b84b7c2026a4cbdad99cdf1c6ef81..e4ca880b5d16ae30676ec25c39c3d5b5 void tryPlacingChildren( PoolElementStructurePiece piece, MutableObject free, -@@ -349,9 +453,9 @@ public class JigsawPlacement { +@@ -345,9 +449,9 @@ public class JigsawPlacement { mutableObject1 = free; } @@ -138,7 +140,7 @@ index 86a54586112b84b7c2026a4cbdad99cdf1c6ef81..e4ca880b5d16ae30676ec25c39c3d5b5 } list.addAll(fallback.value().getShuffledTemplates(this.random)); -@@ -362,10 +466,14 @@ public class JigsawPlacement { +@@ -358,10 +462,14 @@ public class JigsawPlacement { break; } @@ -155,7 +157,7 @@ index 86a54586112b84b7c2026a4cbdad99cdf1c6ef81..e4ca880b5d16ae30676ec25c39c3d5b5 BoundingBox boundingBox1 = structurePoolElement.getBoundingBox(this.structureTemplateManager, BlockPos.ZERO, rotation1); int i2; if (useExpansionHack && boundingBox1.getYSpan() <= 16) { -@@ -398,7 +506,7 @@ public class JigsawPlacement { +@@ -394,7 +502,7 @@ public class JigsawPlacement { } for (StructureTemplate.JigsawBlockInfo jigsawBlockInfo1 : shuffledJigsawBlocks) { @@ -164,7 +166,7 @@ index 86a54586112b84b7c2026a4cbdad99cdf1c6ef81..e4ca880b5d16ae30676ec25c39c3d5b5 BlockPos blockPos2 = jigsawBlockInfo1.info().pos(); BlockPos blockPos3 = blockPos1.subtract(blockPos2); BoundingBox boundingBox2 = structurePoolElement.getBoundingBox(this.structureTemplateManager, blockPos3, rotation1); -@@ -427,9 +535,26 @@ public class JigsawPlacement { +@@ -423,9 +531,26 @@ public class JigsawPlacement { boundingBox3.encapsulate(new BlockPos(boundingBox3.minX(), boundingBox3.minY() + max, boundingBox3.minZ())); } @@ -231,7 +233,7 @@ index 5c081a5b3d10f713e4e82fe1a43758f553fe50e0..85e84603a19964f05d9d5e62eb096ca7 + // DivineMC end - Optimize Structure Generation } diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -index 5a05536e474bec574aa637f86bfc51f566d76ebf..e0f4500099c582653a81e6679be859e3d669bb88 100644 +index f21e612a35d6ac4482dbf5d14e506959659e371a..c02c3b1fddd513cb477cbb7400c30a9ad57f80a6 100644 --- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java +++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java @@ -255,6 +255,12 @@ public class StructureTemplate { diff --git a/patches/work/server/minecraft/0013-Implement-NoChatReports.patch b/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch similarity index 99% rename from patches/work/server/minecraft/0013-Implement-NoChatReports.patch rename to divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch index 2be2edc..8b8f786 100644 --- a/patches/work/server/minecraft/0013-Implement-NoChatReports.patch +++ b/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch @@ -287,7 +287,7 @@ index 667ef5b2ab50eeb0491f7fe0bc8913ec29a4603a..a7c4fad2b1cb0cbac742a18d37d688bb if (packet == null || this.processedDisconnect) { // Spigot return; diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 8a67672f1175769ac213099331453fbae59442fa..5ebbb4e37469beef11bdfd1531b0d10f3d01c826 100644 +index fb1b9f75cffeb15875e6690a0e030f8a4fd8b276..6713eb83b36f115e72fa5999c413e59e4f634f9f 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java @@ -276,7 +276,7 @@ public abstract class PlayerList { @@ -299,7 +299,7 @@ index 8a67672f1175769ac213099331453fbae59442fa..5ebbb4e37469beef11bdfd1531b0d10f ) ); player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit -@@ -1318,6 +1318,7 @@ public abstract class PlayerList { +@@ -1332,6 +1332,7 @@ public abstract class PlayerList { } public boolean verifyChatTrusted(PlayerChatMessage message) { diff --git a/patches/work/server/minecraft/0012-Lag-compensation.patch b/divinemc-server/minecraft-patches/features/0065-Lag-compensation.patch similarity index 95% rename from patches/work/server/minecraft/0012-Lag-compensation.patch rename to divinemc-server/minecraft-patches/features/0065-Lag-compensation.patch index 38d2a80..4805345 100644 --- a/patches/work/server/minecraft/0012-Lag-compensation.patch +++ b/divinemc-server/minecraft-patches/features/0065-Lag-compensation.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Lag compensation diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index abfecaf4467092f7baa02e0f5bbfd23d087f2aa3..77a693f42d90b5d17bf56d86b1676247c1ad505d 100644 +index 7a3775185d5c80f43456a595f22a9ebf19760bd6..23144971acc04bbeacd719dafe2363d1618153b9 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -288,6 +288,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop Date: Tue, 28 Jan 2025 01:04:55 +0300 -Subject: [PATCH] Async Pathfinding +Subject: [PATCH] Petal: Async Pathfinding Original code by Bloom-host, licensed under GPL v3 You can find the original code on https://github.com/Bloom-host/Petal @@ -393,7 +393,7 @@ index 86fccf3617a32f3791b03d8067e2eaf6b8d8bebb..2c26d30a7373c6ac8ead22894b63a8d6 } diff --git a/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index c8e4ccb96a0f162c780066cf4f61b970b49b7703..0b5f1f1e24c8c0468875d709c6b81798882600a0 100644 +index 24dd92449f70144c79f25bf24942ebd666655ed2..8d243cac4a0ba0536bd65c39bf3483d056e00116 100644 --- a/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/net/minecraft/world/entity/ai/navigation/PathNavigation.java @@ -167,6 +167,10 @@ public abstract class PathNavigation { @@ -579,10 +579,10 @@ index ca5651f15552f91fba650747d28a75c00fa11442..c5883758d11e91f96b4139b3bd8586a8 } } diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java -index c6e4966d3e4fdb7c91577fc1693fb66930b4f3dc..81f0e444ccb6962d675e3a097341683d504d0889 100644 +index 85963b74a533beb7883ea417ceb3c21d834aebe0..1c9f3f0b2a344c026532c89c0db377ab8183c912 100644 --- a/net/minecraft/world/entity/animal/frog/Frog.java +++ b/net/minecraft/world/entity/animal/frog/Frog.java -@@ -483,6 +483,17 @@ public class Frog extends Animal { +@@ -488,6 +488,17 @@ public class Frog extends Animal { super(mob, level); } @@ -600,7 +600,7 @@ index c6e4966d3e4fdb7c91577fc1693fb66930b4f3dc..81f0e444ccb6962d675e3a097341683d @Override public boolean canCutCorner(PathType pathType) { return pathType != PathType.WATER_BORDER && super.canCutCorner(pathType); -@@ -491,6 +502,11 @@ public class Frog extends Animal { +@@ -496,6 +507,11 @@ public class Frog extends Animal { @Override protected PathFinder createPathFinder(int maxVisitedNodes) { this.nodeEvaluator = new Frog.FrogNodeEvaluator(true); @@ -613,10 +613,10 @@ index c6e4966d3e4fdb7c91577fc1693fb66930b4f3dc..81f0e444ccb6962d675e3a097341683d } } diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java -index 2e6d0f035a01277aa28bbe912d5df8dc4cf04547..edcb20935f58e78fa4ef2c11a7dcc6a7857341c2 100644 +index 2a13332ebabf2e63a8f51a5d794fab3d66c7a1db..d4e7fc0a5bda4f44bcfed3d1adae7cdaf815784b 100644 --- a/net/minecraft/world/entity/monster/Drowned.java +++ b/net/minecraft/world/entity/monster/Drowned.java -@@ -308,7 +308,7 @@ public class Drowned extends Zombie implements RangedAttackMob { +@@ -309,7 +309,7 @@ public class Drowned extends Zombie implements RangedAttackMob { protected boolean closeToNextPos() { Path path = this.getNavigation().getPath(); @@ -656,10 +656,10 @@ index fe31c4a45afd61be8b74efe9d0858ccd0aced075..859c41c3c81b3d3ac05eebdc83c959d1 } diff --git a/net/minecraft/world/entity/monster/warden/Warden.java b/net/minecraft/world/entity/monster/warden/Warden.java -index 021aa51da04bea01b0e827390ce1690af7092b8f..0440cbbc0d6657f32dc37a1dbbe9ee78f8e229cf 100644 +index 7bfc597655cc55c46b65c9726a6e9de9f3f5afc8..4944b6d389c65511eed75d580779f912b8ff076d 100644 --- a/net/minecraft/world/entity/monster/warden/Warden.java +++ b/net/minecraft/world/entity/monster/warden/Warden.java -@@ -574,6 +574,16 @@ public class Warden extends Monster implements VibrationSystem { +@@ -579,6 +579,16 @@ public class Warden extends Monster implements VibrationSystem { @Override protected PathFinder createPathFinder(int maxVisitedNodes) { this.nodeEvaluator = new WalkNodeEvaluator(); diff --git a/patches/work/server/minecraft/0007-Multithreaded-Tracker.patch b/divinemc-server/minecraft-patches/features/0073-Petal-Multithreaded-Tracker.patch similarity index 95% rename from patches/work/server/minecraft/0007-Multithreaded-Tracker.patch rename to divinemc-server/minecraft-patches/features/0073-Petal-Multithreaded-Tracker.patch index 9c949a8..28aa428 100644 --- a/patches/work/server/minecraft/0007-Multithreaded-Tracker.patch +++ b/divinemc-server/minecraft-patches/features/0073-Petal-Multithreaded-Tracker.patch @@ -1,8 +1,18 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Tue, 28 Jan 2025 01:18:49 +0300 -Subject: [PATCH] Multithreaded Tracker +Subject: [PATCH] Petal: Multithreaded Tracker +Original project: https://github.com/Bloom-host/Petal +Original license: GPL v3 + +Patch description: + +We made much of tracking logic asynchronously, and fixed visible issue +for the case of some NPC plugins which using real entity type, e.g. Citizens. + +But it is still recommending to use those packet based, virtual entity +based NPC plugins, e.g. ZNPC Plus, Adyeshach, Fancy NPC, etc. diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..93272808d94e81d31af728ebe85df9a2bc7aedab 100644 @@ -27,10 +37,10 @@ index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..93272808d94e81d31af728ebe85df9a2 { for (int i = 0; i < this.directByChunk.length; ++i) { diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -index bdc1200ef5317fdaf58973bf580b0a672aee800f..dc2b3ccf7810731c0e2c90e5a476c1c8203a1fb7 100644 +index 053da602eb08b5a8b7a316e56f76a99e86149483..d1adef3f61acdbbc246f7ca3614b7e8aa7d25284 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -@@ -344,7 +344,11 @@ public final class RegionizedPlayerChunkLoader { +@@ -347,7 +347,11 @@ public final class RegionizedPlayerChunkLoader { private boolean canGenerateChunks = true; private final ArrayDeque> delayedTicketOps = new ArrayDeque<>(); @@ -56,7 +66,7 @@ index 9c0c99b936b4a82ebfe924866e53ec71f7bbe9ad..01ed1e3572e9c2ccfd19df117cda0d5c .add( new ClientboundUpdateAttributesPacket.AttributeSnapshot( diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index edda52a8430386238be4963e8ea2406f0c2d4df3..2c5104b9ae1d2ea902eeac5a1c9d49bc1af67c43 100644 +index c0d996fb99f053863ce623889add3feb70d7137d..a3290eb416ecb377d240bf334aef4e2b5e3bbefc 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java @@ -255,9 +255,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -346,7 +356,7 @@ index f106373ef3ac4a8685c2939c9e8361688a285913..b844b6dd89bc53b74c0d1bdbf4657c11 public boolean visible = true; diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java -index e96d4dee14c05f2fa329bfb1588ec795d4e3d730..917029d96afb5843276f4fa4ee37292327aea626 100644 +index 0868189fee30d40dfb82ae39592a65b510e96b54..39e28ad0cbb4617a80d7f197723233d4bdc1eed5 100644 --- a/net/minecraft/server/level/ServerEntity.java +++ b/net/minecraft/server/level/ServerEntity.java @@ -134,7 +134,7 @@ public class ServerEntity { @@ -358,7 +368,7 @@ index e96d4dee14c05f2fa329bfb1588ec795d4e3d730..917029d96afb5843276f4fa4ee372923 final ServerPlayer serverPlayer = connection.getPlayer(); // Paper savedData.tickCarriedBy(serverPlayer, item); Packet updatePacket = savedData.getUpdatePacket(mapId, serverPlayer); -@@ -424,8 +424,6 @@ public class ServerEntity { +@@ -428,8 +428,6 @@ public class ServerEntity { // CraftBukkit end this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync)); } @@ -368,10 +378,10 @@ index e96d4dee14c05f2fa329bfb1588ec795d4e3d730..917029d96afb5843276f4fa4ee372923 } diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 9dcb9e5ecc31fcc3fc7547a47ec98d2689698769..2560799fe6ec006916a2bc9915355a358ab6c8bb 100644 +index 78bf3365b426e7090182af84630111d410a2460e..3c1795eb56900cd80cfec38bd1d922d566463ecb 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -2504,7 +2504,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2517,7 +2517,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public LevelEntityGetter getEntities() { @@ -379,7 +389,7 @@ index 9dcb9e5ecc31fcc3fc7547a47ec98d2689698769..2560799fe6ec006916a2bc9915355a35 return this.moonrise$getEntityLookup(); // Paper - rewrite chunk system } -@@ -2771,7 +2770,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2784,7 +2783,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } map.carriedByPlayers.remove(player); @@ -389,10 +399,10 @@ index 9dcb9e5ecc31fcc3fc7547a47ec98d2689698769..2560799fe6ec006916a2bc9915355a35 } } diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index f36e042b36b94a0de2524d01ed44558900ba2a99..649b01c00ec01eea1514676e424d88acbfa26184 100644 +index b6f67c4359e718db8eb9240a22e71fd0b1bc6d05..bc738535f67d789e9d240b245e9247e026b3c751 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1931,7 +1931,6 @@ public class ServerGamePacketListenerImpl +@@ -1934,7 +1934,6 @@ public class ServerGamePacketListenerImpl } public void internalTeleport(PositionMoveRotation posMoveRotation, Set relatives) { @@ -401,10 +411,10 @@ index f36e042b36b94a0de2524d01ed44558900ba2a99..649b01c00ec01eea1514676e424d88ac if (this.player.isRemoved()) { LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName()); diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index d382a9760c0379f3d1c3bc65303d1de250858343..f5a036cfde9ced6ed8f0e548db3b69b1a46a0d2d 100644 +index a6a7af2393c15f92683f05500bd4f45b1b1f4853..6ac8209ec468ec4f65f75b383478eee0b537fabf 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java -@@ -1335,13 +1335,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin +@@ -1353,13 +1353,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin } private void refreshDirtyAttributes() { @@ -638,10 +648,10 @@ index 325ec57df2885f5e81b8a6b61e3a9fed9484b30f..1796f0a6f647c94b0943a6003a130779 @Override diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -index 7bbeed6c998c91e68376d3f17a510d68e3cd0b27..de7b3a8a7c841360310a88005da02a0733b46714 100644 +index ebb0b7e5047efa65e8b6986f12dd5a7d6c0e9613..a77665abefdf653e65393cc6908506a5812b5596 100644 --- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -211,6 +211,7 @@ public class MapItemSavedData extends SavedData { +@@ -212,6 +212,7 @@ public class MapItemSavedData extends SavedData { for (int i = 0; i < this.carriedBy.size(); i++) { MapItemSavedData.HoldingPlayer holdingPlayer1 = this.carriedBy.get(i); diff --git a/patches/work/server/minecraft/0041-Async-mob-spawning.patch b/divinemc-server/minecraft-patches/features/0074-Pufferfish-Optimize-mob-spawning.patch similarity index 66% rename from patches/work/server/minecraft/0041-Async-mob-spawning.patch rename to divinemc-server/minecraft-patches/features/0074-Pufferfish-Optimize-mob-spawning.patch index a7210ac..5f053df 100644 --- a/patches/work/server/minecraft/0041-Async-mob-spawning.patch +++ b/divinemc-server/minecraft-patches/features/0074-Pufferfish-Optimize-mob-spawning.patch @@ -1,11 +1,15 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 19 Mar 2025 23:24:32 +0300 -Subject: [PATCH] Async mob spawning +Subject: [PATCH] Pufferfish: Optimize mob spawning +Original license: GPL v3 +Original project: https://github.com/pufferfish-gg/Pufferfish + +This patch reduces the main-thread impact of mob spawning by moving spawning work to other threads diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 1a36a7c071c9f203d32f524008cf031fb1a4d6a6..c067f46935753794b49f29358262273fcd15d707 100644 +index 7dbefd83d164a7d97a56b02862fef3b2f17d5aab..2f4be37e1ef4ea550bd6acd2c4647e5a7ed77648 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -289,6 +289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function threadFunction) { ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 6de832e7aec630914e70fb0f11223907ab28298c..7205fc8d3b17863c262d4c4c3cb956c852468c6f 100644 +index 75c8ce32e68f92e20201e9c243f46f2be716eac8..a76f7ce474cc1d6ff918737e845666a7529bd4a3 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -182,6 +182,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -31,7 +35,7 @@ index 6de832e7aec630914e70fb0f11223907ab28298c..7205fc8d3b17863c262d4c4c3cb956c8 public ServerChunkCache( ServerLevel level, -@@ -505,6 +509,32 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -506,6 +510,47 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon this.broadcastChangedChunks(); } @@ -42,20 +46,35 @@ index 6de832e7aec630914e70fb0f11223907ab28298c..7205fc8d3b17863c262d4c4c3cb956c8 + for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) { + player.mobCounts[ii] = 0; + -+ int newBackoff = Math.max(0, player.mobBackoffCounts[ii] - 1); // DivineMC - Async mob spawning ++ int newBackoff = Math.max(0, player.mobBackoffCounts[ii] - 1); + player.mobBackoffCounts[ii] = newBackoff; + } + } ++ + if (firstRunSpawnCounts) { + firstRunSpawnCounts = false; + spawnCountsReady.set(true); + } ++ + if (spawnCountsReady.getAndSet(false)) { -+ MinecraftServer.getServer().mobSpawnExecutor.submit(() -> { ++ net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> { + int mapped = distanceManager.getNaturalSpawnChunkCount(); ++ ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator objectiterator = level.entityTickList.entities.iterator(ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); ++ + try { -+ lastSpawnState = NaturalSpawner.createState(mapped, new java.util.ArrayList<>(level.entityTickList.entities), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap), true); -+ } finally { } ++ gg.pufferfish.pufferfish.util.IterableWrapper wrappedIterator = new gg.pufferfish.pufferfish.util.IterableWrapper<>(objectiterator); ++ LocalMobCapCalculator mobCapCalculator = !level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(chunkMap) : null; ++ ++ lastSpawnState = NaturalSpawner.createState( ++ mapped, ++ wrappedIterator, ++ ServerChunkCache.this::getFullChunk, ++ mobCapCalculator, ++ level.paperConfig().entities.spawning.perPlayerMobSpawns ++ ); ++ } finally { ++ objectiterator.finishedIterating(); ++ } + spawnCountsReady.set(true); + }); + } @@ -64,7 +83,7 @@ index 6de832e7aec630914e70fb0f11223907ab28298c..7205fc8d3b17863c262d4c4c3cb956c8 } private void broadcastChangedChunks() { -@@ -522,27 +552,31 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -523,27 +568,31 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon int naturalSpawnChunkCount = this.distanceManager.getNaturalSpawnChunkCount(); // Paper start - Optional per player mob spawns NaturalSpawner.SpawnState spawnState; @@ -110,7 +129,7 @@ index 6de832e7aec630914e70fb0f11223907ab28298c..7205fc8d3b17863c262d4c4c3cb956c8 boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit int _int = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); List filteredSpawningCategories; -@@ -556,7 +590,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -557,7 +606,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } // Paper end - PlayerNaturallySpawnCreaturesEvent boolean flag = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit @@ -119,7 +138,7 @@ index 6de832e7aec630914e70fb0f11223907ab28298c..7205fc8d3b17863c262d4c4c3cb956c8 } else { filteredSpawningCategories = List.of(); } -@@ -573,7 +607,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -572,7 +621,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon // Paper end - chunk tick iteration optimisation for (LevelChunk levelChunk : list) { @@ -128,7 +147,7 @@ index 6de832e7aec630914e70fb0f11223907ab28298c..7205fc8d3b17863c262d4c4c3cb956c8 } } finally { list.clear(); -@@ -592,11 +626,11 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -591,11 +640,11 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon this.level.tickThunder(chunk); } @@ -144,69 +163,3 @@ index 6de832e7aec630914e70fb0f11223907ab28298c..7205fc8d3b17863c262d4c4c3cb956c8 } private void getFullChunk(long chunkPos, Consumer fullChunkGetter) { -diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java -index 68a074a1eb11b158af773a2c44aa49d5d8462080..a5f6f50ad1e276a908347d9c21527fb583734538 100644 ---- a/net/minecraft/world/level/NaturalSpawner.java -+++ b/net/minecraft/world/level/NaturalSpawner.java -@@ -149,7 +149,18 @@ public final class NaturalSpawner { - return list; - } - -+ private static int maxCapPerPlayer = -1; // DivineMC - Async mob spawning -+ - public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List categories) { -+ // DivineMC start - Async mob spawning -+ if (maxCapPerPlayer < 0) { -+ maxCapPerPlayer = 0; -+ for (final MobCategory value : MobCategory.values()) { -+ maxCapPerPlayer += value.getMaxInstancesPerChunk(); -+ } -+ } -+ // DivineMC end - Async mob spawning -+ - for (MobCategory mobCategory : categories) { - // Paper start - Optional per player mob spawns - final boolean canSpawn; -@@ -680,6 +691,13 @@ public final class NaturalSpawner { - } - - boolean canSpawnForCategoryLocal(MobCategory category, ChunkPos chunkPos) { -+ // DivineMC start - Async mob spawning -+ if (this.localMobCapCalculator == null) { -+ LOGGER.warn("Local mob cap calculator was null! Report to DivineMC!"); -+ return false; -+ } -+ // DivineMC end - Async mob spawning -+ - return this.localMobCapCalculator.canSpawn(category, chunkPos); - } - } -diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java -index c89701d7bdc9b889038d3c52f2232fb17624b113..9e75320e51886e0f93c23683d8614128f44a613e 100644 ---- a/net/minecraft/world/level/entity/EntityTickList.java -+++ b/net/minecraft/world/level/entity/EntityTickList.java -@@ -9,7 +9,7 @@ import javax.annotation.Nullable; - import net.minecraft.world.entity.Entity; - - public class EntityTickList { -- public final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system -+ public final java.util.concurrent.ConcurrentLinkedQueue entities = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Paper - rewrite chunk system // DivineMC - Async mob spawning - - private void ensureActiveIsNotIterated() { - // Paper - rewrite chunk system -@@ -33,13 +33,13 @@ public class EntityTickList { - // Paper start - rewrite chunk system - // To ensure nothing weird happens with dimension travelling, do not iterate over new entries... - // (by dfl iterator() is configured to not iterate over new entries) -- final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator iterator = this.entities.iterator(); -+ final java.util.Iterator iterator = this.entities.iterator(); // DivineMC - Async mob spawning - try { - while (iterator.hasNext()) { - entity.accept(iterator.next()); - } - } finally { -- iterator.finishedIterating(); -+ //iterator.finishedIterating(); // DivineMC - Async mob spawning - } - // Paper end - rewrite chunk system - } diff --git a/patches/work/server/paper/0005-Implement-Secure-Seed.patch b/divinemc-server/paper-patches/features/0015-Implement-Secure-Seed.patch similarity index 96% rename from patches/work/server/paper/0005-Implement-Secure-Seed.patch rename to divinemc-server/paper-patches/features/0015-Implement-Secure-Seed.patch index f0d7b21..88d4cbc 100644 --- a/patches/work/server/paper/0005-Implement-Secure-Seed.patch +++ b/divinemc-server/paper-patches/features/0015-Implement-Secure-Seed.patch @@ -25,7 +25,7 @@ index 400e632208d133a3f49fc7f14bceb48a1026769b..a1c7ba0fdb505d09407cca94e890dedd @Override diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 8014666a5145c46d7ecd40b2175f0990e699db47..b161209bb1111fd2ae7a3b601c8303cbdfab0ea7 100644 +index 414fdc6ca7a2979124a7fbf529bff60f993c005a..19430a22687e6bf2887222ecdda2fdda9539c0f8 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1352,7 +1352,11 @@ public final class CraftServer implements Server { diff --git a/patches/work/server/paper/0010-Multithreaded-Tracker.patch b/divinemc-server/paper-patches/features/0016-Petal-Multithreaded-Tracker.patch similarity index 85% rename from patches/work/server/paper/0010-Multithreaded-Tracker.patch rename to divinemc-server/paper-patches/features/0016-Petal-Multithreaded-Tracker.patch index e667eaf..b78e3ec 100644 --- a/patches/work/server/paper/0010-Multithreaded-Tracker.patch +++ b/divinemc-server/paper-patches/features/0016-Petal-Multithreaded-Tracker.patch @@ -1,8 +1,18 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 1 Mar 2025 23:06:52 +0300 -Subject: [PATCH] Multithreaded Tracker +Subject: [PATCH] Petal: Multithreaded Tracker +Original project: https://github.com/Bloom-host/Petal +Original license: GPL v3 + +Patch description: + +We made much of tracking logic asynchronously, and fixed visible issue +for the case of some NPC plugins which using real entity type, e.g. Citizens. + +But it is still recommending to use those packet based, virtual entity +based NPC plugins, e.g. ZNPC Plus, Adyeshach, Fancy NPC, etc. diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java index d7398b1ecf2660c29fb7d106b48fe02d3736603e..ab499a7eaccdc1578ec64f90f54f79b0da3c0e96 100644 @@ -22,10 +32,10 @@ index d7398b1ecf2660c29fb7d106b48fe02d3736603e..ab499a7eaccdc1578ec64f90f54f79b0 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index acd3b4f8b3e9c40253bacb3d16017fb7102c071c..fda15b81d2405179261fa6fa76c3ec8f7ad6eaf5 100644 +index 4913ac7d0426025689c8aee3790d87f7ac0131fd..d4d3aeae964d9a64805ddc5862e46fff5dd7d98a 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2942,7 +2942,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa +@@ -2953,7 +2953,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa Iterator iterator = collection.iterator(); while (iterator.hasNext()) { AttributeInstance genericInstance = iterator.next(); @@ -35,7 +45,7 @@ index acd3b4f8b3e9c40253bacb3d16017fb7102c071c..fda15b81d2405179261fa6fa76c3ec8f break; } diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index a162440a583801671787163d998d6b9546ef7e61..214bc24aa301f99c911a129676bc7d7d50df7236 100644 +index d10ee84ed2f6b1c81667b968984f3ebf5c39e445..83c6cf3cb062c8a6508728822e37d52a543415a3 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -1808,6 +1808,26 @@ public class CraftEventFactory { diff --git a/divinemc-server/paper-patches/features/0017-Pufferfish-Optimize-mob-spawning.patch b/divinemc-server/paper-patches/features/0017-Pufferfish-Optimize-mob-spawning.patch new file mode 100644 index 0000000..6ae2fe5 --- /dev/null +++ b/divinemc-server/paper-patches/features/0017-Pufferfish-Optimize-mob-spawning.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 9 Jul 2025 03:01:38 +0300 +Subject: [PATCH] Pufferfish: Optimize mob spawning + +Original license: GPL v3 +Original project: https://github.com/pufferfish-gg/Pufferfish + +This patch reduces the main-thread impact of mob spawning by moving spawning work to other threads + +diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java +index ece6db7b9a0dfd535141c0c756947c4898140503..41a725e9926767fbbf2a3e3558f850f0d57c5945 100644 +--- a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java ++++ b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java +@@ -19,7 +19,7 @@ public final class IteratorSafeOrderedReferenceSet { + + private final double maxFragFactor; + +- private int iteratorCount; ++ private final java.util.concurrent.atomic.AtomicInteger iteratorCount = new java.util.concurrent.atomic.AtomicInteger(); // DivineMC - Pufferfish: Optimize mob spawning + + public IteratorSafeOrderedReferenceSet() { + this(Object.class); +@@ -99,7 +99,7 @@ public final class IteratorSafeOrderedReferenceSet { + } + + public int createRawIterator() { +- ++this.iteratorCount; ++ this.iteratorCount.incrementAndGet(); // DivineMC - Pufferfish: Optimize mob spawning + if (this.indexMap.isEmpty()) { + return Integer.MAX_VALUE; + } else { +@@ -120,7 +120,7 @@ public final class IteratorSafeOrderedReferenceSet { + } + + public void finishRawIterator() { +- if (--this.iteratorCount == 0) { ++ if (this.iteratorCount.decrementAndGet() == 0) { // DivineMC - Pufferfish: Optimize mob spawning + if (this.getFragFactor() >= this.maxFragFactor) { + this.defrag(); + } +@@ -137,7 +137,7 @@ public final class IteratorSafeOrderedReferenceSet { + throw new IllegalStateException(); + } + this.listElements[index] = null; +- if (this.iteratorCount == 0 && this.getFragFactor() >= this.maxFragFactor) { ++ if (this.iteratorCount.get() == 0 && this.getFragFactor() >= this.maxFragFactor) { // DivineMC - Pufferfish: Optimize mob spawning + this.defrag(); + } + //this.check(); +@@ -235,7 +235,7 @@ public final class IteratorSafeOrderedReferenceSet { + } + + public IteratorSafeOrderedReferenceSet.Iterator iterator(final int flags) { +- ++this.iteratorCount; ++ this.iteratorCount.incrementAndGet(); // DivineMC - Pufferfish: Optimize mob spawning + return new BaseIterator<>(this, true, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize); + } + diff --git a/divinemc-server/src/main/java/gg/pufferfish/pufferfish/util/IterableWrapper.java b/divinemc-server/src/main/java/gg/pufferfish/pufferfish/util/IterableWrapper.java new file mode 100644 index 0000000..08e75cd --- /dev/null +++ b/divinemc-server/src/main/java/gg/pufferfish/pufferfish/util/IterableWrapper.java @@ -0,0 +1,13 @@ +package gg.pufferfish.pufferfish.util; + +import java.util.Iterator; + +import org.jetbrains.annotations.NotNull; + +public record IterableWrapper(Iterator iterator) implements Iterable { + @NotNull + @Override + public Iterator iterator() { + return iterator; + } +} diff --git a/patches/work/server/minecraft/0008-Misc-Optimizations.patch b/patches/work/server/minecraft/0008-Misc-Optimizations.patch deleted file mode 100644 index 44ea716..0000000 --- a/patches/work/server/minecraft/0008-Misc-Optimizations.patch +++ /dev/null @@ -1,741 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Fri, 31 Jan 2025 21:50:46 +0300 -Subject: [PATCH] Misc Optimizations - - -diff --git a/com/mojang/math/Transformation.java b/com/mojang/math/Transformation.java -index 5fb382be4d86328690c49f2a5a0c3ec698a38e21..f333d9028f315e7912dd335c8158abd525c27ecd 100644 ---- a/com/mojang/math/Transformation.java -+++ b/com/mojang/math/Transformation.java -@@ -52,6 +52,7 @@ public final class Transformation { - } else { - this.matrix = matrix; - } -+ ensureDecomposed(); // DivineMC - Math Optimizations - } - - public Transformation(@Nullable Vector3f translation, @Nullable Quaternionf leftRotation, @Nullable Vector3f scale, @Nullable Quaternionf rightRotation) { -@@ -61,6 +62,7 @@ public final class Transformation { - this.scale = scale != null ? scale : new Vector3f(1.0F, 1.0F, 1.0F); - this.rightRotation = rightRotation != null ? rightRotation : new Quaternionf(); - this.decomposed = true; -+ ensureDecomposed(); // DivineMC - Math Optimizations - } - - public static Transformation identity() { -diff --git a/net/minecraft/core/MappedRegistry.java b/net/minecraft/core/MappedRegistry.java -index 4715a60760c2c9079313db9016000bfb5c65e070..fce8f1caca81f47f704bc0237147e9999cc5732c 100644 ---- a/net/minecraft/core/MappedRegistry.java -+++ b/net/minecraft/core/MappedRegistry.java -@@ -33,10 +33,12 @@ public class MappedRegistry implements WritableRegistry { - private final ResourceKey> key; - private final ObjectList> byId = new ObjectArrayList<>(256); - private final Reference2IntMap toId = Util.make(new Reference2IntOpenHashMap<>(2048), map -> map.defaultReturnValue(-1)); // Paper - Perf: Use bigger expected size to reduce collisions -- private final Map> byLocation = new HashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions -- private final Map, Holder.Reference> byKey = new HashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions -- private final Map> byValue = new IdentityHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions -- private final Map, RegistrationInfo> registrationInfos = new IdentityHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions -+ // DivineMC start - Some optimizations -+ private final Map> byLocation = new java.util.concurrent.ConcurrentHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions -+ private final Map, Holder.Reference> byKey = new java.util.concurrent.ConcurrentHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions -+ private final Map> byValue = Collections.synchronizedMap(new IdentityHashMap<>(2048)); // Paper - Perf: Use bigger expected size to reduce collisions -+ private final Map, RegistrationInfo> registrationInfos = Collections.synchronizedMap(new IdentityHashMap<>(2048)); // Paper - Perf: Use bigger expected size to reduce collisions -+ // DivineMC end - Some optimizations - private Lifecycle registryLifecycle; - private final Map, HolderSet.Named> frozenTags = new IdentityHashMap<>(); - MappedRegistry.TagSet allTags = MappedRegistry.TagSet.unbound(); -diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index e72eda830644851656fae3118c513d7bd701be45..cdacbfa64bda461d4f24c2a85db9feae7766b597 100644 ---- a/net/minecraft/network/Connection.java -+++ b/net/minecraft/network/Connection.java -@@ -601,13 +601,7 @@ public class Connection extends SimpleChannelInboundHandler> { - if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) - || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING - || Connection.joinAttemptsThisTick++ < MAX_PER_TICK) { -- // Paper start - detailed watchdog information -- net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener); -- try { - tickablePacketListener.tick(); -- } finally { -- net.minecraft.network.protocol.PacketUtils.packetProcessing.pop(); -- } // Paper end - detailed watchdog information - } // Paper end - Buffer joins to world - } - -diff --git a/net/minecraft/network/VarInt.java b/net/minecraft/network/VarInt.java -index 4897ff4648083ebe737ae5b32bae344af27357e4..0d103821d7220daa5cc0d5d3231e794fca0ca055 100644 ---- a/net/minecraft/network/VarInt.java -+++ b/net/minecraft/network/VarInt.java -@@ -52,16 +52,43 @@ public class VarInt { - - public static ByteBuf write(ByteBuf buffer, int value) { - // Paper start - Optimize VarInts -- // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes -- // that the proxy will write, to improve inlining. -- if ((value & (0xFFFFFFFF << 7)) == 0) { -- buffer.writeByte(value); -- } else if ((value & (0xFFFFFFFF << 14)) == 0) { -- int w = (value & 0x7F | 0x80) << 8 | (value >>> 7); -- buffer.writeShort(w); -- } else { -- writeOld(buffer, value); -+ // DivineMC start - Misc optimizations -+ int bytesNeeded = getByteSize(value); -+ -+ switch (bytesNeeded) { -+ case 1: -+ buffer.writeByte(value); -+ break; -+ case 2: -+ int w2 = ((value & 0x7F) << 8) | (value >>> 7) | 0x00008000; -+ buffer.writeShort(w2); -+ break; -+ case 3: -+ int w3 = (value & 0x7F) << 16 -+ | (value & 0x3F80) << 1 -+ | (value >>> 14) -+ | 0x00808000; -+ buffer.writeMedium(w3); -+ break; -+ case 4: -+ int w4 = (value & 0x7F) << 24 -+ | ((value & 0x3F80) << 9) -+ | (value & 0x1FC000) >> 6 -+ | (value >>> 21) -+ | 0x80808000; -+ buffer.writeInt(w4); -+ break; -+ case 5: -+ int w5 = (value & 0x7F) << 24 -+ | (value & 0x3F80) << 9 -+ | (value & 0x1FC000) >> 6 -+ | ((value >>> 21) & 0x7F) -+ | 0x80808080; -+ buffer.writeInt(w5); -+ buffer.writeByte(value >>> 28); -+ break; - } -+ // DivineMC end - Slightly optimized VarInt#write - return buffer; - } - public static ByteBuf writeOld(ByteBuf buffer, int value) { -diff --git a/net/minecraft/network/protocol/PacketUtils.java b/net/minecraft/network/protocol/PacketUtils.java -index 4535858701b2bb232b9d2feb2af6551526232ddc..e65c62dbe4c1560ae153e4c4344e9194c783a2f4 100644 ---- a/net/minecraft/network/protocol/PacketUtils.java -+++ b/net/minecraft/network/protocol/PacketUtils.java -@@ -21,8 +21,6 @@ public class PacketUtils { - public static void ensureRunningOnSameThread(Packet packet, T processor, BlockableEventLoop executor) throws RunningOnDifferentThreadException { - if (!executor.isSameThread()) { - executor.executeIfPossible(() -> { -- packetProcessing.push(processor); // Paper - detailed watchdog information -- try { // Paper - detailed watchdog information - if (processor instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // Paper - Don't handle sync packets for kicked players - if (processor.shouldHandleMessage(packet)) { - try { -@@ -37,12 +35,6 @@ public class PacketUtils { - } else { - LOGGER.debug("Ignoring packet due to disconnection: {}", packet); - } -- // Paper start - detailed watchdog information -- } finally { -- totalMainThreadPacketsProcessed.getAndIncrement(); -- packetProcessing.pop(); -- } -- // Paper end - detailed watchdog information - }); - throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD; - } -@@ -69,22 +61,4 @@ public class PacketUtils { - - packetListener.fillCrashReport(crashReport); - } -- -- // Paper start - detailed watchdog information -- public static final java.util.concurrent.ConcurrentLinkedDeque packetProcessing = new java.util.concurrent.ConcurrentLinkedDeque<>(); -- static final java.util.concurrent.atomic.AtomicLong totalMainThreadPacketsProcessed = new java.util.concurrent.atomic.AtomicLong(); -- -- public static long getTotalProcessedPackets() { -- return totalMainThreadPacketsProcessed.get(); -- } -- -- public static java.util.List getCurrentPacketProcessors() { -- java.util.List listeners = new java.util.ArrayList<>(4); -- for (PacketListener listener : packetProcessing) { -- listeners.add(listener); -- } -- -- return listeners; -- } -- // Paper end - detailed watchdog information - } -diff --git a/net/minecraft/server/level/ChunkTrackingView.java b/net/minecraft/server/level/ChunkTrackingView.java -index bee90335677f7d8b01589ce5cfd81a40fd422886..a5e488d14fd2016ee188b114d0e681562b5b09cc 100644 ---- a/net/minecraft/server/level/ChunkTrackingView.java -+++ b/net/minecraft/server/level/ChunkTrackingView.java -@@ -73,12 +73,12 @@ public interface ChunkTrackingView { - } - - static boolean isWithinDistance(int centerX, int centerZ, int viewDistance, int x, int z, boolean includeOuterChunksAdjacentToViewBorder) { -- int i = includeOuterChunksAdjacentToViewBorder ? 2 : 1; -- long l = Math.max(0, Math.abs(x - centerX) - i); -- long l1 = Math.max(0, Math.abs(z - centerZ) - i); -- long l2 = l * l + l1 * l1; -- int i1 = viewDistance * viewDistance; -- return l2 < i1; -+ // DivineMC start - Some optimizations -+ int actualViewDistance = viewDistance + (includeOuterChunksAdjacentToViewBorder ? 1 : 0); -+ int xDistance = Math.abs(centerX - x); -+ int zDistance = Math.abs(centerZ - z); -+ return xDistance <= actualViewDistance && zDistance <= actualViewDistance; -+ // DivineMC end - Some optimizations - } - - public record Positioned(ChunkPos center, int viewDistance) implements ChunkTrackingView { -diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 75c8ce32e68f92e20201e9c243f46f2be716eac8..879d6eb8e72b63bc95d8028cbc2f6e93e516ab1d 100644 ---- a/net/minecraft/server/level/ServerChunkCache.java -+++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -567,8 +567,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - try { - this.chunkMap.collectSpawningChunks(list); - // Paper start - chunk tick iteration optimisation -- this.shuffleRandom.setSeed(this.level.random.nextLong()); -- if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled -+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { -+ this.shuffleRandom.setSeed(this.level.random.nextLong()); // DivineMC - Misc Optimizations -+ Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled -+ } - // Paper end - chunk tick iteration optimisation - - for (LevelChunk levelChunk : list) { -diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 2560799fe6ec006916a2bc9915355a358ab6c8bb..740f6324eeb4021bc45d27d6145ff71282c761c2 100644 ---- a/net/minecraft/server/level/ServerLevel.java -+++ b/net/minecraft/server/level/ServerLevel.java -@@ -1321,13 +1321,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // Paper end - log detailed entity tick information - - public void tickNonPassenger(Entity entity) { -- // Paper start - log detailed entity tick information - ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot tick an entity off-main"); -- try { -- if (currentlyTickingEntity.get() == null) { -- currentlyTickingEntity.lazySet(entity); -- } -- // Paper end - log detailed entity tick information - entity.setOldPosAndRot(); - entity.tickCount++; - entity.totalEntityAge++; // Paper - age-like counter for all entities -@@ -1340,13 +1334,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - for (Entity entity1 : entity.getPassengers()) { - this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 - } -- // Paper start - log detailed entity tick information -- } finally { -- if (currentlyTickingEntity.get() == entity) { -- currentlyTickingEntity.lazySet(null); -- } -- } -- // Paper end - log detailed entity tick information - } - - private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2 -diff --git a/net/minecraft/util/ClassInstanceMultiMap.java b/net/minecraft/util/ClassInstanceMultiMap.java -index 2a708ae0d5bb209650b525e3c56051f8b5655074..4c7670224f0c90c1d0d833ff0b3d908846133b4a 100644 ---- a/net/minecraft/util/ClassInstanceMultiMap.java -+++ b/net/minecraft/util/ClassInstanceMultiMap.java -@@ -14,9 +14,9 @@ import java.util.Map.Entry; - import net.minecraft.Util; - - public class ClassInstanceMultiMap extends AbstractCollection { -- private final Map, List> byClass = Maps.newHashMap(); -+ private final Map, List> byClass = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // DivineMC - Misc Optimizations - private final Class baseClass; -- private final List allInstances = Lists.newArrayList(); -+ private final List allInstances = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // DivineMC - Misc Optimizations - - public ClassInstanceMultiMap(Class baseClass) { - this.baseClass = baseClass; -@@ -56,13 +56,27 @@ public class ClassInstanceMultiMap extends AbstractCollection { - } - - public Collection find(Class type) { -+ // DivineMC start - Some optimizations -+ List cached = this.byClass.get(type); -+ if (cached != null) return (Collection) cached; -+ - if (!this.baseClass.isAssignableFrom(type)) { - throw new IllegalArgumentException("Don't know how to search for " + type); - } else { -- List list = this.byClass -- .computeIfAbsent(type, clazz -> this.allInstances.stream().filter(clazz::isInstance).collect(Util.toMutableList())); -- return (Collection)Collections.unmodifiableCollection(list); -+ List list = this.byClass.computeIfAbsent(type, -+ typeClass -> { -+ it.unimi.dsi.fastutil.objects.ObjectArrayList ts = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(this.allInstances.size()); -+ for (Object _allElement : ((it.unimi.dsi.fastutil.objects.ObjectArrayList) this.allInstances).elements()) { -+ if (typeClass.isInstance(_allElement)) { -+ ts.add((T) _allElement); -+ } -+ } -+ return ts; -+ } -+ ); -+ return (Collection) list; - } -+ // DivineMC end - Some optimizations - } - - @Override -diff --git a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java -index f28fbf81a417a678726d3f77b3999054676d522e..7ff32b1f93b31fafd13f4e0857d14d85ef1f28c7 100644 ---- a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java -+++ b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java -@@ -52,23 +52,23 @@ public class CrudeIncrementalIntIdentityHashBiMap implements IdMap, ca.spo - - @Nullable - @Override -- public K byId(int value) { -+ public synchronized K byId(int value) { // DivineMC - Misc Optimizations - return value >= 0 && value < this.byId.length ? this.byId[value] : null; - } - -- private int getValue(int key) { -+ private synchronized int getValue(int key) { // DivineMC - Misc Optimizations - return key == -1 ? -1 : this.values[key]; - } - -- public boolean contains(K value) { -+ public synchronized boolean contains(K value) { // DivineMC - Misc Optimizations - return this.getId(value) != -1; - } - -- public boolean contains(int value) { -+ public synchronized boolean contains(int value) { // DivineMC - Misc Optimizations - return this.byId(value) != null; - } - -- public int add(K object) { -+ public synchronized int add(K object) { // DivineMC - Misc Optimizations - int i = this.nextId(); - this.addMapping(object, i); - return i; -@@ -106,7 +106,7 @@ public class CrudeIncrementalIntIdentityHashBiMap implements IdMap, ca.spo - // Paper end - optimise palette reads - } - -- public void addMapping(K object, int intKey) { -+ public synchronized void addMapping(K object, int intKey) { // DivineMC - Misc Optimizations - int max = Math.max(intKey, this.size + 1); - if (max >= this.keys.length * 0.8F) { - int i = this.keys.length << 1; -@@ -173,11 +173,11 @@ public class CrudeIncrementalIntIdentityHashBiMap implements IdMap, ca.spo - } - - @Override -- public Iterator iterator() { -+ public synchronized Iterator iterator() { // DivineMC - Misc Optimizations - return Iterators.filter(Iterators.forArray(this.byId), Predicates.notNull()); - } - -- public void clear() { -+ public synchronized void clear() { // DivineMC - Misc Optimizations - Arrays.fill(this.keys, null); - Arrays.fill(this.byId, null); - this.nextId = 0; -diff --git a/net/minecraft/util/Mth.java b/net/minecraft/util/Mth.java -index e2602c6d817794616eb05a471077447804b835a1..d5a9fd918621708c5bcbf56e33513a6765122d1c 100644 ---- a/net/minecraft/util/Mth.java -+++ b/net/minecraft/util/Mth.java -@@ -46,11 +46,11 @@ public class Mth { - private static final double[] COS_TAB = new double[257]; - - public static float sin(float value) { -- return SIN[(int)(value * 10430.378F) & 65535]; -+ return net.caffeinemc.mods.lithium.common.util.math.CompactSineLUT.sin(value); // DivineMC - Math Optimizations - } - - public static float cos(float value) { -- return SIN[(int)(value * 10430.378F + 16384.0F) & 65535]; -+ return net.caffeinemc.mods.lithium.common.util.math.CompactSineLUT.cos(value); // DivineMC - Math Optimizations - } - - public static float sqrt(float value) { -@@ -58,18 +58,15 @@ public class Mth { - } - - public static int floor(float value) { -- int i = (int)value; -- return value < i ? i - 1 : i; -+ return (int) Math.floor(value); // DivineMC - Math Optimizations - } - - public static int floor(double value) { -- int i = (int)value; -- return value < i ? i - 1 : i; -+ return (int) Math.floor(value); // DivineMC - Math Optimizations - } - - public static long lfloor(double value) { -- long l = (long)value; -- return value < l ? l - 1L : l; -+ return (long) Math.floor(value); // DivineMC - Math Optimizations - } - - public static float abs(float value) { -@@ -81,13 +78,11 @@ public class Mth { - } - - public static int ceil(float value) { -- int i = (int)value; -- return value > i ? i + 1 : i; -+ return (int) Math.ceil(value); // DivineMC - Math Optimizations - } - - public static int ceil(double value) { -- int i = (int)value; -- return value > i ? i + 1 : i; -+ return (int) Math.ceil(value); // DivineMC - Math Optimizations - } - - public static int clamp(int value, int min, int max) { -@@ -123,15 +118,7 @@ public class Mth { - } - - public static double absMax(double x, double y) { -- if (x < 0.0) { -- x = -x; -- } -- -- if (y < 0.0) { -- y = -y; -- } -- -- return Math.max(x, y); -+ return Math.max(Math.abs(x), Math.abs(y)); // DivineMC - Math Optimizations - } - - public static int floorDiv(int dividend, int divisor) { -@@ -162,14 +149,26 @@ public class Mth { - return Math.floorMod(x, y); - } - -- public static float positiveModulo(float numerator, float denominator) { -+ public static float positiveModuloForAnyDenominator(float numerator, float denominator) { // DivineMC - Math Optimizations - return (numerator % denominator + denominator) % denominator; - } - -- public static double positiveModulo(double numerator, double denominator) { -+ public static double positiveModuloForAnyDenominator(double numerator, double denominator) { // DivineMC - Math Optimizations - return (numerator % denominator + denominator) % denominator; - } - -+ // DivineMC start - Math Optimizations -+ public static float positiveModuloForPositiveIntegerDenominator(float numerator, float denominator) { -+ var modulo = numerator % denominator; -+ return modulo < 0 ? modulo + denominator : modulo; -+ } -+ -+ public static double positiveModuloForPositiveIntegerDenominator(double numerator, double denominator) { -+ var modulo = numerator % denominator; -+ return modulo < 0 ? modulo + denominator : modulo; -+ } -+ // DivineMC end - Math Optimizations -+ - public static boolean isMultipleOf(int number, int multiple) { - return number % multiple == 0; - } -diff --git a/net/minecraft/util/RandomSource.java b/net/minecraft/util/RandomSource.java -index 8516d47b0ba79d91638837199e7ae0fb6cb44a79..71444431b10582f5917c1795275ccdadd2364c3c 100644 ---- a/net/minecraft/util/RandomSource.java -+++ b/net/minecraft/util/RandomSource.java -@@ -12,7 +12,7 @@ public interface RandomSource { - double GAUSSIAN_SPREAD_FACTOR = 2.297; - - static RandomSource create() { -- return create(RandomSupport.generateUniqueSeed()); -+ return createThreadSafe(); // DivineMC - Misc Optimizations - } - - @Deprecated -@@ -21,7 +21,7 @@ public interface RandomSource { - } - - static RandomSource create(long seed) { -- return new LegacyRandomSource(seed); -+ return new ThreadSafeLegacyRandomSource(seed); // DivineMC - Misc Optimizations - } - - static RandomSource createNewThreadLocalInstance() { -diff --git a/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java b/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java -index a18240418a19a95147341a634527d774f3d5bb92..66f74ad2a194a6676574da2932cf4677f9383ecd 100644 ---- a/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java -+++ b/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java -@@ -14,7 +14,7 @@ public class DebugSampleSubscriptionTracker { - public static final int STOP_SENDING_AFTER_MS = 10000; - private final PlayerList playerList; - private final Map> subscriptions; -- private final Queue subscriptionRequestQueue = new LinkedList<>(); -+ private final java.util.List subscriptionRequestQueue = java.util.Collections.synchronizedList(new LinkedList<>()); // DivineMC - Misc Optimizations - - public DebugSampleSubscriptionTracker(PlayerList playerList) { - this.playerList = playerList; -diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index f8b37b4ce54afd61a72e9d18ac323540431c655d..0f28bc38d8dcb1b68ee7ae05c0c95ca86865c8ba 100644 ---- a/net/minecraft/world/entity/Entity.java -+++ b/net/minecraft/world/entity/Entity.java -@@ -155,7 +155,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - // Paper start - Share random for entities to make them more random -- public static RandomSource SHARED_RANDOM = new RandomRandomSource(); -+ public static RandomSource SHARED_RANDOM = new net.minecraft.world.level.levelgen.ThreadSafeLegacyRandomSource(net.minecraft.world.level.levelgen.RandomSupport.generateUniqueSeed()); // DivineMC - Misc Optimizations - // Paper start - replace random - private static final class RandomRandomSource extends ca.spottedleaf.moonrise.common.util.ThreadUnsafeRandom { - public RandomRandomSource() { -@@ -1108,28 +1108,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return this.onGround; - } - -- // Paper start - detailed watchdog information -- public final Object posLock = new Object(); // Paper - log detailed entity tick information -- -- @Nullable -- private Vec3 moveVector; -- private double moveStartX; -- private double moveStartY; -- private double moveStartZ; -- // Paper end - detailed watchdog information -- - public void move(MoverType type, Vec3 movement) { - final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity -- // Paper start - detailed watchdog information - ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); -- synchronized (this.posLock) { -- this.moveStartX = this.getX(); -- this.moveStartY = this.getY(); -- this.moveStartZ = this.getZ(); -- this.moveVector = movement; -- } -- try { -- // Paper end - detailed watchdog information - if (this.noPhysics) { - this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); - } else { -@@ -1244,13 +1225,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.setDeltaMovement(this.getDeltaMovement().multiply(blockSpeedFactor, 1.0, blockSpeedFactor)); - } - } -- // Paper start - detailed watchdog information -- } finally { -- synchronized (this.posLock) { // Paper -- this.moveVector = null; -- } // Paper -- } -- // Paper end - detailed watchdog information - } - - private void applyMovementEmissionAndPlaySound(Entity.MovementEmission movementEmission, Vec3 movement, BlockPos pos, BlockState state) { -@@ -4922,9 +4896,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public void setDeltaMovement(Vec3 deltaMovement) { -- synchronized (this.posLock) { // Paper - detailed watchdog information - this.deltaMovement = deltaMovement; -- } // Paper - detailed watchdog information - } - - public void addDeltaMovement(Vec3 addend) { -@@ -5022,9 +4994,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - // Paper end - Block invalid positions and bounding box - if (this.position.x != x || this.position.y != y || this.position.z != z) { -- synchronized (this.posLock) { // Paper - detailed watchdog information - this.position = new Vec3(x, y, z); -- } // Paper - detailed watchdog information - int floor = Mth.floor(x); - int floor1 = Mth.floor(y); - int floor2 = Mth.floor(z); -diff --git a/net/minecraft/world/entity/ExperienceOrb.java b/net/minecraft/world/entity/ExperienceOrb.java -index c8354d46ed909090f7c15f396863bf7d73afcefa..382ef2dad5e995bc01f6492218b8c8f7a930d6ac 100644 ---- a/net/minecraft/world/entity/ExperienceOrb.java -+++ b/net/minecraft/world/entity/ExperienceOrb.java -@@ -195,6 +195,7 @@ public class ExperienceOrb extends Entity { - if (this.age >= 6000) { - this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } -+ if (this.count == 0) this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // DivineMC - discard when count is 0 - } - } - -diff --git a/net/minecraft/world/level/GameRules.java b/net/minecraft/world/level/GameRules.java -index d510503a8ad272255aeba20a916642828023fd19..2d9bf302b779602d733187c6f86e52467f0dc540 100644 ---- a/net/minecraft/world/level/GameRules.java -+++ b/net/minecraft/world/level/GameRules.java -@@ -288,7 +288,7 @@ public class GameRules { - } - - private GameRules(Map, GameRules.Value> rules, FeatureFlagSet enabledFeatures) { -- this.rules = rules; -+ this.rules = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(rules); // DivineMC - lithium: collections.gamerules - this.enabledFeatures = enabledFeatures; - - // Paper start - Perf: Use array for gamerule storage -diff --git a/net/minecraft/world/level/LocalMobCapCalculator.java b/net/minecraft/world/level/LocalMobCapCalculator.java -index 9641219c190261dea0db5f95f040a705ba0a3ff9..a3fccdeb2c076e12b611683da55d45e00a166417 100644 ---- a/net/minecraft/world/level/LocalMobCapCalculator.java -+++ b/net/minecraft/world/level/LocalMobCapCalculator.java -@@ -13,16 +13,24 @@ import net.minecraft.world.entity.MobCategory; - - public class LocalMobCapCalculator { - private final Long2ObjectMap> playersNearChunk = new Long2ObjectOpenHashMap<>(); -- private final Map playerMobCounts = Maps.newHashMap(); -+ private final Map playerMobCounts = Maps.newConcurrentMap(); // DivineMC - Misc Optimizations - private final ChunkMap chunkMap; - - public LocalMobCapCalculator(ChunkMap chunkMap) { - this.chunkMap = chunkMap; - } - -- private List getPlayersNear(ChunkPos pos) { -- return this.playersNearChunk.computeIfAbsent(pos.toLong(), key -> this.chunkMap.getPlayersCloseForSpawning(pos)); -+ // DivineMC start - Some optimizations -+ private synchronized @org.jetbrains.annotations.NotNull List getPlayersNear(ChunkPos pos) { -+ List retVal = this.playersNearChunk.get(pos.toLong()); -+ if (retVal == null) { -+ List newVal = this.chunkMap.getPlayersCloseForSpawning(pos); -+ this.playersNearChunk.put(pos.toLong(), newVal); -+ return newVal; -+ } -+ return retVal; - } -+ // DivineMC end - Some optimizations - - public void addMob(ChunkPos pos, MobCategory category) { - for (ServerPlayer serverPlayer : this.getPlayersNear(pos)) { -@@ -42,14 +50,14 @@ public class LocalMobCapCalculator { - } - - static class MobCounts { -- private final Object2IntMap counts = new Object2IntOpenHashMap<>(MobCategory.values().length); -+ private final int[] spawnGroupDensities = new int[MobCategory.values().length]; // DivineMC - Misc Optimizations - - public void add(MobCategory category) { -- this.counts.computeInt(category, (key, value) -> value == null ? 1 : value + 1); -+ this.spawnGroupDensities[category.ordinal()] ++; // DivineMC - Misc Optimizations - } - - public boolean canSpawn(MobCategory category) { -- return this.counts.getOrDefault(category, 0) < category.getMaxInstancesPerChunk(); -+ return this.spawnGroupDensities[category.ordinal()] < category.getMaxInstancesPerChunk(); // DivineMC - Misc Optimizations - } - } - } -diff --git a/net/minecraft/world/level/levelgen/blending/Blender.java b/net/minecraft/world/level/levelgen/blending/Blender.java -index 01e5b29d6e9a5c53c0e23b61ed0c1d7be1a0fe08..d80df05e40f3941ade5ed320e12f8dcf47e6b247 100644 ---- a/net/minecraft/world/level/levelgen/blending/Blender.java -+++ b/net/minecraft/world/level/levelgen/blending/Blender.java -@@ -144,7 +144,7 @@ public class Blender { - private static double heightToOffset(double height) { - double d = 1.0; - double d1 = height + 0.5; -- double d2 = Mth.positiveModulo(d1, 8.0); -+ double d2 = Mth.positiveModuloForPositiveIntegerDenominator(d1, 8.0); // DivineMC - Math optimizations - return 1.0 * (32.0 * (d1 - 128.0) - 3.0 * (d1 - 120.0) * d2 + 3.0 * d2 * d2) / (128.0 * (32.0 - 3.0 * d2)); - } - -diff --git a/net/minecraft/world/level/levelgen/feature/OreFeature.java b/net/minecraft/world/level/levelgen/feature/OreFeature.java -index c7b46efd4f08067e2c9c5c8b0e8b71a94a79823d..c7252c636fcea34a866dcc4862b60cef31071666 100644 ---- a/net/minecraft/world/level/levelgen/feature/OreFeature.java -+++ b/net/minecraft/world/level/levelgen/feature/OreFeature.java -@@ -69,7 +69,7 @@ public class OreFeature extends Feature { - int height - ) { - int i = 0; -- BitSet bitSet = new BitSet(width * height * width); -+ BitSet bitSet = org.bxteam.divinemc.util.cache.CachedOrNewBitsGetter.getCachedOrNewBitSet(width * height * width); // DivineMC - Misc Optimizations - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); - int i1 = config.size; - double[] doubles = new double[i1 * 4]; -diff --git a/net/minecraft/world/level/storage/DimensionDataStorage.java b/net/minecraft/world/level/storage/DimensionDataStorage.java -index 1ff0b19a077333ad9da9cab7f5a891eeaa2109a9..b82be2c9576b7d41d104b0c44237a01e678811d5 100644 ---- a/net/minecraft/world/level/storage/DimensionDataStorage.java -+++ b/net/minecraft/world/level/storage/DimensionDataStorage.java -@@ -39,7 +39,7 @@ import org.slf4j.Logger; - public class DimensionDataStorage implements AutoCloseable { - private static final Logger LOGGER = LogUtils.getLogger(); - private final SavedData.Context context; -- public final Map, Optional> cache = new HashMap<>(); -+ public final Map, Optional> cache = new java.util.concurrent.ConcurrentHashMap<>(); // DivineMC - Misc Optimizations - private final DataFixer fixerUpper; - private final HolderLookup.Provider registries; - private final Path dataFolder; -diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java -index e53398996bbb278c6e06024d8ca945b364a44c10..f60c1ab58a2e9adfb01e9bd430b92cd1902e5dbe 100644 ---- a/net/minecraft/world/phys/AABB.java -+++ b/net/minecraft/world/phys/AABB.java -@@ -190,13 +190,15 @@ public class AABB { - } - - public AABB intersect(AABB other) { -- double max = Math.max(this.minX, other.minX); -- double max1 = Math.max(this.minY, other.minY); -- double max2 = Math.max(this.minZ, other.minZ); -- double min = Math.min(this.maxX, other.maxX); -- double min1 = Math.min(this.maxY, other.maxY); -- double min2 = Math.min(this.maxZ, other.maxZ); -- return new AABB(max, max1, max2, min, min1, min2); -+ // DivineMC start - Math Optimizations -+ return new AABB( -+ this.minX > other.minX ? this.minX : other.minX, -+ this.minY > other.minY ? this.minY : other.minY, -+ this.minZ > other.minZ ? this.minZ : other.minZ, -+ this.maxX < other.maxX ? this.maxX : other.maxX, -+ this.maxY < other.maxY ? this.maxY : other.maxY, -+ this.maxZ < other.maxZ ? this.maxZ : other.maxZ -+ ); - } - - public AABB minmax(AABB other) { -@@ -228,16 +230,37 @@ public class AABB { - } - - public boolean intersects(AABB other) { -- return this.intersects(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ); -+ // DivineMC start - Math Optimizations -+ return this.minX < other.maxX && -+ this.maxX > other.minX && -+ this.minY < other.maxY && -+ this.maxY > other.minY && -+ this.minZ < other.maxZ && -+ this.maxZ > other.minZ; -+ // DivineMC end - Math Optimizations - } - - public boolean intersects(double x1, double y1, double z1, double x2, double y2, double z2) { -- return this.minX < x2 && this.maxX > x1 && this.minY < y2 && this.maxY > y1 && this.minZ < z2 && this.maxZ > z1; -+ // DivineMC start - Math Optimizations -+ return this.minX < x2 && -+ this.maxX > x1 && -+ this.minY < y2 && -+ this.maxY > y1 && -+ this.minZ < z2 && -+ this.maxZ > z1; -+ // DivineMC end - Math Optimizations - } - - public boolean intersects(Vec3 min, Vec3 max) { - return this.intersects( -- Math.min(min.x, max.x), Math.min(min.y, max.y), Math.min(min.z, max.z), Math.max(min.x, max.x), Math.max(min.y, max.y), Math.max(min.z, max.z) -+ // DivineMC start - Math Optimizations -+ min.x < max.x ? min.x : max.x, -+ min.y < max.y ? min.y : max.y, -+ min.z < max.z ? min.z : max.z, -+ min.x > max.x ? min.x : max.x, -+ min.y > max.y ? min.y : max.y, -+ min.z > max.z ? min.z : max.z -+ // DivineMC end - Math Optimizations - ); - } - diff --git a/patches/work/server/paper/0008-Configurable-thread-pool-priority.patch b/patches/work/server/paper/0008-Configurable-thread-pool-priority.patch deleted file mode 100644 index 213ae7e..0000000 --- a/patches/work/server/paper/0008-Configurable-thread-pool-priority.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 23 Feb 2025 00:43:23 +0300 -Subject: [PATCH] Configurable thread pool priority - - -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java -index 03e7344661b6aea258918bd388dc0e4e6fb5bc96..098b50751d805f03cad5e94e8ed04a20697a51cc 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java -@@ -75,6 +75,7 @@ public final class MoonriseCommon { - LOGGER.error("Uncaught exception in thread {}", thread.getName(), throwable); - } - }); -+ thread.setPriority(DivineConfig.PerformanceCategory.threadPoolPriority); // DivineMC - Configurable thread pool priority - } - } - ); diff --git a/patches/work/server/paper/0009-Virtual-Threads.patch b/patches/work/server/paper/0009-Virtual-Threads.patch deleted file mode 100644 index 80f48f8..0000000 --- a/patches/work/server/paper/0009-Virtual-Threads.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Mon, 24 Feb 2025 19:36:33 +0300 -Subject: [PATCH] Virtual Threads - - -diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index 8492a06883e2ff597bbbdaa74fe5e5cdd0a0a1b1..862e49f510720f3546c339f5c4cf1945303dd8c9 100644 ---- a/src/main/java/io/papermc/paper/util/MCUtil.java -+++ b/src/main/java/io/papermc/paper/util/MCUtil.java -@@ -37,7 +37,7 @@ public final class MCUtil { - run.run(); - } - }; -- public static final ExecutorService ASYNC_EXECUTOR = Executors.newFixedThreadPool(2, new ThreadFactoryBuilder() -+ public static final ExecutorService ASYNC_EXECUTOR = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualAsyncExecutor ? Executors.newVirtualThreadPerTaskExecutor() : Executors.newFixedThreadPool(2, new ThreadFactoryBuilder() // DivineMC - Virtual Threads - .setNameFormat("Paper Async Task Handler Thread - %1$d") - .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) - .build() -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java -index 0ca279fb71d39c81b1f608e0ee9ba3e498d55fa3..8f82c034de320af7b65bad1602ebb561dd844e59 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java -@@ -31,14 +31,18 @@ import java.util.ArrayList; - import java.util.Iterator; - import java.util.List; - import java.util.concurrent.Executor; -+import java.util.concurrent.ExecutorService; - import java.util.concurrent.Executors; - import java.util.concurrent.SynchronousQueue; - import java.util.concurrent.ThreadPoolExecutor; - import java.util.concurrent.TimeUnit; - - public class CraftAsyncScheduler extends CraftScheduler { -- -- private final ThreadPoolExecutor executor = new ThreadPoolExecutor( -+ // DivineMC start - Virtual Threads -+ private final ExecutorService executor = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualBukkitScheduler -+ ? Executors.newVirtualThreadPerTaskExecutor() -+ : new ThreadPoolExecutor( -+ // DivineMC end - Virtual Threads - 4, Integer.MAX_VALUE,30L, TimeUnit.SECONDS, new SynchronousQueue<>(), - new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build()); - private final Executor management = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder() -@@ -47,8 +51,12 @@ public class CraftAsyncScheduler extends CraftScheduler { - - CraftAsyncScheduler() { - super(true); -- executor.allowCoreThreadTimeOut(true); -- executor.prestartAllCoreThreads(); -+ // DivineMC start - Virtual Threads -+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && !org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualBukkitScheduler) { -+ ((ThreadPoolExecutor) executor).allowCoreThreadTimeOut(true); -+ ((ThreadPoolExecutor) executor).prestartAllCoreThreads(); -+ } -+ // DivineMC end - Virtual Threads - } - - @Override From a679c78a0dde5baa8877baa22d3cd2e4d2354f18 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 9 Jul 2025 03:27:50 +0300 Subject: [PATCH 11/67] big applies :fire: --- ...er-ShapelessRecipes-comparison-for-V.patch | 68 + .../0076-C2ME-Density-Function-Compiler.patch | 8 +- .../features/0077-Clump-experience-orbs.patch | 14 +- ...-SparklyPaper-Parallel-world-ticking.patch | 93 +- .../0079-MSPT-Tracking-for-each-world.patch | 4 +- .../0080-Catch-update-suppressors.patch | 6 +- ...er-ShapelessRecipes-comparison-for-V.patch | 26 + ...-SparklyPaper-Parallel-world-ticking.patch | 3 +- .../0004-MSPT-Tracking-for-each-world.patch | 0 .../0010-Chunk-System-Optimizations.patch | 3679 ----------------- ...ch => 0078-Regionized-Chunk-Ticking.patch} | 65 +- .../0006-Chunk-System-Optimizations.patch | 693 ---- 12 files changed, 189 insertions(+), 4470 deletions(-) create mode 100644 divinemc-server/minecraft-patches/features/0075-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch rename patches/work/server/minecraft/0044-Density-Function-Compiler.patch => divinemc-server/minecraft-patches/features/0076-C2ME-Density-Function-Compiler.patch (99%) rename patches/work/server/minecraft/0055-Clump-experience-orbs.patch => divinemc-server/minecraft-patches/features/0077-Clump-experience-orbs.patch (96%) rename patches/work/server/minecraft/0045-Parallel-world-ticking.patch => divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch (96%) rename patches/work/server/minecraft/0046-MSPT-Tracking-for-each-world.patch => divinemc-server/minecraft-patches/features/0079-MSPT-Tracking-for-each-world.patch (91%) rename patches/work/server/minecraft/0048-Catch-update-suppressors.patch => divinemc-server/minecraft-patches/features/0080-Catch-update-suppressors.patch (95%) create mode 100644 divinemc-server/paper-patches/features/0018-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch rename patches/work/server/paper/0014-Parallel-world-ticking.patch => divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch (99%) rename patches/work/server/purpur/0003-MSPT-Tracking-for-each-world.patch => divinemc-server/purpur-patches/features/0004-MSPT-Tracking-for-each-world.patch (100%) delete mode 100644 patches/work/server/minecraft/0010-Chunk-System-Optimizations.patch rename patches/work/server/minecraft/{0009-Regionized-Chunk-Ticking.patch => 0078-Regionized-Chunk-Ticking.patch} (94%) delete mode 100644 patches/work/server/paper/0006-Chunk-System-Optimizations.patch diff --git a/divinemc-server/minecraft-patches/features/0075-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch b/divinemc-server/minecraft-patches/features/0075-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch new file mode 100644 index 0000000..693fc2f --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0075-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 9 Jul 2025 03:06:02 +0300 +Subject: [PATCH] Pufferfish: Simpler ShapelessRecipes comparison for Vanilla + +Original license: GPL v3 +Original project: https://github.com/pufferfish-gg/Pufferfish + +Patch description: + +Paper added a fancy sorting comparison due to Bukkit recipes breaking +the vanilla one, however this is far more advanced than what you need +for all the vanilla recipes. + +diff --git a/net/minecraft/world/item/crafting/ShapelessRecipe.java b/net/minecraft/world/item/crafting/ShapelessRecipe.java +index d601b54b1de2f2ae44fe2b20c8116c71a6340e45..658c950e18a5a4ff992c8720e60f505a11ab2efd 100644 +--- a/net/minecraft/world/item/crafting/ShapelessRecipe.java ++++ b/net/minecraft/world/item/crafting/ShapelessRecipe.java +@@ -23,13 +23,21 @@ public class ShapelessRecipe implements CraftingRecipe { + final List ingredients; + @Nullable + private PlacementInfo placementInfo; ++ // DivineMC start - Pufferfish: Simpler ShapelessRecipes comparison for Vanilla ++ private final boolean isBukkit; + + public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, List ingredients) { ++ this(group, category, result, ingredients, false); ++ } ++ ++ public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, List ingredients, boolean isBukkit) { + this.group = group; + this.category = category; + this.result = result; + this.ingredients = ingredients; ++ this.isBukkit = isBukkit; + } ++ // DivineMC end - Pufferfish: Simpler ShapelessRecipes comparison for Vanilla + + // CraftBukkit start + @Override +@@ -72,6 +80,27 @@ public class ShapelessRecipe implements CraftingRecipe { + + @Override + public boolean matches(CraftingInput input, Level level) { ++ // DivineMC start - Pufferfish: Simpler ShapelessRecipes comparison for Vanilla ++ if (!this.isBukkit) { ++ java.util.List ingredients = com.google.common.collect.Lists.newArrayList(this.ingredients.toArray(new Ingredient[0])); ++ ++ inventory: for (int index = 0; index < input.size(); index++) { ++ ItemStack itemStack = input.getItem(index); ++ ++ if (!itemStack.isEmpty()) { ++ for (int i = 0; i < ingredients.size(); i++) { ++ if (ingredients.get(i).test(itemStack)) { ++ ingredients.remove(i); ++ continue inventory; ++ } ++ } ++ return false; ++ } ++ } ++ ++ return ingredients.isEmpty(); ++ } ++ // DivineMC end - Pufferfish: Simpler ShapelessRecipes comparison for Vanilla + // Paper start - Improve exact choice recipe ingredients & unwrap ternary + if (input.ingredientCount() != this.ingredients.size()) { + return false; diff --git a/patches/work/server/minecraft/0044-Density-Function-Compiler.patch b/divinemc-server/minecraft-patches/features/0076-C2ME-Density-Function-Compiler.patch similarity index 99% rename from patches/work/server/minecraft/0044-Density-Function-Compiler.patch rename to divinemc-server/minecraft-patches/features/0076-C2ME-Density-Function-Compiler.patch index 8bea7ab..dbdaee6 100644 --- a/patches/work/server/minecraft/0044-Density-Function-Compiler.patch +++ b/divinemc-server/minecraft-patches/features/0076-C2ME-Density-Function-Compiler.patch @@ -1,17 +1,15 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 12 Feb 2025 01:05:50 +0300 -Subject: [PATCH] Density Function Compiler - -Implements density function compiler to accelerate world generation from C2ME - -Density function: https://minecraft.wiki/w/Density_function +Subject: [PATCH] C2ME: Density Function Compiler This functionality compiles density functions from world generation datapacks (including vanilla generation) to JVM bytecode to increase performance by allowing JVM JIT to better optimize the code. All functions provided by vanilla are implemented. +About Density function: https://minecraft.wiki/w/Density_function + diff --git a/net/minecraft/util/CubicSpline.java b/net/minecraft/util/CubicSpline.java index f36f8f2d49d4eba5c80eb243883749d6f831eb8a..b43b7e242ea0a4f87704853c03201144ce355565 100644 --- a/net/minecraft/util/CubicSpline.java diff --git a/patches/work/server/minecraft/0055-Clump-experience-orbs.patch b/divinemc-server/minecraft-patches/features/0077-Clump-experience-orbs.patch similarity index 96% rename from patches/work/server/minecraft/0055-Clump-experience-orbs.patch rename to divinemc-server/minecraft-patches/features/0077-Clump-experience-orbs.patch index 9c79872..96de872 100644 --- a/patches/work/server/minecraft/0055-Clump-experience-orbs.patch +++ b/divinemc-server/minecraft-patches/features/0077-Clump-experience-orbs.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Clump experience orbs diff --git a/net/minecraft/world/entity/ExperienceOrb.java b/net/minecraft/world/entity/ExperienceOrb.java -index 382ef2dad5e995bc01f6492218b8c8f7a930d6ac..598d46010877cf31c8b6f23deecb91ce61c832b2 100644 +index c8354d46ed909090f7c15f396863bf7d73afcefa..96d22f93fc07de0fecf3249081a997c280b8fde2 100644 --- a/net/minecraft/world/entity/ExperienceOrb.java +++ b/net/minecraft/world/entity/ExperienceOrb.java @@ -50,6 +50,10 @@ public class ExperienceOrb extends Entity { @@ -19,7 +19,7 @@ index 382ef2dad5e995bc01f6492218b8c8f7a930d6ac..598d46010877cf31c8b6f23deecb91ce private void loadPaperNBT(ValueInput input) { input.read("Paper.ExpData", net.minecraft.nbt.CompoundTag.CODEC).ifPresent(expData -> { -@@ -273,6 +277,28 @@ public class ExperienceOrb extends Entity { +@@ -272,6 +276,28 @@ public class ExperienceOrb extends Entity { } private static boolean tryMergeToExisting(ServerLevel level, Vec3 pos, int amount) { @@ -48,7 +48,7 @@ index 382ef2dad5e995bc01f6492218b8c8f7a930d6ac..598d46010877cf31c8b6f23deecb91ce // Paper - TODO some other event for this kind of merge AABB aabb = AABB.ofSize(pos, 1.0, 1.0, 1.0); int randomInt = level.getRandom().nextInt(io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA)); // Paper - Configure how many orb groups per area -@@ -290,11 +316,11 @@ public class ExperienceOrb extends Entity { +@@ -289,11 +315,11 @@ public class ExperienceOrb extends Entity { } private boolean canMerge(ExperienceOrb orb) { @@ -62,7 +62,7 @@ index 382ef2dad5e995bc01f6492218b8c8f7a930d6ac..598d46010877cf31c8b6f23deecb91ce } private void merge(ExperienceOrb orb) { -@@ -303,6 +329,18 @@ public class ExperienceOrb extends Entity { +@@ -302,6 +328,18 @@ public class ExperienceOrb extends Entity { return; } // Paper end - call orb merge event @@ -81,7 +81,7 @@ index 382ef2dad5e995bc01f6492218b8c8f7a930d6ac..598d46010877cf31c8b6f23deecb91ce this.count = this.count + orb.count; this.age = Math.min(this.age, orb.age); orb.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.MERGE); // CraftBukkit - add Bukkit remove cause -@@ -344,6 +382,13 @@ public class ExperienceOrb extends Entity { +@@ -343,6 +381,13 @@ public class ExperienceOrb extends Entity { output.putInt("Value", this.getValue()); // Paper - save as Integer output.putInt("Count", this.count); this.savePaperNBT(output); // Paper @@ -95,7 +95,7 @@ index 382ef2dad5e995bc01f6492218b8c8f7a930d6ac..598d46010877cf31c8b6f23deecb91ce } @Override -@@ -353,10 +398,52 @@ public class ExperienceOrb extends Entity { +@@ -352,10 +397,52 @@ public class ExperienceOrb extends Entity { this.setValue(input.getIntOr("Value", 0)); // Paper - load as Integer this.count = input.read("Count", ExtraCodecs.POSITIVE_INT).orElse(1); this.loadPaperNBT(input); // Paper @@ -148,7 +148,7 @@ index 382ef2dad5e995bc01f6492218b8c8f7a930d6ac..598d46010877cf31c8b6f23deecb91ce if (entity instanceof ServerPlayer serverPlayer) { if (entity.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent entity.takeXpDelay = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(entity, this.level().purpurConfig.playerExpPickupDelay, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; // Purpur - Configurable player pickup exp delay -@@ -374,10 +461,60 @@ public class ExperienceOrb extends Entity { +@@ -373,10 +460,60 @@ public class ExperienceOrb extends Entity { } } diff --git a/patches/work/server/minecraft/0045-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch similarity index 96% rename from patches/work/server/minecraft/0045-Parallel-world-ticking.patch rename to divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch index 9634cc7..ae69f2c 100644 --- a/patches/work/server/minecraft/0045-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch @@ -1,16 +1,15 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 29 Jan 2025 00:59:03 +0300 -Subject: [PATCH] Parallel world ticking +Subject: [PATCH] SparklyPaper: Parallel world ticking Original project: https://github.com/SparklyPower/SparklyPaper -TODO: find the crash problem and fix it (Attempting to remove entity ... from entity slices (.., ..) that is receiving status updates) diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -index c10e31017e7dfab348e9cc45c28d3858863ac0b1..97bdfe92f32368427bff4960b8f5e39f298c00ab 100644 +index 6ce4a98e4d3b633e3c87944c23b6b3f0ff58f159..57fec1f9a210d2ecb74ff7b05cec790ae77f9178 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -@@ -1155,7 +1155,7 @@ public final class ChunkHolderManager { +@@ -1142,7 +1142,7 @@ public final class ChunkHolderManager { if (changedFullStatus.isEmpty()) { return; } @@ -18,8 +17,8 @@ index c10e31017e7dfab348e9cc45c28d3858863ac0b1..97bdfe92f32368427bff4960b8f5e39f + if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableParallelWorldTicking && !TickThread.isTickThreadFor(world) || !TickThread.isTickThread()) { // DivineMC - Parallel world ticking // These will be handled on the next ServerChunkCache$MainThreadExecutor#pollTask, as it runs the distance manager update // which will invoke processTicketUpdates - this.getData().offThreadPendingFullLoadUpdate.addAll(changedFullStatus); // DivineMC - Chunk System optimization -@@ -1176,7 +1176,13 @@ public final class ChunkHolderManager { + this.offThreadPendingFullLoadUpdate.addAll(changedFullStatus); +@@ -1163,7 +1163,13 @@ public final class ChunkHolderManager { // note: never call while inside the chunk system, this will absolutely break everything public void processUnloads() { @@ -34,7 +33,7 @@ index c10e31017e7dfab348e9cc45c28d3858863ac0b1..97bdfe92f32368427bff4960b8f5e39f if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) { throw new IllegalStateException("Cannot unload chunks recursively"); -@@ -1463,7 +1469,7 @@ public final class ChunkHolderManager { +@@ -1429,7 +1435,7 @@ public final class ChunkHolderManager { if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) { throw new IllegalStateException("Cannot update ticket level while unloading chunks or updating entity manager"); } @@ -83,7 +82,7 @@ index ac27ff24f018d8798921c5152e679ceed1e88d8d..ec7d1353b19e55b00c558df8981323ef List states = new java.util.ArrayList<>(level.capturedBlockStates.values()); level.capturedBlockStates.clear(); diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index aa8c2a3fc3a9a6318a3e757c6e51249ff11bd633..7bf2449141270c8ed924e38fdd8f9c1830ac2d99 100644 +index 2f4be37e1ef4ea550bd6acd2c4647e5a7ed77648..101dce7741f74dd79b333fd6cf38a97cb0c832f8 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -290,6 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop entities = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Paper - rewrite chunk system // DivineMC - Async mob spawning + public final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system + + // DivineMC start - Parallel world ticking + @Nullable + private final net.minecraft.server.level.ServerLevel serverLevel; @@ -1375,7 +1374,7 @@ index 9e75320e51886e0f93c23683d8614128f44a613e..d8b3e0901922016a22ca2801c2c4e0af + this.serverLevel = serverLevel; + } + // DivineMC end - Parallel world ticking - ++ private void ensureActiveIsNotIterated() { // Paper - rewrite chunk system } @@ -1391,7 +1390,7 @@ index 9e75320e51886e0f93c23683d8614128f44a613e..d8b3e0901922016a22ca2801c2c4e0af this.ensureActiveIsNotIterated(); this.entities.remove(entity); // Paper - rewrite chunk system } -@@ -30,6 +44,7 @@ public class EntityTickList { +@@ -30,6 +45,7 @@ public class EntityTickList { } public void forEach(Consumer entity) { diff --git a/patches/work/server/minecraft/0046-MSPT-Tracking-for-each-world.patch b/divinemc-server/minecraft-patches/features/0079-MSPT-Tracking-for-each-world.patch similarity index 91% rename from patches/work/server/minecraft/0046-MSPT-Tracking-for-each-world.patch rename to divinemc-server/minecraft-patches/features/0079-MSPT-Tracking-for-each-world.patch index 67f77c2..b04c8ab 100644 --- a/patches/work/server/minecraft/0046-MSPT-Tracking-for-each-world.patch +++ b/divinemc-server/minecraft-patches/features/0079-MSPT-Tracking-for-each-world.patch @@ -5,7 +5,7 @@ Subject: [PATCH] MSPT Tracking for each world diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index cbeb56539f00a3139f7c19d29cce92fae49dab2f..59642de7b2d3064c59bb1d8d2fc436cb9e2c2914 100644 +index 101dce7741f74dd79b333fd6cf38a97cb0c832f8..c0a272285e244e0267e6ef776aef14524e63c076 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -1676,7 +1676,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Wed, 9 Jul 2025 03:07:19 +0300 +Subject: [PATCH] Pufferfish: Simpler ShapelessRecipes comparison for Vanilla + +Original license: GPL v3 +Original project: https://github.com/pufferfish-gg/Pufferfish + +Patch description: + +Paper added a fancy sorting comparison due to Bukkit recipes breaking +the vanilla one, however this is far more advanced than what you need +for all the vanilla recipes. + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java +index 7c989318dc7ad89bb0d9143fcaac1e4bba6f5907..233446d9aa149ec5be7a009622d0c89353f3d3df 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java +@@ -44,6 +44,6 @@ public class CraftShapelessRecipe extends ShapelessRecipe implements CraftRecipe + data.add(this.toNMS(i, true)); + } + +- MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data))); ++ MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data, true))); // DivineMC - Pufferfish: Simpler ShapelessRecipes comparison for Vanilla + } + } diff --git a/patches/work/server/paper/0014-Parallel-world-ticking.patch b/divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch similarity index 99% rename from patches/work/server/paper/0014-Parallel-world-ticking.patch rename to divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch index 10b7c99..fc2f0c4 100644 --- a/patches/work/server/paper/0014-Parallel-world-ticking.patch +++ b/divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch @@ -1,8 +1,9 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 29 Jan 2025 01:41:25 +0300 -Subject: [PATCH] Parallel world ticking +Subject: [PATCH] SparklyPaper: Parallel world ticking +Original project: https://github.com/SparklyPower/SparklyPaper diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java index 69cdd304d255d52c9b7dc9b6a33ffdb630b79abe..a4adaba06c1bc4bb8029ccb128fde90ec2564525 100644 diff --git a/patches/work/server/purpur/0003-MSPT-Tracking-for-each-world.patch b/divinemc-server/purpur-patches/features/0004-MSPT-Tracking-for-each-world.patch similarity index 100% rename from patches/work/server/purpur/0003-MSPT-Tracking-for-each-world.patch rename to divinemc-server/purpur-patches/features/0004-MSPT-Tracking-for-each-world.patch diff --git a/patches/work/server/minecraft/0010-Chunk-System-Optimizations.patch b/patches/work/server/minecraft/0010-Chunk-System-Optimizations.patch deleted file mode 100644 index 17b25fd..0000000 --- a/patches/work/server/minecraft/0010-Chunk-System-Optimizations.patch +++ /dev/null @@ -1,3679 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 1 Feb 2025 00:09:39 +0300 -Subject: [PATCH] Chunk System Optimizations - - -diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java -index 93272808d94e81d31af728ebe85df9a2bc7aedab..17c0f25206b12665518142f27c17d17f315aad5f 100644 ---- a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java -+++ b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java -@@ -59,7 +59,7 @@ public final class NearbyPlayers { - public static final int GENERAL_REALLY_SMALL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_REALLY_SMALL_VIEW_DISTANCE << 4); - - private final ServerLevel world; -- private final Reference2ReferenceOpenHashMap players = new Reference2ReferenceOpenHashMap<>(); -+ private final it.unimi.dsi.fastutil.objects.Reference2ReferenceMap players = it.unimi.dsi.fastutil.objects.Reference2ReferenceMaps.synchronize(new Reference2ReferenceOpenHashMap<>()); // DivineMC - Chunk System optimization - // DivineMC start - Multithreaded Tracker - private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap byChunk; - { -@@ -70,10 +70,10 @@ public final class NearbyPlayers { - } - } - // DivineMC end - Multithreaded Tracker -- private final Long2ReferenceOpenHashMap>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES]; -+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap>[] directByChunk = new it.unimi.dsi.fastutil.longs.Long2ReferenceMap[TOTAL_MAP_TYPES]; // DivineMC - Chunk System optimization - { - for (int i = 0; i < this.directByChunk.length; ++i) { -- this.directByChunk[i] = new Long2ReferenceOpenHashMap<>(); -+ this.directByChunk[i] = it.unimi.dsi.fastutil.longs.Long2ReferenceMaps.synchronize(new Long2ReferenceOpenHashMap<>()); // DivineMC - Chunk System optimization - } - } - -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java -index b2bcfb3557a0326fd7ec1059f95d6da4568dfd80..325f02fa5b4e429f30bd625a74623101ad92d3e2 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java -@@ -225,8 +225,10 @@ public final class ChunkEntitySlices { - } - } - -+ public final java.util.concurrent.locks.ReentrantLock statusLock = new java.util.concurrent.locks.ReentrantLock(); // DivineMC - Chunk System Optimizations - private boolean preventStatusUpdates; - public boolean startPreventingStatusUpdates() { -+ this.statusLock.lock(); // DivineMC - Chunk System Optimizations - final boolean ret = this.preventStatusUpdates; - this.preventStatusUpdates = true; - return ret; -@@ -238,85 +240,104 @@ public final class ChunkEntitySlices { - - public void stopPreventingStatusUpdates(final boolean prev) { - this.preventStatusUpdates = prev; -+ this.statusLock.unlock(); // DivineMC - Chunk System Optimizations - } - - public void updateStatus(final FullChunkStatus status, final EntityLookup lookup) { -- this.status = status; -+ // DivineMC start - Chunk System Optimizations -+ this.statusLock.lock(); try { -+ this.status = status; - -- final Entity[] entities = this.entities.getRawData(); -+ final Entity[] entities = this.entities.getRawData(); - -- for (int i = 0, size = this.entities.size(); i < size; ++i) { -- final Entity entity = entities[i]; -+ for (int i = 0, size = this.entities.size(); i < size; ++i) { -+ final Entity entity = entities[i]; - -- final Visibility oldVisibility = EntityLookup.getEntityStatus(entity); -- ((ChunkSystemEntity)entity).moonrise$setChunkStatus(status); -- final Visibility newVisibility = EntityLookup.getEntityStatus(entity); -+ final Visibility oldVisibility = EntityLookup.getEntityStatus(entity); -+ ((ChunkSystemEntity) entity).moonrise$setChunkStatus(status); -+ final Visibility newVisibility = EntityLookup.getEntityStatus(entity); - -- lookup.entityStatusChange(entity, this, oldVisibility, newVisibility, false, false, false); -+ lookup.entityStatusChange(entity, this, oldVisibility, newVisibility, false, false, false); -+ } -+ } finally { -+ this.statusLock.unlock(); - } -+ // DivineMC end - Chunk System Optimizations - } - - public boolean addEntity(final Entity entity, final int chunkSection) { -- if (!this.entities.add(entity)) { -- return false; -- } -- ((ChunkSystemEntity)entity).moonrise$setChunkStatus(this.status); -- ((ChunkSystemEntity)entity).moonrise$setChunkData(this.chunkData); -- final int sectionIndex = chunkSection - this.minSection; -+ // DivineMC start - Chunk System Optimizations -+ this.statusLock.lock(); try { -+ if (!this.entities.add(entity)) { -+ return false; -+ } -+ ((ChunkSystemEntity) entity).moonrise$setChunkStatus(this.status); -+ ((ChunkSystemEntity) entity).moonrise$setChunkData(this.chunkData); -+ final int sectionIndex = chunkSection - this.minSection; - -- this.allEntities.addEntity(entity, sectionIndex); -+ this.allEntities.addEntity(entity, sectionIndex); - -- if (((ChunkSystemEntity)entity).moonrise$isHardColliding()) { -- this.hardCollidingEntities.addEntity(entity, sectionIndex); -- } -+ if (((ChunkSystemEntity) entity).moonrise$isHardColliding()) { -+ this.hardCollidingEntities.addEntity(entity, sectionIndex); -+ } - -- for (final Iterator, EntityCollectionBySection>> iterator = -- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) { -- final Reference2ObjectMap.Entry, EntityCollectionBySection> entry = iterator.next(); -+ for (final Iterator, EntityCollectionBySection>> iterator = -+ this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext(); ) { -+ final Reference2ObjectMap.Entry, EntityCollectionBySection> entry = iterator.next(); - -- if (entry.getKey().isInstance(entity)) { -- entry.getValue().addEntity(entity, sectionIndex); -+ if (entry.getKey().isInstance(entity)) { -+ entry.getValue().addEntity(entity, sectionIndex); -+ } - } -- } - -- EntityCollectionBySection byType = this.entitiesByType.get(entity.getType()); -- if (byType != null) { -- byType.addEntity(entity, sectionIndex); -- } else { -- this.entitiesByType.put(entity.getType(), byType = new EntityCollectionBySection(this)); -- byType.addEntity(entity, sectionIndex); -- } -+ EntityCollectionBySection byType = this.entitiesByType.get(entity.getType()); -+ if (byType != null) { -+ byType.addEntity(entity, sectionIndex); -+ } else { -+ this.entitiesByType.put(entity.getType(), byType = new EntityCollectionBySection(this)); -+ byType.addEntity(entity, sectionIndex); -+ } - -- return true; -+ return true; -+ } finally { -+ this.statusLock.unlock(); -+ } -+ // DivineMC end - Chunk System Optimizations - } - - public boolean removeEntity(final Entity entity, final int chunkSection) { -- if (!this.entities.remove(entity)) { -- return false; -- } -- ((ChunkSystemEntity)entity).moonrise$setChunkStatus(null); -- ((ChunkSystemEntity)entity).moonrise$setChunkData(null); -- final int sectionIndex = chunkSection - this.minSection; -+ // DivineMC start - Chunk System Optimizations -+ this.statusLock.lock(); try { -+ if (!this.entities.remove(entity)) { -+ return false; -+ } -+ ((ChunkSystemEntity) entity).moonrise$setChunkStatus(null); -+ ((ChunkSystemEntity) entity).moonrise$setChunkData(null); -+ final int sectionIndex = chunkSection - this.minSection; - -- this.allEntities.removeEntity(entity, sectionIndex); -+ this.allEntities.removeEntity(entity, sectionIndex); - -- if (((ChunkSystemEntity)entity).moonrise$isHardColliding()) { -- this.hardCollidingEntities.removeEntity(entity, sectionIndex); -- } -+ if (((ChunkSystemEntity) entity).moonrise$isHardColliding()) { -+ this.hardCollidingEntities.removeEntity(entity, sectionIndex); -+ } - -- for (final Iterator, EntityCollectionBySection>> iterator = -- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) { -- final Reference2ObjectMap.Entry, EntityCollectionBySection> entry = iterator.next(); -+ for (final Iterator, EntityCollectionBySection>> iterator = -+ this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext(); ) { -+ final Reference2ObjectMap.Entry, EntityCollectionBySection> entry = iterator.next(); - -- if (entry.getKey().isInstance(entity)) { -- entry.getValue().removeEntity(entity, sectionIndex); -+ if (entry.getKey().isInstance(entity)) { -+ entry.getValue().removeEntity(entity, sectionIndex); -+ } - } -- } - -- final EntityCollectionBySection byType = this.entitiesByType.get(entity.getType()); -- byType.removeEntity(entity, sectionIndex); -+ final EntityCollectionBySection byType = this.entitiesByType.get(entity.getType()); -+ byType.removeEntity(entity, sectionIndex); - -- return true; -+ return true; -+ } finally { -+ this.statusLock.unlock(); -+ } -+ // DivineMC end - Chunk System Optimizations - } - - public void getHardCollidingEntities(final Entity except, final AABB box, final List into, final Predicate predicate) { -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java -index 2d24d03bbdb5ee0d862cbfff2219f58afffafe12..950b284cb3b4488a794e6c6f936f55ea427ef7cc 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java -@@ -93,8 +93,14 @@ public abstract class EntityLookup implements LevelEntityGetter { - if (entity == null) { - return null; - } -- final Visibility visibility = EntityLookup.getEntityStatus(entity); -- return visibility.isAccessible() ? entity : null; -+ // DivineMC start - Chunk System Optimizations -+ final FullChunkStatus entityStatus = ((ChunkSystemEntity) entity).moonrise$getChunkStatus(); -+ return switch (entityStatus) { -+ case INACCESSIBLE -> null; -+ case FULL, BLOCK_TICKING, ENTITY_TICKING -> entity; -+ case null -> null; -+ }; -+ // DivineMC end - Chunk System Optimizations - } - - @Override -@@ -398,7 +404,14 @@ public abstract class EntityLookup implements LevelEntityGetter { - return Visibility.TICKING; - } - final FullChunkStatus entityStatus = ((ChunkSystemEntity)entity).moonrise$getChunkStatus(); -- return Visibility.fromFullChunkStatus(entityStatus == null ? FullChunkStatus.INACCESSIBLE : entityStatus); -+ // DivineMC start - Chunk System Optimizations -+ return switch (entityStatus) { -+ case INACCESSIBLE -> Visibility.HIDDEN; -+ case FULL, BLOCK_TICKING -> Visibility.TRACKED; -+ case ENTITY_TICKING -> Visibility.TICKING; -+ case null -> Visibility.HIDDEN; -+ }; -+ // DivineMC end - Chunk System Optimizations - } - - protected boolean addEntity(final Entity entity, final boolean fromDisk, final boolean event) { -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -index dc2b3ccf7810731c0e2c90e5a476c1c8203a1fb7..7c223e99dfc8b67b3c953d9c741ced4a2c485343 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -@@ -191,13 +191,13 @@ public final class RegionizedPlayerChunkLoader { - } - - if (((ChunkSystemServerPlayer)player).moonrise$getChunkLoader() != null) { -- throw new IllegalStateException("Player is already added to player chunk loader"); -+ return; // DivineMC - Chunk System optimization - already loaded - } - - final PlayerChunkLoaderData loader = new PlayerChunkLoaderData(this.world, player); - -- ((ChunkSystemServerPlayer)player).moonrise$setChunkLoader(loader); - loader.add(); -+ player.moonrise$setChunkLoader(loader); // DivineMC - Chunk System optimization - } - - public void updatePlayer(final ServerPlayer player) { -@@ -308,7 +308,7 @@ public final class RegionizedPlayerChunkLoader { - long currTime = System.nanoTime(); - for (final ServerPlayer player : new java.util.ArrayList<>(this.world.players())) { - final PlayerChunkLoaderData loader = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader(); -- if (loader == null || loader.removed || loader.world != this.world) { -+ if (loader == null || loader.removed || loader.world != this.world || !loader.canTick) { // DivineMC - Chunk System optimization - // not our problem anymore - continue; - } -@@ -327,6 +327,7 @@ public final class RegionizedPlayerChunkLoader { - - private final ServerPlayer player; - private final ServerLevel world; -+ public volatile boolean canTick; // DivineMC - Chunk System optimization - - private int lastChunkX = Integer.MIN_VALUE; - private int lastChunkZ = Integer.MIN_VALUE; -@@ -386,10 +387,12 @@ public final class RegionizedPlayerChunkLoader { - final int centerX = PlayerChunkLoaderData.this.lastChunkX; - final int centerZ = PlayerChunkLoaderData.this.lastChunkZ; - -+ // DivineMC start - Chunk System Optimization - return Integer.compare( -- Math.abs(c1x - centerX) + Math.abs(c1z - centerZ), -- Math.abs(c2x - centerX) + Math.abs(c2z - centerZ) -+ (c1x - centerX) * (c1x - centerX) + (c1z - centerZ) * (c1z - centerZ), -+ (c2x - centerX) * (c2x - centerX) + (c2z - centerZ) * (c2z - centerZ) - ); -+ // DivineMC end - Chunk System Optimization - }; - private final LongHeapPriorityQueue sendQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); - private final LongHeapPriorityQueue tickingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); -@@ -857,6 +860,7 @@ public final class RegionizedPlayerChunkLoader { - } - - void add() { -+ this.canTick = false; // DivineMC - Chunk System optimization - TickThread.ensureTickThread(this.player, "Cannot add player asynchronously"); - if (this.removed) { - throw new IllegalStateException("Adding removed player chunk loader"); -@@ -896,6 +900,7 @@ public final class RegionizedPlayerChunkLoader { - - // now we can update - this.update(); -+ this.canTick = true; // DivineMC - Chunk System optimization - } - - private boolean isLoadedChunkGeneratable(final int chunkX, final int chunkZ) { -@@ -1064,6 +1069,7 @@ public final class RegionizedPlayerChunkLoader { - } - - void remove() { -+ this.canTick = false; // DivineMC - Chunk System optimization - TickThread.ensureTickThread(this.player, "Cannot add player asynchronously"); - if (this.removed) { - throw new IllegalStateException("Removing removed player chunk loader"); -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -index 6ce4a98e4d3b633e3c87944c23b6b3f0ff58f159..c10e31017e7dfab348e9cc45c28d3858863ac0b1 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -@@ -73,37 +73,50 @@ public final class ChunkHolderManager { - private static final long NO_TIMEOUT_MARKER = Long.MIN_VALUE; - public final ReentrantAreaLock ticketLockArea; - -- private final ConcurrentLong2ReferenceChainedHashTable> tickets = new ConcurrentLong2ReferenceChainedHashTable<>(); -- private final ConcurrentLong2ReferenceChainedHashTable sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>(); -+ // DivineMC start - Chunk System optimization -+ private final ConcurrentLong2ReferenceChainedHashTable> tickets = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F); -+ private final ConcurrentLong2ReferenceChainedHashTable sectionToChunkToExpireCount = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F); -+ // DivineMC end - Chunk System optimization - final ChunkUnloadQueue unloadQueue; - -- private final ConcurrentLong2ReferenceChainedHashTable chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f); -+ private final ConcurrentLong2ReferenceChainedHashTable chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F); // DivineMC - Chunk System optimization - private final ServerLevel world; - private final ChunkTaskScheduler taskScheduler; - private long currentTick; - -- private final ArrayDeque pendingFullLoadUpdate = new ArrayDeque<>(); -- private final MultiThreadedQueue offThreadPendingFullLoadUpdate = new MultiThreadedQueue<>(); -- private final ObjectRBTreeSet autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> { -- if (c1 == c2) { -- return 0; -- } -+ // DivineMC start - Chunk System optimization -+ public static class LevelHolderData { -+ private final java.util.concurrent.ConcurrentLinkedDeque pendingFullLoadUpdate = new java.util.concurrent.ConcurrentLinkedDeque<>(); -+ private final MultiThreadedQueue offThreadPendingFullLoadUpdate = new MultiThreadedQueue<>(); -+ private final ObjectRBTreeSet autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> { -+ if (c1 == c2) { -+ return 0; -+ } - -- final int saveTickCompare = Long.compare(c1.lastAutoSave, c2.lastAutoSave); -+ final int saveTickCompare = Long.compare(c1.lastAutoSave, c2.lastAutoSave); - -- if (saveTickCompare != 0) { -- return saveTickCompare; -- } -+ if (saveTickCompare != 0) { -+ return saveTickCompare; -+ } - -- final long coord1 = CoordinateUtils.getChunkKey(c1.chunkX, c1.chunkZ); -- final long coord2 = CoordinateUtils.getChunkKey(c2.chunkX, c2.chunkZ); -+ final long coord1 = CoordinateUtils.getChunkKey(c1.chunkX, c1.chunkZ); -+ final long coord2 = CoordinateUtils.getChunkKey(c2.chunkX, c2.chunkZ); - -- if (coord1 == coord2) { -- throw new IllegalStateException("Duplicate chunkholder in auto save queue"); -- } -+ if (coord1 == coord2) { -+ throw new IllegalStateException("Duplicate chunkholder in auto save queue"); -+ } - -- return Long.compare(coord1, coord2); -- }); -+ return Long.compare(coord1, coord2); -+ }); -+ } -+ -+ public LevelHolderData getData() { -+ if (this.world == null) { -+ throw new RuntimeException("World was null!"); -+ } -+ return world.chunkHolderData; -+ } -+ // DivineMC end - Chunk System optimization - - private final ConcurrentLong2ReferenceChainedHashTable ticketCounters = new ConcurrentLong2ReferenceChainedHashTable<>(); - -@@ -226,26 +239,29 @@ public final class ChunkHolderManager { - this.taskScheduler.setShutdown(true); - } - -- void ensureInAutosave(final NewChunkHolder holder) { -- if (!this.autoSaveQueue.contains(holder)) { -+ // DivineMC start - Chunk System optimization -+ synchronized void ensureInAutosave(final NewChunkHolder holder) { -+ final LevelHolderData data = getData(); -+ if (!data.autoSaveQueue.contains(holder)) { - holder.lastAutoSave = this.currentTick; -- this.autoSaveQueue.add(holder); -+ data.autoSaveQueue.add(holder); - } - } - -- public void autoSave() { -+ public synchronized void autoSave() { -+ final LevelHolderData data = getData(); - final List reschedule = new ArrayList<>(); - final long currentTick = this.currentTick; - final long maxSaveTime = currentTick - Math.max(1L, PlatformHooks.get().configAutoSaveInterval(this.world)); - final int maxToSave = PlatformHooks.get().configMaxAutoSavePerTick(this.world); -- for (int autoSaved = 0; autoSaved < maxToSave && !this.autoSaveQueue.isEmpty();) { -- final NewChunkHolder holder = this.autoSaveQueue.first(); -+ for (int autoSaved = 0; autoSaved < maxToSave && !data.autoSaveQueue.isEmpty();) { -+ final NewChunkHolder holder = data.autoSaveQueue.first(); - - if (holder.lastAutoSave > maxSaveTime) { - break; - } - -- this.autoSaveQueue.remove(holder); -+ data.autoSaveQueue.remove(holder); - - holder.lastAutoSave = currentTick; - if (holder.save(false) != null) { -@@ -259,10 +275,11 @@ public final class ChunkHolderManager { - - for (final NewChunkHolder holder : reschedule) { - if (holder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)) { -- this.autoSaveQueue.add(holder); -+ data.autoSaveQueue.add(holder); - } - } - } -+ // DivineMC end - Chunk System optimization - - public void saveAllChunks(final boolean flush, final boolean shutdown, final boolean logProgress) { - final List holders = this.getChunkHolders(); -@@ -323,11 +340,7 @@ public final class ChunkHolderManager { - final long currTime = System.nanoTime(); - if ((currTime - lastLog) > TimeUnit.SECONDS.toNanos(10L)) { - lastLog = currTime; -- LOGGER.info( -- "Saved " + savedChunk + " block chunks, " + savedEntity + " entity chunks, " + savedPoi -- + " poi chunks in world '" + WorldUtil.getWorldName(this.world) + "', progress: " -- + format.format((double)(i+1)/(double)len * 100.0) -- ); -+ LOGGER.info("Saved {} block chunks, {} entity chunks, {} poi chunks in world '{}', progress: {}", savedChunk, savedEntity, savedPoi, ca.spottedleaf.moonrise.common.util.WorldUtil.getWorldName(this.world), format.format((double) (i + 1) / (double) len * 100.0)); // DivineMC - Beautify log - } - } - } -@@ -461,8 +474,8 @@ public final class ChunkHolderManager { - final Long2ObjectOpenHashMap> ret = new Long2ObjectOpenHashMap<>(); - final Long2ObjectOpenHashMap sections = new Long2ObjectOpenHashMap<>(); - final int sectionShift = this.taskScheduler.getChunkSystemLockShift(); -- for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) { -- final long coord = iterator.nextLong(); -+ for (final Iterator iterator = this.tickets.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization -+ final long coord = iterator.next(); // DivineMC - Chunk System optimization - sections.computeIfAbsent( - CoordinateUtils.getChunkKey( - CoordinateUtils.getChunkX(coord) >> sectionShift, -@@ -559,7 +572,7 @@ public final class ChunkHolderManager { - chunkZ >> sectionShift - ); - -- this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (final long keyInMap) -> { -+ this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (keyInMap) -> { // DivineMC - Chunk System optimization - return new Long2IntOpenHashMap(); - }).addTo(chunkKey, 1); - } -@@ -603,8 +616,8 @@ public final class ChunkHolderManager { - - final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null; - try { -- final SortedArraySet ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (final long keyInMap) -> { -- return (SortedArraySet)SortedArraySet.create(4); -+ final SortedArraySet ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (keyInMap) -> { // DivineMC - Chunk System optimization -+ return SortedArraySet.create(4); - }); - - final int levelBefore = getTicketLevelAt(ticketsAtChunk); -@@ -784,8 +797,8 @@ public final class ChunkHolderManager { - - final Long2ObjectOpenHashMap sections = new Long2ObjectOpenHashMap<>(); - final int sectionShift = this.taskScheduler.getChunkSystemLockShift(); -- for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) { -- final long coord = iterator.nextLong(); -+ for (final Iterator iterator = this.tickets.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization -+ final long coord = iterator.next(); // DivineMC - Chunk System optimization - sections.computeIfAbsent( - CoordinateUtils.getChunkKey( - CoordinateUtils.getChunkX(coord) >> sectionShift, -@@ -836,8 +849,8 @@ public final class ChunkHolderManager { - final List scheduledTasks = new ArrayList<>(); - final List changedFullStatus = new ArrayList<>(); - -- for (final PrimitiveIterator.OfLong iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) { -- final long sectionKey = iterator.nextLong(); -+ for (final Iterator iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization -+ final long sectionKey = iterator.next(); // DivineMC - Chunk System optimization - - if (!this.sectionToChunkToExpireCount.containsKey(sectionKey)) { - // removed concurrently -@@ -1145,18 +1158,18 @@ public final class ChunkHolderManager { - if (!TickThread.isTickThread()) { - // These will be handled on the next ServerChunkCache$MainThreadExecutor#pollTask, as it runs the distance manager update - // which will invoke processTicketUpdates -- this.offThreadPendingFullLoadUpdate.addAll(changedFullStatus); -+ this.getData().offThreadPendingFullLoadUpdate.addAll(changedFullStatus); // DivineMC - Chunk System optimization - } else { -- final ArrayDeque pendingFullLoadUpdate = this.pendingFullLoadUpdate; -+ final java.util.Deque pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization - for (int i = 0, len = changedFullStatus.size(); i < len; ++i) { - pendingFullLoadUpdate.add(changedFullStatus.get(i)); - } - } - } - -- private void removeChunkHolder(final NewChunkHolder holder) { -+ private synchronized void removeChunkHolder(final NewChunkHolder holder) { // DivineMC - Chunk System optimization - holder.onUnload(); -- this.autoSaveQueue.remove(holder); -+ this.getData().autoSaveQueue.remove(holder); // DivineMC - Chunk System optimization - PlatformHooks.get().onChunkHolderDelete(this.world, holder.vanillaChunkHolder); - this.chunkHolders.remove(CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ)); - } -@@ -1314,6 +1327,27 @@ public final class ChunkHolderManager { - } - } - -+ // DivineMC start - Chunk System optimization -+ public final java.util.Set blockTickingChunkHolders = java.util.Collections.synchronizedSet(new org.agrona.collections.ObjectHashSet<>(10, 0.88f, true)); -+ public final java.util.Set entityTickingChunkHolders = java.util.Collections.synchronizedSet(new org.agrona.collections.ObjectHashSet<>(10, 0.88f, true)); -+ -+ public void markBlockTicking(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) { -+ this.blockTickingChunkHolders.add(newChunkHolder.getCachedLongPos()); -+ } -+ -+ public void markNonBlockTickingIfPossible(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) { -+ this.blockTickingChunkHolders.remove(newChunkHolder.getCachedLongPos()); -+ } -+ -+ public void markEntityTicking(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) { -+ this.entityTickingChunkHolders.add(newChunkHolder.getCachedLongPos()); -+ } -+ -+ public void markNonEntityTickingIfPossible(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) { -+ this.entityTickingChunkHolders.remove(newChunkHolder.getCachedLongPos()); -+ } -+ // DivineMC end - Chunk System optimization -+ - public enum TicketOperationType { - ADD, REMOVE, ADD_IF_REMOVED, ADD_AND_REMOVE - } -@@ -1473,8 +1507,8 @@ public final class ChunkHolderManager { - - // only call on tick thread - private void processOffThreadFullUpdates() { -- final ArrayDeque pendingFullLoadUpdate = this.pendingFullLoadUpdate; -- final MultiThreadedQueue offThreadPendingFullLoadUpdate = this.offThreadPendingFullLoadUpdate; -+ final java.util.concurrent.ConcurrentLinkedDeque pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization -+ final MultiThreadedQueue offThreadPendingFullLoadUpdate = this.getData().offThreadPendingFullLoadUpdate; // DivineMC - Chunk System optimization - - NewChunkHolder toUpdate; - while ((toUpdate = offThreadPendingFullLoadUpdate.poll()) != null) { -@@ -1486,7 +1520,7 @@ public final class ChunkHolderManager { - private boolean processPendingFullUpdate() { - this.processOffThreadFullUpdates(); - -- final ArrayDeque pendingFullLoadUpdate = this.pendingFullLoadUpdate; -+ final java.util.Deque pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization - - boolean ret = false; - -@@ -1522,8 +1556,7 @@ public final class ChunkHolderManager { - final JsonArray allTicketsJson = new JsonArray(); - ret.add("tickets", allTicketsJson); - -- for (final Iterator>> iterator = this.tickets.entryIterator(); -- iterator.hasNext();) { -+ for (final Iterator>> iterator = this.tickets.entryIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization - final ConcurrentLong2ReferenceChainedHashTable.TableEntry> coordinateTickets = iterator.next(); - final long coordinate = coordinateTickets.getKey(); - final SortedArraySet tickets = coordinateTickets.getValue(); -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java -index 8f8268924ac92fca5df8a11e08031fa8416c6e05..f1bc7a5e80de0293e1837b2f7401b347fc59f831 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java -@@ -66,14 +66,6 @@ public final class ChunkTaskScheduler { - - private static final Logger LOGGER = LogUtils.getClassLogger(); - -- public static void init(final boolean useParallelGen) { -- for (final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor executor : MoonriseCommon.RADIUS_AWARE_GROUP.getAllExecutors()) { -- executor.setMaxParallelism(useParallelGen ? -1 : 1); -- } -- -- LOGGER.info("Chunk system is using population gen parallelism: " + useParallelGen); -- } -- - public static final TicketType CHUNK_LOAD = ChunkSystemTicketType.create("chunk_system:chunk_load", Long::compareTo); - private static final AtomicLong CHUNK_LOAD_IDS = new AtomicLong(); - -@@ -116,12 +108,12 @@ public final class ChunkTaskScheduler { - - public final ServerLevel world; - public final RadiusAwarePrioritisedExecutor radiusAwareScheduler; -- public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor parallelGenExecutor; -- private final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor radiusAwareGenExecutor; -- public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor loadExecutor; -+ public final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor parallelGenExecutor; -+ private final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor radiusAwareGenExecutor; -+ public final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor loadExecutor; - public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor ioExecutor; -- public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor compressionExecutor; -- public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor saveExecutor; -+ public final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor compressionExecutor; -+ public final org.bxteam.divinemc.server.chunk.TheChunkSystem.ExecutorGroup.ThreadPoolExecutor saveExecutor; - - private final PrioritisedTaskQueue mainThreadExecutor = new PrioritisedTaskQueue(); - -@@ -292,14 +284,14 @@ public final class ChunkTaskScheduler { - this.lockShift = Math.max(((ChunkSystemServerLevel)world).moonrise$getRegionChunkShift(), ThreadedTicketLevelPropagator.SECTION_SHIFT); - this.schedulingLockArea = new ReentrantAreaLock(this.getChunkSystemLockShift()); - -- this.parallelGenExecutor = MoonriseCommon.PARALLEL_GEN_GROUP.createExecutor(-1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0); -- this.radiusAwareGenExecutor = MoonriseCommon.RADIUS_AWARE_GROUP.createExecutor(1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0); -- this.loadExecutor = MoonriseCommon.LOAD_GROUP.createExecutor(-1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0); -- this.radiusAwareScheduler = new RadiusAwarePrioritisedExecutor(this.radiusAwareGenExecutor, 16); -+ this.parallelGenExecutor = MoonriseCommon.PARALLEL_GEN_GROUP.createExecutor(); -+ this.radiusAwareGenExecutor = MoonriseCommon.RADIUS_AWARE_GROUP.createExecutor(); -+ this.loadExecutor = MoonriseCommon.LOAD_GROUP.createExecutor(); -+ this.radiusAwareScheduler = new RadiusAwarePrioritisedExecutor(this.radiusAwareGenExecutor, 10_000); - this.ioExecutor = MoonriseCommon.SERVER_REGION_IO_GROUP.createExecutor(-1, MoonriseCommon.IO_QUEUE_HOLD_TIME, 0); - // we need a separate executor here so that on shutdown we can continue to process I/O tasks -- this.compressionExecutor = MoonriseCommon.LOAD_GROUP.createExecutor(-1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0); -- this.saveExecutor = MoonriseCommon.LOAD_GROUP.createExecutor(-1, MoonriseCommon.WORKER_QUEUE_HOLD_TIME, 0); -+ this.compressionExecutor = MoonriseCommon.LOAD_GROUP.createExecutor(); -+ this.saveExecutor = MoonriseCommon.LOAD_GROUP.createExecutor(); - this.chunkHolderManager = new ChunkHolderManager(world, this); - } - -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -index 2cc0e7c72d2b2e562452138f2b41fd1dcaf0570a..cf7ecf226f7090ca598423aed83249a8e3c19fe1 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -@@ -646,11 +646,19 @@ public final class NewChunkHolder { - } - - public final ChunkHolder vanillaChunkHolder; -+ // DivineMC start - Chunk System optimization -+ private final long cachedLongPos; -+ -+ public long getCachedLongPos() { -+ return cachedLongPos; -+ } -+ // DivineMC end - Chunk System optimization - - public NewChunkHolder(final ServerLevel world, final int chunkX, final int chunkZ, final ChunkTaskScheduler scheduler) { - this.world = world; - this.chunkX = chunkX; - this.chunkZ = chunkZ; -+ this.cachedLongPos = ((long)chunkZ << 32) | (chunkX & 0xFFFFFFFFL); // DivineMC - Chunk System optimization - this.scheduler = scheduler; - this.vanillaChunkHolder = new ChunkHolder( - new ChunkPos(chunkX, chunkZ), ChunkHolderManager.MAX_TICKET_LEVEL, world, -@@ -792,9 +800,11 @@ public final class NewChunkHolder { - - // note: these are completed with null to indicate that no write occurred - // they are also completed with null to indicate a null write occurred -- private UnloadTask chunkDataUnload; -- private UnloadTask entityDataUnload; -- private UnloadTask poiDataUnload; -+ // DivineMC start - Chunk System optimization -+ private volatile UnloadTask chunkDataUnload; -+ private volatile UnloadTask entityDataUnload; -+ private volatile UnloadTask poiDataUnload; -+ // DivineMC end - Chunk System optimization - - public static final record UnloadTask(CallbackCompletable completable, PrioritisedExecutor.PrioritisedTask task, - LazyRunnable toRun) {} -@@ -879,7 +889,11 @@ public final class NewChunkHolder { - MoonriseRegionFileIO.scheduleSave(this.world, this.chunkX, this.chunkZ, data, type); - } - -- this.getUnloadTask(type).completable().complete(data); -+ // DivineMC start - Chunk System optimization -+ UnloadTask task = this.getUnloadTask(type); -+ if (task == null) return; -+ task.completable().complete(data); -+ // DivineMC end - Chunk System optimization - final ReentrantAreaLock.Node schedulingLock = this.scheduler.schedulingLockArea.lock(this.chunkX, this.chunkZ); - try { - // can only write to these fields while holding the schedule lock -@@ -1192,6 +1206,7 @@ public final class NewChunkHolder { - for (int dz = -NEIGHBOUR_RADIUS; dz <= NEIGHBOUR_RADIUS; ++dz) { - for (int dx = -NEIGHBOUR_RADIUS; dx <= NEIGHBOUR_RADIUS; ++dx) { - final NewChunkHolder holder = (dx | dz) == 0 ? this : this.scheduler.chunkHolderManager.getChunkHolder(dx + this.chunkX, dz + this.chunkZ); -+ if (holder == null) continue; // DivineMC - Chunk System optimization - if (loaded) { - if (holder.setNeighbourFullLoaded(-dx, -dz)) { - changedFullStatus.add(holder); -@@ -1216,6 +1231,19 @@ public final class NewChunkHolder { - - private void updateCurrentState(final FullChunkStatus to) { - this.currentFullChunkStatus = to; -+ // DivineMC start - Chunk System optimization -+ if (to.isOrAfter(FullChunkStatus.BLOCK_TICKING)) { -+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markBlockTicking(this); -+ } else { -+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markNonBlockTickingIfPossible(this); -+ } -+ -+ if (to.isOrAfter(FullChunkStatus.ENTITY_TICKING)) { -+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markEntityTicking(this); -+ } else { -+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markNonEntityTickingIfPossible(this); -+ } -+ // DivineMC end - Chunk System optimization - } - - // only to be called on the main thread, no locks need to be held -@@ -1350,7 +1378,7 @@ public final class NewChunkHolder { - return this.requestedGenStatus; - } - -- private final Reference2ObjectOpenHashMap>> statusWaiters = new Reference2ObjectOpenHashMap<>(); -+ private final Reference2ObjectMap>> statusWaiters = it.unimi.dsi.fastutil.objects.Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>()); // DivineMC - Chunk System optimization - - void addStatusConsumer(final ChunkStatus status, final Consumer consumer) { - this.statusWaiters.computeIfAbsent(status, (final ChunkStatus keyInMap) -> { -@@ -1396,7 +1424,7 @@ public final class NewChunkHolder { - }, Priority.HIGHEST); - } - -- private final Reference2ObjectOpenHashMap>> fullStatusWaiters = new Reference2ObjectOpenHashMap<>(); -+ private final Reference2ObjectMap>> fullStatusWaiters = it.unimi.dsi.fastutil.objects.Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>()); // DivineMC - Chunk System optimization - - void addFullStatusConsumer(final FullChunkStatus status, final Consumer consumer) { - this.fullStatusWaiters.computeIfAbsent(status, (final FullChunkStatus keyInMap) -> { -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java -index 28ffa653e87a4e8ef7cf614916ef3fe61681fe16..b35b92b204fbefd139c4544f15e32d46bfa30777 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/executor/RadiusAwarePrioritisedExecutor.java -@@ -110,60 +110,27 @@ public class RadiusAwarePrioritisedExecutor { - return priorityId == this.selectedQueue ? queue.tryPushTasks() : null; - } - -+ // DivineMC start - Chunk System Optimizations - public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius, -- final Runnable run, final Priority priority) { -+ final Runnable run, final Priority priority, final net.minecraft.server.level.ServerLevel world) { - if (radius < 0) { - throw new IllegalArgumentException("Radius must be > 0: " + radius); - } -- return new Task(this, chunkX, chunkZ, radius, run, priority); -+ return new Task(this, chunkX, chunkZ, radius, run, priority, world); - } - -- public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius, -- final Runnable run) { -- return this.createTask(chunkX, chunkZ, radius, run, Priority.NORMAL); -- } -- -- public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius, -- final Runnable run, final Priority priority) { -- final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run, priority); -- -- ret.queue(); -- -- return ret; -- } -- -- public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius, -- final Runnable run) { -- final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run); -- -- ret.queue(); -- -- return ret; -- } -- -- public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run, final Priority priority) { -- return new Task(this, 0, 0, -1, run, priority); -- } -- -- public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run) { -- return this.createInfiniteRadiusTask(run, Priority.NORMAL); -- } -- -- public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run, final Priority priority) { -- final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, priority); -- -- ret.queue(); -- -- return ret; -+ public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run, final Priority priority, final net.minecraft.server.level.ServerLevel world) { -+ return new Task(this, 0, 0, -1, run, priority, world); - } - -- public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run) { -- final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, Priority.NORMAL); -+ public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run, final net.minecraft.server.level.ServerLevel world) { -+ final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, Priority.NORMAL, world); - - ret.queue(); - - return ret; - } -+ // DivineMC end - Chunk System Optimizations - - private static void scheduleTasks(final List toSchedule) { - if (toSchedule != null) { -@@ -440,18 +407,20 @@ public class RadiusAwarePrioritisedExecutor { - private final int radius; - private Runnable run; - private Priority priority; -+ public final net.minecraft.server.level.ServerLevel world; // DivineMC - Chunk System Optimization - - private DependencyNode dependencyNode; - private PrioritisedExecutor.PrioritisedTask queuedTask; - - private Task(final RadiusAwarePrioritisedExecutor scheduler, final int chunkX, final int chunkZ, final int radius, -- final Runnable run, final Priority priority) { -+ final Runnable run, final Priority priority, final net.minecraft.server.level.ServerLevel world) { // DivineMC - Chunk System Optimization - this.scheduler = scheduler; - this.chunkX = chunkX; - this.chunkZ = chunkZ; - this.radius = radius; - this.run = run; - this.priority = priority; -+ this.world = world; // DivineMC - Chunk System Optimization - } - - private boolean isFiniteRadius() { -@@ -473,6 +442,7 @@ public class RadiusAwarePrioritisedExecutor { - synchronized (this.scheduler) { - final DependencyNode node = this.dependencyNode; - this.dependencyNode = null; -+ if (node == null) return; // DivineMC - Chunk System Optimization - toSchedule = node.tree.returnNode(node); - } - -@@ -489,6 +459,7 @@ public class RadiusAwarePrioritisedExecutor { - final Runnable run = this.run; - this.run = null; - try { -+ if (run == null) return; // DivineMC - Chunk System Optimization - run.run(); - } finally { - this.returnNode(); -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java -index 96ccb8f657d755b2e58a8dd0cda00ca0df4886b2..89de0fcb3f8142f76399fc00e288e03d7f3742f2 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java -@@ -35,7 +35,7 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl - super(scheduler, world, chunkX, chunkZ); - this.chunkHolder = chunkHolder; - this.fromChunk = fromChunk; -- this.convertToFullTask = scheduler.createChunkTask(chunkX, chunkZ, this, priority); -+ this.convertToFullTask = scheduler.radiusAwareScheduler.createInfiniteRadiusTask(this, priority, world); // DivineMC - Chunk System Optimizations - } - - @Override -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java -index e9623c334858ebc698c92d05b36b70f6d846d0b1..43ef4d7b7db64a766bb815e1c2202b1f30ae4f99 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkProgressionTask.java -@@ -69,7 +69,7 @@ public abstract class ChunkProgressionTask { - } - } - -- protected final void complete(final ChunkAccess chunk, final Throwable throwable) { -+ protected void complete(final ChunkAccess chunk, final Throwable throwable) { // DivineMC - not final - try { - this.complete0(chunk, throwable); - } catch (final Throwable thr2) { -@@ -81,7 +81,7 @@ public abstract class ChunkProgressionTask { - - private void complete0(final ChunkAccess chunk, final Throwable throwable) { - if ((boolean)COMPLETED_HANDLE.getAndSet((ChunkProgressionTask)this, (boolean)true)) { -- throw new IllegalStateException("Already completed"); -+ return; // DivineMC - do not crash the server - } - this.completedChunk = chunk; - this.completedThrowable = throwable; -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java -index 25d8da4773dcee5096053e7e3788bfc224d705a7..2112ccbe382993dcfb56a50d991c3613765d7d56 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkUpgradeGenericStatusTask.java -@@ -51,9 +51,9 @@ public final class ChunkUpgradeGenericStatusTask extends ChunkProgressionTask im - } else { - final int writeRadius = ((ChunkSystemChunkStatus)this.toStatus).moonrise$getWriteRadius(); - if (writeRadius < 0) { -- this.generateTask = this.scheduler.radiusAwareScheduler.createInfiniteRadiusTask(this, priority); -+ this.generateTask = this.scheduler.radiusAwareScheduler.createInfiniteRadiusTask(this, priority, world); // DivineMC - Chunk System Optimizations - } else { -- this.generateTask = this.scheduler.radiusAwareScheduler.createTask(chunkX, chunkZ, writeRadius, this, priority); -+ this.generateTask = this.scheduler.radiusAwareScheduler.createTask(chunkX, chunkZ, writeRadius, this, priority, world); // DivineMC - Chunk System Optimizations - } - } - } -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java -index 95ed5a0ff3f0588f625ba48a5fee3aafbab9d13f..f2fd6d5eb024f646875868c441eb2da284206026 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/GenericDataLoadTask.java -@@ -333,6 +333,12 @@ public abstract class GenericDataLoadTask { - GenericDataLoadTask.this.onComplete((TaskResult)newData); - } - } -+ -+ // DivineMC start - Chunk System Optimizations -+ public GenericDataLoadTask loadTask() { -+ return GenericDataLoadTask.this; -+ } -+ // DivineMC end - Chunk System Optimizations - } - - public final class ProcessOnMainTask implements Runnable { -@@ -351,6 +357,12 @@ public abstract class GenericDataLoadTask { - - GenericDataLoadTask.this.onComplete(result); - } -+ -+ // DivineMC start - Chunk System Optimizations -+ public GenericDataLoadTask loadTask() { -+ return GenericDataLoadTask.this; -+ } -+ // DivineMC end - Chunk System Optimizations - } - - protected static final class LoadDataFromDiskTask { -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java b/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java -index 93fd23027c00cef76562098306737272fda1350a..44e443768f5163454fd11425afd3bc07b2c0c6c2 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java -@@ -23,6 +23,7 @@ public final class ParallelSearchRadiusIteration { - } - - public static long[] getSearchIteration(final int radius) { -+ if (radius >= SEARCH_RADIUS_ITERATION_LIST.length) return SEARCH_RADIUS_ITERATION_LIST[SEARCH_RADIUS_ITERATION_LIST.length - 1]; // DivineMC - Chunk System Optimizations - return SEARCH_RADIUS_ITERATION_LIST[radius]; - } - -diff --git a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java -index 6d1fe8028739145b11fce98ad62b2f8044299548..1885339f1ed5f24aa281aa2720a1d511a95740de 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java -@@ -2,7 +2,7 @@ package ca.spottedleaf.moonrise.patches.chunk_tick_iteration; - - public final class ChunkTickConstants { - -- public static final int PLAYER_SPAWN_TRACK_RANGE = 8; -+ public static final int PLAYER_SPAWN_TRACK_RANGE = (int) Math.round(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange / 16.0); // DivineMC - Chunk System optimization - // the smallest distance on x/z is at 45 degrees, we need to subtract 0.5 since this is calculated from chunk center and not chunk perimeter - // note: vanilla does not subtract 0.5 but the result is (luckily!) the same - public static final int NARROW_SPAWN_TRACK_RANGE = (int)Math.floor(((double)PLAYER_SPAWN_TRACK_RANGE / Math.sqrt(2.0)) - 0.5); -diff --git a/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java b/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java -index 4ca68a903e67606fc4ef0bfa9862a73797121c8b..f94f443f862611f039454d1dc8ff2a4ba5f081d3 100644 ---- a/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java -+++ b/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java -@@ -325,7 +325,7 @@ public final class SWMRNibbleArray { - } - - // operation type: updating -- public boolean updateVisible() { -+ public synchronized boolean updateVisible() { // DivineMC - Chunk System optimization - if (!this.isDirty()) { - return false; - } -diff --git a/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java b/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java -index 51f4dd4f583dfbd16cb00f1cb4418d1044cecb1c..2f83deafbb5b50e5ce191b5351ec5ed948262008 100644 ---- a/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java -+++ b/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java -@@ -887,7 +887,7 @@ public final class StarLightInterface { - super(chunkCoordinate, lightEngine, queue); - this.task = ((ChunkSystemServerLevel)(ServerLevel)lightEngine.getWorld()).moonrise$getChunkTaskScheduler().radiusAwareScheduler.createTask( - CoordinateUtils.getChunkX(chunkCoordinate), CoordinateUtils.getChunkZ(chunkCoordinate), -- ((ChunkSystemChunkStatus)ChunkStatus.LIGHT).moonrise$getWriteRadius(), this, priority -+ ((ChunkSystemChunkStatus)ChunkStatus.LIGHT).moonrise$getWriteRadius(), this, priority, lightEngine.world.getMinecraftWorld() // DivineMC - Chunk System Optimizations - ); - } - -diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java -index df6fbb35e5023b42de0b97434712e04a6b3e66a3..8c6b853c77e5b3af90913e4a878f344b11f8a5aa 100644 ---- a/io/papermc/paper/FeatureHooks.java -+++ b/io/papermc/paper/FeatureHooks.java -@@ -42,10 +42,6 @@ public final class FeatureHooks { - ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.setUnloadDelay(ticks); // Paper - rewrite chunk system - } - -- public static void initChunkTaskScheduler(final boolean useParallelGen) { -- ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.init(useParallelGen); // Paper - Chunk system -- } -- - public static void registerPaperCommands(final Map, PaperSubcommand> commands) { - commands.put(Set.of("fixlight"), new FixLightCommand()); // Paper - rewrite chunk system - commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand()); // Paper - rewrite chunk system -diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index 2c5104b9ae1d2ea902eeac5a1c9d49bc1af67c43..7ebaf03342e8802948b4f412c3f7120927f7b3b3 100644 ---- a/net/minecraft/server/level/ChunkMap.java -+++ b/net/minecraft/server/level/ChunkMap.java -@@ -132,8 +132,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - public final AtomicInteger tickingGenerated = new AtomicInteger(); // Paper - public - private final String storageName; - private final PlayerMap playerMap = new PlayerMap(); -- public final Int2ObjectMap entityMap = new Int2ObjectOpenHashMap<>(); -- private final Long2ByteMap chunkTypeCache = new Long2ByteOpenHashMap(); -+ public final Int2ObjectMap entityMap = new org.bxteam.divinemc.util.map.Int2ObjectConcurrentHashMap<>(); // DivineMC - Chunk System Optimizations -+ private final Long2ByteMap chunkTypeCache = it.unimi.dsi.fastutil.longs.Long2ByteMaps.synchronize(new Long2ByteOpenHashMap()); // DivineMC - Chunk System Optimizations - // Paper - rewrite chunk system - public int serverViewDistance; - public final WorldGenContext worldGenContext; // Paper - public -@@ -283,7 +283,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - final ServerPlayer[] backingSet = inRange.getRawDataUnchecked(); - for (int i = 0, len = inRange.size(); i < len; i++) { -- ++(backingSet[i].mobBackoffCounts[idx]); -+ // DivineMC start - Chunk System Optimizations -+ ServerPlayer player = backingSet[i]; -+ if (player == null) continue; -+ ++(player.mobBackoffCounts[idx]); -+ // DivineMC end - Chunk System Optimizations - } - } - // Paper end - per player mob count backoff -@@ -784,27 +788,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - return false; - } - -- final ServerPlayer[] raw = players.getRawDataUnchecked(); -- final int len = players.size(); -- -- Objects.checkFromIndexSize(0, len, raw.length); -- for (int i = 0; i < len; ++i) { -- final ServerPlayer serverPlayer = raw[i]; -- // Paper start - PlayerNaturallySpawnCreaturesEvent -- com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event; -- blockRange = 16384.0D; -- if (reducedRange) { -- event = serverPlayer.playerNaturallySpawnedEvent; -- if (event == null || event.isCancelled()) continue; -- blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4)); -- } -- if (this.playerIsCloseEnoughForSpawning(serverPlayer, chunkPos, blockRange)) { -- // Paper end - PlayerNaturallySpawnCreaturesEvent -- return true; -- } -- } -- -- return false; -+ return !players.isEmpty(); // DivineMC - Chunk System Optimizations - // Paper end - chunk tick iteration optimisation - } - -@@ -822,10 +806,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - final ServerPlayer[] raw = players.getRawDataUnchecked(); - final int len = players.size(); - -- Objects.checkFromIndexSize(0, len, raw.length); -- for (int i = 0; i < len; ++i) { -+ for (int i = 0; i < raw.length; ++i) { // DivineMC - Chunk System Optimizations - final ServerPlayer player = raw[i]; -- if (this.playerIsCloseEnoughForSpawning(player, chunkPos, 16384.0D)) { // Spigot -+ if (player == null) continue; // DivineMC - Chunk System Optimizations -+ if (this.playerIsCloseEnoughForSpawning(player, chunkPos, (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange^2))) { // Spigot // DivineMC - Chunk System Optimizations - if (ret == null) { - ret = new ArrayList<>(len - i); - ret.add(player); -@@ -1272,6 +1256,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - Runnable updatePlayerTasks = () -> { - for (int i = 0; i < playersLen; ++i) { - final ServerPlayer player = playersRaw[i]; -+ if (player == null) continue; // DivineMC - Chunk System Optimizations - this.updatePlayer(player); - } - -diff --git a/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java -index fd3d0f6cb53bc8b6186f0d86575f21007b2c20ed..7f3c41b59e288364d67534511fc038e6dbb268fa 100644 ---- a/net/minecraft/server/level/DistanceManager.java -+++ b/net/minecraft/server/level/DistanceManager.java -@@ -127,15 +127,13 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches - - public boolean inEntityTickingRange(long chunkPos) { - // Paper start - rewrite chunk system -- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(chunkPos); -- return chunkHolder != null && chunkHolder.isEntityTickingReady(); -+ return this.moonrise$getChunkHolderManager().entityTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization - // Paper end - rewrite chunk system - } - - public boolean inBlockTickingRange(long chunkPos) { - // Paper start - rewrite chunk system -- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(chunkPos); -- return chunkHolder != null && chunkHolder.isTickingReady(); -+ return this.moonrise$getChunkHolderManager().blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization - // Paper end - rewrite chunk system - } - -diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 879d6eb8e72b63bc95d8028cbc2f6e93e516ab1d..6de832e7aec630914e70fb0f11223907ab28298c 100644 ---- a/net/minecraft/server/level/ServerChunkCache.java -+++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -444,8 +444,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - - public boolean isPositionTicking(long chunkPos) { - // Paper start - rewrite chunk system -- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); -- return newChunkHolder != null && newChunkHolder.isTickingReady(); -+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization - // Paper end - rewrite chunk system - } - -diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 740f6324eeb4021bc45d27d6145ff71282c761c2..efda5818ac05cbf06b93a1c983d6e3b18412ca86 100644 ---- a/net/minecraft/server/level/ServerLevel.java -+++ b/net/minecraft/server/level/ServerLevel.java -@@ -179,6 +179,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - public final ServerChunkCache chunkSource; - private final MinecraftServer server; - public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type -+ public final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.LevelHolderData chunkHolderData; // DivineMC - Chunk System optimization - private int lastSpawnChunkRadius; - final EntityTickList entityTickList = new EntityTickList(); - private final ServerWaypointManager waypointManager; -@@ -682,6 +683,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // Paper start - rewrite chunk system - this.moonrise$setEntityLookup(new ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup((ServerLevel)(Object)this, ((ServerLevel)(Object)this).new EntityCallbacks())); - this.chunkTaskScheduler = new ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler((ServerLevel)(Object)this); -+ this.chunkHolderData = new ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.LevelHolderData(); // DivineMC - Chunk System optimization - this.entityDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController( - new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController.EntityRegionFileStorage( - new RegionStorageInfo(levelStorageAccess.getLevelId(), dimension, "entities"), -@@ -825,8 +827,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - @Override - public boolean shouldTickBlocksAt(long chunkPos) { - // Paper start - rewrite chunk system -- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); -- return holder != null && holder.isTickingReady(); -+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization - // Paper end - rewrite chunk system - } - -@@ -882,7 +883,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - - private void optimiseRandomTick(final LevelChunk chunk, final int tickSpeed) { - final LevelChunkSection[] sections = chunk.getSections(); -- final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection((ServerLevel)(Object)this); -+ final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(this); // DivineMC - Chunk System optimization - final ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom simpleRandom = this.simpleRandom; - final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294(); - -@@ -890,42 +891,41 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - final int offsetX = cpos.x << 4; - final int offsetZ = cpos.z << 4; - -+ // DivineMC start - Chunk System optimization - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { -- final int offsetY = (sectionIndex + minSection) << 4; - final LevelChunkSection section = sections[sectionIndex]; -- final net.minecraft.world.level.chunk.PalettedContainer states = section.states; - if (!section.isRandomlyTickingBlocks()) { - continue; - } -+ final int offsetY = (sectionIndex + minSection) << 4; -+ final net.minecraft.world.level.chunk.PalettedContainer states = section.states; - -- final ca.spottedleaf.moonrise.common.list.ShortList tickList = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection)section).moonrise$getTickingBlockList(); -+ final ca.spottedleaf.moonrise.common.list.ShortList tickList = section.moonrise$getTickingBlockList(); - - for (int i = 0; i < tickSpeed; ++i) { -- final int tickingBlocks = tickList.size(); - final int index = simpleRandom.nextInt() & ((16 * 16 * 16) - 1); - -- if (index >= tickingBlocks) { -+ if (index >= tickList.size()) { - // most of the time we fall here - continue; - } - -- final int location = (int)tickList.getRaw(index) & 0xFFFF; -+ final int location = tickList.getRaw(index); - final BlockState state = states.get(location); - - // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! -- final BlockPos pos = new BlockPos((location & 15) | offsetX, ((location >>> (4 + 4)) & 15) | offsetY, ((location >>> 4) & 15) | offsetZ); -+ final BlockPos pos = new BlockPos((location & 15) | offsetX, (location >>> (4 + 4)) | offsetY, ((location >>> 4) & 15) | offsetZ); - -- state.randomTick((ServerLevel)(Object)this, pos, simpleRandom); -+ state.randomTick(this, pos, simpleRandom); - if (doubleTickFluids) { - final FluidState fluidState = state.getFluidState(); - if (fluidState.isRandomlyTicking()) { -- fluidState.randomTick((ServerLevel)(Object)this, pos, simpleRandom); -+ fluidState.randomTick(this, pos, simpleRandom); - } - } - } - } -- -- return; -+ // DivineMC end - Chunk System optimization - } - // Paper end - optimise random ticking - -@@ -2558,16 +2558,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - - public boolean isPositionTickingWithEntitiesLoaded(long chunkPos) { - // Paper start - rewrite chunk system -- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); -- // isTicking implies the chunk is loaded, and the chunk is loaded now implies the entities are loaded -- return chunkHolder != null && chunkHolder.isTickingReady(); -+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization - // Paper end - rewrite chunk system - } - - public boolean isPositionEntityTicking(BlockPos pos) { - // Paper start - rewrite chunk system -- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos)); -- return chunkHolder != null && chunkHolder.isEntityTickingReady(); -+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.contains(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos)); // DivineMC - Chunk System optimization - // Paper end - rewrite chunk system - } - -diff --git a/net/minecraft/server/level/ThreadedLevelLightEngine.java b/net/minecraft/server/level/ThreadedLevelLightEngine.java -index 216c2294f59a9d53613ac249ea63adeaa8a8efa4..b83438852a7b01fef9a736a5b0bc46f15ed1d59b 100644 ---- a/net/minecraft/server/level/ThreadedLevelLightEngine.java -+++ b/net/minecraft/server/level/ThreadedLevelLightEngine.java -@@ -138,7 +138,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - } - } - ); -- }); -+ }, world); // DivineMC - Chunk System Optimizations - - return chunks.size(); - } -diff --git a/net/minecraft/world/level/LevelReader.java b/net/minecraft/world/level/LevelReader.java -index 0842fd6488c8b27d98c4344e1244996b4c0e9912..cba72a86d99fb4b3a3f9f5aefe9993ec8e84abfd 100644 ---- a/net/minecraft/world/level/LevelReader.java -+++ b/net/minecraft/world/level/LevelReader.java -@@ -74,10 +74,27 @@ public interface LevelReader extends ca.spottedleaf.moonrise.patches.chunk_syste - - @Override - default Holder getNoiseBiome(int x, int y, int z) { -- ChunkAccess chunk = this.getChunk(QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false); -+ ChunkAccess chunk = this.fasterChunkAccess(this, QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false); // DivineMC - Chunk System optimization - return chunk != null ? chunk.getNoiseBiome(x, y, z) : this.getUncachedNoiseBiome(x, y, z); - } - -+ // DivineMC start - Chunk System optimization -+ private @Nullable ChunkAccess fasterChunkAccess(LevelReader instance, int x, int z, ChunkStatus chunkStatus, boolean create) { -+ if (!create && instance instanceof net.minecraft.server.level.ServerLevel world) { -+ final net.minecraft.server.level.ChunkHolder holder = (world.getChunkSource().chunkMap).getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); -+ if (holder != null) { -+ final java.util.concurrent.CompletableFuture> future = holder.getFullChunkFuture(); -+ final net.minecraft.server.level.ChunkResult either = future.getNow(null); -+ if (either != null) { -+ final net.minecraft.world.level.chunk.LevelChunk chunk = either.orElse(null); -+ if (chunk != null) return chunk; -+ } -+ } -+ } -+ return instance.getChunk(x, z, chunkStatus, create); -+ } -+ // DivineMC end - Chunk System optimization -+ - Holder getUncachedNoiseBiome(int x, int y, int z); - - boolean isClientSide(); -diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java -index 73962e79a0f3d892e3155443a1b84508b0f4042e..5622345280267792861c8d508d0366cfdfb2c17a 100644 ---- a/net/minecraft/world/level/biome/BiomeManager.java -+++ b/net/minecraft/world/level/biome/BiomeManager.java -@@ -14,6 +14,7 @@ public class BiomeManager { - private static final int ZOOM_MASK = 3; - private final BiomeManager.NoiseBiomeSource noiseBiomeSource; - private final long biomeZoomSeed; -+ private static final double maxOffset = 0.4500000001D; // DivineMC - Chunk System Optimizations - - public BiomeManager(BiomeManager.NoiseBiomeSource noiseBiomeSource, long biomeZoomSeed) { - this.noiseBiomeSource = noiseBiomeSource; -@@ -29,39 +30,65 @@ public class BiomeManager { - } - - public Holder getBiome(BlockPos pos) { -- int i = pos.getX() - 2; -- int i1 = pos.getY() - 2; -- int i2 = pos.getZ() - 2; -- int i3 = i >> 2; -- int i4 = i1 >> 2; -- int i5 = i2 >> 2; -- double d = (i & 3) / 4.0; -- double d1 = (i1 & 3) / 4.0; -- double d2 = (i2 & 3) / 4.0; -- int i6 = 0; -- double d3 = Double.POSITIVE_INFINITY; -+ // DivineMC start - Chunk System Optimizations -+ int xMinus2 = pos.getX() - 2; -+ int yMinus2 = pos.getY() - 2; -+ int zMinus2 = pos.getZ() - 2; -+ int x = xMinus2 >> 2; -+ int y = yMinus2 >> 2; -+ int z = zMinus2 >> 2; -+ double quartX = (double) (xMinus2 & 3) / 4.0; -+ double quartY = (double) (yMinus2 & 3) / 4.0; -+ double quartZ = (double) (zMinus2 & 3) / 4.0; -+ int smallestX = 0; -+ double smallestDist = Double.POSITIVE_INFINITY; -+ for (int biomeX = 0; biomeX < 8; ++biomeX) { -+ boolean everyOtherQuad = (biomeX & 4) == 0; -+ boolean everyOtherPair = (biomeX & 2) == 0; -+ boolean everyOther = (biomeX & 1) == 0; -+ double quartXX = everyOtherQuad ? quartX : quartX - 1.0; -+ double quartYY = everyOtherPair ? quartY : quartY - 1.0; -+ double quartZZ = everyOther ? quartZ : quartZ - 1.0; - -- for (int i7 = 0; i7 < 8; i7++) { -- boolean flag = (i7 & 4) == 0; -- boolean flag1 = (i7 & 2) == 0; -- boolean flag2 = (i7 & 1) == 0; -- int i8 = flag ? i3 : i3 + 1; -- int i9 = flag1 ? i4 : i4 + 1; -- int i10 = flag2 ? i5 : i5 + 1; -- double d4 = flag ? d : d - 1.0; -- double d5 = flag1 ? d1 : d1 - 1.0; -- double d6 = flag2 ? d2 : d2 - 1.0; -- double fiddledDistance = getFiddledDistance(this.biomeZoomSeed, i8, i9, i10, d4, d5, d6); -- if (d3 > fiddledDistance) { -- i6 = i7; -- d3 = fiddledDistance; -+ double maxQuartYY = 0.0, maxQuartZZ = 0.0; -+ if (biomeX != 0) { -+ maxQuartYY = Mth.square(Math.max(quartYY + maxOffset, Math.abs(quartYY - maxOffset))); -+ maxQuartZZ = Mth.square(Math.max(quartZZ + maxOffset, Math.abs(quartZZ - maxOffset))); -+ double maxQuartXX = Mth.square(Math.max(quartXX + maxOffset, Math.abs(quartXX - maxOffset))); -+ if (smallestDist < maxQuartXX + maxQuartYY + maxQuartZZ) continue; - } -- } -+ int xx = everyOtherQuad ? x : x + 1; -+ int yy = everyOtherPair ? y : y + 1; -+ int zz = everyOther ? z : z + 1; -+ -+ long seed = LinearCongruentialGenerator.next(this.biomeZoomSeed, xx); -+ seed = LinearCongruentialGenerator.next(seed, yy); -+ seed = LinearCongruentialGenerator.next(seed, zz); -+ seed = LinearCongruentialGenerator.next(seed, xx); -+ seed = LinearCongruentialGenerator.next(seed, yy); -+ seed = LinearCongruentialGenerator.next(seed, zz); -+ double offsetX = getFiddle(seed); -+ double sqrX = Mth.square(quartXX + offsetX); -+ if (biomeX != 0 && smallestDist < sqrX + maxQuartYY + maxQuartZZ) continue; -+ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed); -+ double offsetY = getFiddle(seed); -+ double sqrY = Mth.square(quartYY + offsetY); -+ if (biomeX != 0 && smallestDist < sqrX + sqrY + maxQuartZZ) continue; -+ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed); -+ double offsetZ = getFiddle(seed); -+ double biomeDist = sqrX + sqrY + Mth.square(quartZZ + offsetZ); - -- int i7x = (i6 & 4) == 0 ? i3 : i3 + 1; -- int i11 = (i6 & 2) == 0 ? i4 : i4 + 1; -- int i12 = (i6 & 1) == 0 ? i5 : i5 + 1; -- return this.noiseBiomeSource.getNoiseBiome(i7x, i11, i12); -+ if (smallestDist > biomeDist) { -+ smallestX = biomeX; -+ smallestDist = biomeDist; -+ } -+ } -+ return this.noiseBiomeSource.getNoiseBiome( -+ (smallestX & 4) == 0 ? x : x + 1, -+ (smallestX & 2) == 0 ? y : y + 1, -+ (smallestX & 1) == 0 ? z : z + 1 -+ ); -+ // DivineMC end - Chunk System Optimizations - } - - public Holder getNoiseBiomeAtPosition(double x, double y, double z) { -diff --git a/net/minecraft/world/level/biome/TheEndBiomeSource.java b/net/minecraft/world/level/biome/TheEndBiomeSource.java -index cf3172be76fa4c7987ed569138439ff42f92fa7f..ed3c470056855a520a110ac7014f7839bcc85b88 100644 ---- a/net/minecraft/world/level/biome/TheEndBiomeSource.java -+++ b/net/minecraft/world/level/biome/TheEndBiomeSource.java -@@ -27,6 +27,33 @@ public class TheEndBiomeSource extends BiomeSource { - private final Holder islands; - private final Holder barrens; - -+ // DivineMC start - Chunk System Optimizations -+ private Holder getBiomeForNoiseGenVanilla(int x, int y, int z, Climate.Sampler noise) { -+ int i = QuartPos.toBlock(x); -+ int j = QuartPos.toBlock(y); -+ int k = QuartPos.toBlock(z); -+ int l = SectionPos.blockToSectionCoord(i); -+ int m = SectionPos.blockToSectionCoord(k); -+ if ((long)l * (long)l + (long)m * (long)m <= 4096L) { -+ return this.end; -+ } else { -+ int n = (SectionPos.blockToSectionCoord(i) * 2 + 1) * 8; -+ int o = (SectionPos.blockToSectionCoord(k) * 2 + 1) * 8; -+ double d = noise.erosion().compute(new DensityFunction.SinglePointContext(n, j, o)); -+ if (d > 0.25D) { -+ return this.highlands; -+ } else if (d >= -0.0625D) { -+ return this.midlands; -+ } else { -+ return d < -0.21875D ? this.islands : this.barrens; -+ } -+ } -+ } -+ -+ private final ThreadLocal>> cache = ThreadLocal.withInitial(it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap::new); -+ private final int cacheCapacity = 1024; -+ // DivineMC end - Chunk System Optimizations -+ - public static TheEndBiomeSource create(HolderGetter biomeGetter) { - return new TheEndBiomeSource( - biomeGetter.getOrThrow(Biomes.THE_END), -@@ -55,26 +82,24 @@ public class TheEndBiomeSource extends BiomeSource { - return CODEC; - } - -+ // DivineMC start - Chunk System Optimizations - @Override -- public Holder getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) { -- int blockPosX = QuartPos.toBlock(x); -- int blockPosY = QuartPos.toBlock(y); -- int blockPosZ = QuartPos.toBlock(z); -- int sectionPosX = SectionPos.blockToSectionCoord(blockPosX); -- int sectionPosZ = SectionPos.blockToSectionCoord(blockPosZ); -- if ((long)sectionPosX * sectionPosX + (long)sectionPosZ * sectionPosZ <= 4096L) { -- return this.end; -+ public Holder getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler multiNoiseSampler) { -+ final long key = net.minecraft.world.level.ChunkPos.asLong(biomeX, biomeZ); -+ final it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap> cacheThreadLocal = cache.get(); -+ final Holder biome = cacheThreadLocal.get(key); -+ if (biome != null) { -+ return biome; - } else { -- int i = (SectionPos.blockToSectionCoord(blockPosX) * 2 + 1) * 8; -- int i1 = (SectionPos.blockToSectionCoord(blockPosZ) * 2 + 1) * 8; -- double d = sampler.erosion().compute(new DensityFunction.SinglePointContext(i, blockPosY, i1)); -- if (d > 0.25) { -- return this.highlands; -- } else if (d >= -0.0625) { -- return this.midlands; -- } else { -- return d < -0.21875 ? this.islands : this.barrens; -+ final Holder gennedBiome = getBiomeForNoiseGenVanilla(biomeX, biomeY, biomeZ, multiNoiseSampler); -+ cacheThreadLocal.put(key, gennedBiome); -+ if (cacheThreadLocal.size() > cacheCapacity) { -+ for (int i = 0; i < cacheCapacity / 16; i ++) { -+ cacheThreadLocal.removeFirst(); -+ } - } -+ return gennedBiome; - } - } -+ // DivineMC end - Chunk System Optimizations - } -diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java -index 4db7ec2647b9f08536dc5253dac0fa8d3044e38b..e3abc97a1a66988e44b1ed78b76a198b82051da1 100644 ---- a/net/minecraft/world/level/chunk/LevelChunkSection.java -+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -23,6 +23,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ - public short tickingFluidCount; - public final PalettedContainer states; - private PalettedContainer> biomes; // CraftBukkit - read/write -+ private static final int sliceSize = 4; // DivineMC - Chunk System Optimizations - - // Paper start - block counting - private static final it.unimi.dsi.fastutil.shorts.ShortArrayList FULL_LIST = new it.unimi.dsi.fastutil.shorts.ShortArrayList(16*16*16); -@@ -296,7 +297,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ - } - - public boolean maybeHas(Predicate predicate) { -- return this.states.maybeHas(predicate); -+ return this.states.maybeHasOrCatch(predicate, Blocks.AIR.defaultBlockState()); // DivineMC - Chunk System Optimizations - } - - public Holder getNoiseBiome(int x, int y, int z) { -@@ -312,13 +313,15 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ - PalettedContainer> palettedContainer = this.biomes.recreate(); - int i = 4; - -- for (int i1 = 0; i1 < 4; i1++) { -- for (int i2 = 0; i2 < 4; i2++) { -- for (int i3 = 0; i3 < 4; i3++) { -- palettedContainer.getAndSetUnchecked(i1, i2, i3, biomeResolver.getNoiseBiome(x + i1, y + i2, z + i3, climateSampler)); -+ // DivineMC start - Chunk System Optimizations -+ for (int posY = 0; posY < sliceSize; ++posY) { -+ for (int posZ = 0; posZ < sliceSize; ++posZ) { -+ for (int posX = 0; posX < sliceSize; ++posX) { -+ palettedContainer.getAndSetUnchecked(posX, posY, posZ, biomeResolver.getNoiseBiome(x + posX, y + posY, z + posZ, climateSampler)); - } - } - } -+ // DivineMC end - Chunk System Optimizations - - this.biomes = palettedContainer; - } -diff --git a/net/minecraft/world/level/chunk/LinearPalette.java b/net/minecraft/world/level/chunk/LinearPalette.java -index 2073f6ff41aa570102621d183ee890b076267d54..25d46d1dff23a9bffd135d6954b551991e175cd4 100644 ---- a/net/minecraft/world/level/chunk/LinearPalette.java -+++ b/net/minecraft/world/level/chunk/LinearPalette.java -@@ -12,7 +12,7 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat - private final T[] values; - private final PaletteResize resizeHandler; - private final int bits; -- private int size; -+ private volatile int size; // DivineMC - Chunk System Optimizations - - // Paper start - optimise palette reads - @Override -@@ -49,11 +49,14 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat - - @Override - public int idFor(T state) { -- for (int i = 0; i < this.size; i++) { -- if (this.values[i] == state) { -+ // DivineMC start - Chunk System Optimizations -+ final T[] values = this.values; -+ for (int i = 0; i < values.length; i++) { -+ if (values[i] == state) { - return i; - } - } -+ // DivineMC end - Chunk System Optimizations - - int ix = this.size; - if (ix < this.values.length) { -@@ -67,17 +70,23 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat - - @Override - public boolean maybeHas(Predicate filter) { -- for (int i = 0; i < this.size; i++) { -- if (filter.test(this.values[i])) { -+ // DivineMC start - Chunk System Optimizations -+ final T[] values = this.values; -+ final int currentSize = this.size; -+ -+ for (int i = 0; i < currentSize; i++) { -+ T value = values[i]; -+ if (value != null && filter.test(value)) { - return true; - } - } -+ // DivineMC end - Chunk System Optimizations - - return false; - } - - @Override -- public T valueFor(int id) { -+ public synchronized T valueFor(int id) { // DivineMC - Chunk System Optimizations - if (id >= 0 && id < this.size) { - return this.values[id]; - } else { -diff --git a/net/minecraft/world/level/chunk/Palette.java b/net/minecraft/world/level/chunk/Palette.java -index a80b2e9dceea423180a9c390d1970317dff4f1b0..6d9dfc1837dccef2073da180aaaf68b07b04a8e3 100644 ---- a/net/minecraft/world/level/chunk/Palette.java -+++ b/net/minecraft/world/level/chunk/Palette.java -@@ -10,6 +10,12 @@ public interface Palette extends ca.spottedleaf.moonrise.patches.fast_palette - - boolean maybeHas(Predicate filter); - -+ // DivineMC start - Chunk System Optimizations -+ public default boolean maybeHasOrCatch(Predicate filter, T defaultValue) { -+ return this.maybeHas(filter); -+ } -+ // DivineMC end - Chunk System Optimizations -+ - T valueFor(int id); - - void read(FriendlyByteBuf buffer); -diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java -index baa006132b1fa3d73fd4a14f6bc747a3957d1a0c..ce41cd702a61d96552567b310cf59b22d9363eeb 100644 ---- a/net/minecraft/world/level/chunk/PalettedContainer.java -+++ b/net/minecraft/world/level/chunk/PalettedContainer.java -@@ -392,6 +392,12 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - return this.data.palette.maybeHas(predicate); - } - -+ // DivineMC start - Chunk System Optimizations -+ public boolean maybeHasOrCatch(Predicate predicate, @org.jetbrains.annotations.NotNull T defaultValue) { -+ return this.data.palette.maybeHasOrCatch(predicate, defaultValue); -+ } -+ // DivineMC end - Chunk System Optimizations -+ - @Override - public PalettedContainer copy() { - return new PalettedContainer<>(this, this.presetValues); // Paper - Anti-Xray - Add preset values -diff --git a/net/minecraft/world/level/chunk/ProtoChunk.java b/net/minecraft/world/level/chunk/ProtoChunk.java -index aa085d8a78a3fb40a214e4b152ab04d9a409f76f..2aea410b5ba3156cf08f92ffc554ae64c9e90664 100644 ---- a/net/minecraft/world/level/chunk/ProtoChunk.java -+++ b/net/minecraft/world/level/chunk/ProtoChunk.java -@@ -46,7 +46,7 @@ public class ProtoChunk extends ChunkAccess { - @Nullable - private volatile LevelLightEngine lightEngine; - private volatile ChunkStatus status = ChunkStatus.EMPTY; -- private final List entities = Lists.newArrayList(); -+ private final List entities = Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System optimization - @Nullable - private CarvingMask carvingMask; - @Nullable -diff --git a/net/minecraft/world/level/chunk/SingleValuePalette.java b/net/minecraft/world/level/chunk/SingleValuePalette.java -index 2ffae24b0cb1a20c7d5a8520f1b5197c2cedea11..c3ec5e5645f680a915c95d833b589b680c82c35d 100644 ---- a/net/minecraft/world/level/chunk/SingleValuePalette.java -+++ b/net/minecraft/world/level/chunk/SingleValuePalette.java -@@ -11,7 +11,7 @@ import org.apache.commons.lang3.Validate; - public class SingleValuePalette implements Palette, ca.spottedleaf.moonrise.patches.fast_palette.FastPalette { // Paper - optimise palette reads - private final IdMap registry; - @Nullable -- private T value; -+ private volatile T value; // DivineMC - Chunk System Optimizations - private final PaletteResize resizeHandler; - - // Paper start - optimise palette reads -@@ -44,6 +44,7 @@ public class SingleValuePalette implements Palette, ca.spottedleaf.moonris - if (this.value != null && this.value != state) { - return this.resizeHandler.onResize(1, state); - } else { -+ if (state == null) throw new IllegalArgumentException("Null state not allowed"); // DivineMC - Chunk System Optimizations - this.value = state; - // Paper start - optimise palette reads - if (this.rawPalette != null) { -@@ -63,6 +64,19 @@ public class SingleValuePalette implements Palette, ca.spottedleaf.moonris - } - } - -+ // DivineMC start - Chunk System Optimizations -+ @Override -+ public boolean maybeHasOrCatch(final Predicate filter, final T defaultValue) { -+ if (this.value == null) { -+ if (defaultValue == null) throw new IllegalArgumentException("Default value for 'maybeHasOrCatch' cannot be null!"); -+ this.value = defaultValue; -+ return maybeHas(filter); -+ } else { -+ return filter.test(this.value); -+ } -+ } -+ // DivineMC end - Chunk System Optimizations -+ - @Override - public T valueFor(int id) { - if (this.value != null && id == 0) { -diff --git a/net/minecraft/world/level/chunk/storage/IOWorker.java b/net/minecraft/world/level/chunk/storage/IOWorker.java -index 27e1edbd8d8ffd80c1a3df17bc47f4a6936619f7..67d48ad11671e72e9dfeafbd64dc27031bd395d5 100644 ---- a/net/minecraft/world/level/chunk/storage/IOWorker.java -+++ b/net/minecraft/world/level/chunk/storage/IOWorker.java -@@ -212,7 +212,38 @@ public class IOWorker implements ChunkScanAccess, AutoCloseable { - }); - } - -+ // DivineMC start - Chunk System optimization -+ private void checkHardLimit() { -+ if (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheLimit) { -+ LOGGER.warn("Chunk data cache size exceeded hard limit ({} >= {}), forcing writes to disk (you can increase chunkDataCacheLimit in c2me.toml)", this.pendingWrites.size(), org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheLimit); -+ while (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit * 0.75) { -+ writeResult0(); -+ } -+ } -+ } -+ -+ private void writeResult0() { -+ java.util.Iterator> iterator = this.pendingWrites.entrySet().iterator(); -+ if (iterator.hasNext()) { -+ java.util.Map.Entry entry = iterator.next(); -+ iterator.remove(); -+ this.runStore(entry.getKey(), entry.getValue()); -+ } -+ } -+ // DivineMC end - Chunk System optimization -+ - private void storePendingChunk() { -+ // DivineMC start - Chunk System optimization -+ if (!this.pendingWrites.isEmpty()) { -+ checkHardLimit(); -+ if (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit) { -+ int writeFrequency = Math.min(1, (this.pendingWrites.size() - (int) org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit) / 16); -+ for (int i = 0; i < writeFrequency; i++) { -+ writeResult0(); -+ } -+ } -+ } -+ // DivineMC end - Chunk System optimization - Entry entry = this.pendingWrites.pollFirstEntry(); - if (entry != null) { - this.runStore(entry.getKey(), entry.getValue()); -diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 8d1174f25e0e90d0533970f4ddd8448442024936..c98cb390bda4b536f97445f228e06aaebcd84609 100644 ---- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -269,7 +269,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - - protected RegionFileStorage(RegionStorageInfo info, Path folder, boolean sync) { // Paper - protected - this.folder = folder; -- this.sync = sync; -+ this.sync = Boolean.parseBoolean(System.getProperty("com.ishland.c2me.chunkio.syncDiskWrites", String.valueOf(sync))); // DivineMC - C2ME: sync disk writes - this.info = info; - this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers - } -diff --git a/net/minecraft/world/level/levelgen/Aquifer.java b/net/minecraft/world/level/levelgen/Aquifer.java -index c62a15ea4a1bb22e7bcc2fc544acf8a601892029..bc67039f8374ae4e471ca14e0c623e6bf334020f 100644 ---- a/net/minecraft/world/level/levelgen/Aquifer.java -+++ b/net/minecraft/world/level/levelgen/Aquifer.java -@@ -85,6 +85,15 @@ public interface Aquifer { - private final int minGridZ; - private final int gridSizeX; - private final int gridSizeZ; -+ // DivineMC start - Chunk System Optimizations -+ private int c2me$dist1; -+ private int c2me$dist2; -+ private int c2me$dist3; -+ private long c2me$pos1; -+ private long c2me$pos2; -+ private long c2me$pos3; -+ private double c2me$mutableDoubleThingy; -+ // DivineMC end - Chunk System Optimizations - private static final int[][] SURFACE_SAMPLING_OFFSETS_IN_CHUNKS = new int[][]{ - {0, 0}, {-2, -1}, {-1, -1}, {0, -1}, {1, -1}, {-3, 0}, {-2, 0}, {-1, 0}, {1, 0}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1} - }; -@@ -120,6 +129,36 @@ public interface Aquifer { - this.aquiferCache = new Aquifer.FluidStatus[i4]; - this.aquiferLocationCache = new long[i4]; - Arrays.fill(this.aquiferLocationCache, Long.MAX_VALUE); -+ // DivineMC start - Chunk System Optimizations -+ if (this.aquiferLocationCache.length % (this.gridSizeX * this.gridSizeZ) != 0) { -+ throw new AssertionError("Array length"); -+ } -+ -+ int sizeY = this.aquiferLocationCache.length / (this.gridSizeX * this.gridSizeZ); -+ -+ final RandomSource random = org.bxteam.divinemc.util.RandomUtil.getRandom(this.positionalRandomFactory); -+ // index: y, z, x -+ for (int y = 0; y < sizeY; y++) { -+ for (int z = 0; z < this.gridSizeZ; z++) { -+ for (int x = 0; x < this.gridSizeX; x++) { -+ final int x1 = x + this.minGridX; -+ final int y1 = y + this.minGridY; -+ final int z1 = z + this.minGridZ; -+ org.bxteam.divinemc.util.RandomUtil.derive(this.positionalRandomFactory, random, x1, y1, z1); -+ int x2 = x1 * 16 + random.nextInt(10); -+ int y2 = y1 * 12 + random.nextInt(9); -+ int z2 = z1 * 16 + random.nextInt(10); -+ int index = this.getIndex(x1, y1, z1); -+ this.aquiferLocationCache[index] = BlockPos.asLong(x2, y2, z2); -+ } -+ } -+ } -+ for (long blockPosition : this.aquiferLocationCache) { -+ if (blockPosition == Long.MAX_VALUE) { -+ throw new AssertionError("Array initialization"); -+ } -+ } -+ // DivineMC end - Chunk System Optimizations - } - - private int getIndex(int gridX, int gridY, int gridZ) { -@@ -132,140 +171,24 @@ public interface Aquifer { - @Nullable - @Override - public BlockState computeSubstance(DensityFunction.FunctionContext context, double substance) { -+ // DivineMC start - Chunk System Optimizations - int i = context.blockX(); -- int i1 = context.blockY(); -- int i2 = context.blockZ(); -+ int j = context.blockY(); -+ int k = context.blockZ(); - if (substance > 0.0) { - this.shouldScheduleFluidUpdate = false; - return null; - } else { -- Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(i, i1, i2); -- if (fluidStatus.at(i1).is(Blocks.LAVA)) { -+ Aquifer.FluidStatus fluidLevel = this.globalFluidPicker.computeFluid(i, j, k); -+ if (fluidLevel.at(j).is(Blocks.LAVA)) { - this.shouldScheduleFluidUpdate = false; - return Blocks.LAVA.defaultBlockState(); - } else { -- int i3 = Math.floorDiv(i - 5, 16); -- int i4 = Math.floorDiv(i1 + 1, 12); -- int i5 = Math.floorDiv(i2 - 5, 16); -- int i6 = Integer.MAX_VALUE; -- int i7 = Integer.MAX_VALUE; -- int i8 = Integer.MAX_VALUE; -- int i9 = Integer.MAX_VALUE; -- long l = 0L; -- long l1 = 0L; -- long l2 = 0L; -- long l3 = 0L; -- -- for (int i10 = 0; i10 <= 1; i10++) { -- for (int i11 = -1; i11 <= 1; i11++) { -- for (int i12 = 0; i12 <= 1; i12++) { -- int i13 = i3 + i10; -- int i14 = i4 + i11; -- int i15 = i5 + i12; -- int index = this.getIndex(i13, i14, i15); -- long l4 = this.aquiferLocationCache[index]; -- long l5; -- if (l4 != Long.MAX_VALUE) { -- l5 = l4; -- } else { -- RandomSource randomSource = this.positionalRandomFactory.at(i13, i14, i15); -- l5 = BlockPos.asLong( -- i13 * 16 + randomSource.nextInt(10), i14 * 12 + randomSource.nextInt(9), i15 * 16 + randomSource.nextInt(10) -- ); -- this.aquiferLocationCache[index] = l5; -- } -- -- int i16 = BlockPos.getX(l5) - i; -- int i17 = BlockPos.getY(l5) - i1; -- int i18 = BlockPos.getZ(l5) - i2; -- int i19 = i16 * i16 + i17 * i17 + i18 * i18; -- if (i6 >= i19) { -- l3 = l2; -- l2 = l1; -- l1 = l; -- l = l5; -- i9 = i8; -- i8 = i7; -- i7 = i6; -- i6 = i19; -- } else if (i7 >= i19) { -- l3 = l2; -- l2 = l1; -- l1 = l5; -- i9 = i8; -- i8 = i7; -- i7 = i19; -- } else if (i8 >= i19) { -- l3 = l2; -- l2 = l5; -- i9 = i8; -- i8 = i19; -- } else if (i9 >= i19) { -- l3 = l5; -- i9 = i19; -- } -- } -- } -- } -- -- Aquifer.FluidStatus aquiferStatus = this.getAquiferStatus(l); -- double d = similarity(i6, i7); -- BlockState blockState = aquiferStatus.at(i1); -- if (d <= 0.0) { -- if (d >= FLOWING_UPDATE_SIMULARITY) { -- Aquifer.FluidStatus aquiferStatus1 = this.getAquiferStatus(l1); -- this.shouldScheduleFluidUpdate = !aquiferStatus.equals(aquiferStatus1); -- } else { -- this.shouldScheduleFluidUpdate = false; -- } -- -- return blockState; -- } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, i1 - 1, i2).at(i1 - 1).is(Blocks.LAVA)) { -- this.shouldScheduleFluidUpdate = true; -- return blockState; -- } else { -- MutableDouble mutableDouble = new MutableDouble(Double.NaN); -- Aquifer.FluidStatus aquiferStatus2 = this.getAquiferStatus(l1); -- double d1 = d * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus2); -- if (substance + d1 > 0.0) { -- this.shouldScheduleFluidUpdate = false; -- return null; -- } else { -- Aquifer.FluidStatus aquiferStatus3 = this.getAquiferStatus(l2); -- double d2 = similarity(i6, i8); -- if (d2 > 0.0) { -- double d3 = d * d2 * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus3); -- if (substance + d3 > 0.0) { -- this.shouldScheduleFluidUpdate = false; -- return null; -- } -- } -- -- double d3 = similarity(i7, i8); -- if (d3 > 0.0) { -- double d4 = d * d3 * this.calculatePressure(context, mutableDouble, aquiferStatus2, aquiferStatus3); -- if (substance + d4 > 0.0) { -- this.shouldScheduleFluidUpdate = false; -- return null; -- } -- } -- -- boolean flag = !aquiferStatus.equals(aquiferStatus2); -- boolean flag1 = d3 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus2.equals(aquiferStatus3); -- boolean flag2 = d2 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus.equals(aquiferStatus3); -- if (!flag && !flag1 && !flag2) { -- this.shouldScheduleFluidUpdate = d2 >= FLOWING_UPDATE_SIMULARITY -- && similarity(i6, i9) >= FLOWING_UPDATE_SIMULARITY -- && !aquiferStatus.equals(this.getAquiferStatus(l3)); -- } else { -- this.shouldScheduleFluidUpdate = true; -- } -- -- return blockState; -- } -- } -+ aquiferExtracted$refreshDistPosIdx(i, j, k); -+ return aquiferExtracted$applyPost(context, substance, j, i, k); - } - } -+ // DivineMC end - Chunk System Optimizations - } - - @Override -@@ -278,65 +201,28 @@ public interface Aquifer { - return 1.0 - Math.abs(secondDistance - firstDistance) / 25.0; - } - -+ // DivineMC start - Chunk System Optimizations - private double calculatePressure( -- DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus firstFluid, Aquifer.FluidStatus secondFluid -+ DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2 // DivineMC - rename args - ) { - int i = context.blockY(); -- BlockState blockState = firstFluid.at(i); -- BlockState blockState1 = secondFluid.at(i); -- if ((!blockState.is(Blocks.LAVA) || !blockState1.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState1.is(Blocks.LAVA))) { -- int abs = Math.abs(firstFluid.fluidLevel - secondFluid.fluidLevel); -+ BlockState blockState = fluidLevel.at(i); -+ BlockState blockState2 = fluidLevel2.at(i); -+ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) { -+ int abs = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel); - if (abs == 0) { - return 0.0; - } else { -- double d = 0.5 * (firstFluid.fluidLevel + secondFluid.fluidLevel); -- double d1 = i + 0.5 - d; -- double d2 = abs / 2.0; -- double d3 = 0.0; -- double d4 = 2.5; -- double d5 = 1.5; -- double d6 = 3.0; -- double d7 = 10.0; -- double d8 = 3.0; -- double d9 = d2 - Math.abs(d1); -- double d11; -- if (d1 > 0.0) { -- double d10 = 0.0 + d9; -- if (d10 > 0.0) { -- d11 = d10 / 1.5; -- } else { -- d11 = d10 / 2.5; -- } -- } else { -- double d10 = 3.0 + d9; -- if (d10 > 0.0) { -- d11 = d10 / 3.0; -- } else { -- d11 = d10 / 10.0; -- } -- } -- -- double d10x = 2.0; -- double d12; -- if (!(d11 < -2.0) && !(d11 > 2.0)) { -- double value = substance.getValue(); -- if (Double.isNaN(value)) { -- double d13 = this.barrierNoise.compute(context); -- substance.setValue(d13); -- d12 = d13; -- } else { -- d12 = value; -- } -- } else { -- d12 = 0.0; -- } -+ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel); -+ final double q = aquiferExtracted$getQ(i, d, abs); - -- return 2.0 * (d12 + d11); -+ return aquiferExtracted$postCalculateDensity(context, substance, q); - } - } else { - return 2.0; - } - } -+ // DivineMC end - Chunk System Optimizations - - private int gridX(int x) { - return Math.floorDiv(x, 16); -@@ -350,23 +236,25 @@ public interface Aquifer { - return Math.floorDiv(z, 16); - } - -- private Aquifer.FluidStatus getAquiferStatus(long packedPos) { -- int x = BlockPos.getX(packedPos); -- int y = BlockPos.getY(packedPos); -- int z = BlockPos.getZ(packedPos); -- int i = this.gridX(x); -- int i1 = this.gridY(y); -- int i2 = this.gridZ(z); -- int index = this.getIndex(i, i1, i2); -- Aquifer.FluidStatus fluidStatus = this.aquiferCache[index]; -- if (fluidStatus != null) { -- return fluidStatus; -+ // DivineMC start - Chunk System Optimizations -+ private Aquifer.FluidStatus getAquiferStatus(long pos) { -+ int i = BlockPos.getX(pos); -+ int j = BlockPos.getY(pos); -+ int k = BlockPos.getZ(pos); -+ int l = i >> 4; // C2ME - inline: floorDiv(i, 16) -+ int m = Math.floorDiv(j, 12); // C2ME - inline -+ int n = k >> 4; // C2ME - inline: floorDiv(k, 16) -+ int o = this.getIndex(l, m, n); -+ Aquifer.FluidStatus fluidLevel = this.aquiferCache[o]; -+ if (fluidLevel != null) { -+ return fluidLevel; - } else { -- Aquifer.FluidStatus fluidStatus1 = this.computeFluid(x, y, z); -- this.aquiferCache[index] = fluidStatus1; -- return fluidStatus1; -+ Aquifer.FluidStatus fluidLevel2 = this.computeFluid(i, j, k); -+ this.aquiferCache[o] = fluidLevel2; -+ return fluidLevel2; - } - } -+ // DivineMC end - Chunk System Optimizations - - private Aquifer.FluidStatus computeFluid(int x, int y, int z) { - Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(x, y, z); -@@ -407,22 +295,21 @@ public interface Aquifer { - } - - private int computeSurfaceLevel(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int maxSurfaceLevel, boolean fluidPresent) { -- DensityFunction.SinglePointContext singlePointContext = new DensityFunction.SinglePointContext(x, y, z); -+ // DivineMC start - Chunk System Optimizations -+ DensityFunction.SinglePointContext unblendedNoisePos = new DensityFunction.SinglePointContext(x, y, z); - double d; - double d1; -- if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, singlePointContext)) { -+ if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, unblendedNoisePos)) { - d = -1.0; - d1 = -1.0; - } else { - int i = maxSurfaceLevel + 8 - y; -- int i1 = 64; -- double d2 = fluidPresent ? Mth.clampedMap((double)i, 0.0, 64.0, 1.0, 0.0) : 0.0; -- double d3 = Mth.clamp(this.fluidLevelFloodednessNoise.compute(singlePointContext), -1.0, 1.0); -- double d4 = Mth.map(d2, 1.0, 0.0, -0.3, 0.8); -- double d5 = Mth.map(d2, 1.0, 0.0, -0.8, 0.4); -- d = d3 - d5; -- d1 = d3 - d4; -+ double f = fluidPresent ? Mth.clampedLerp(1.0, 0.0, ((double) i) / 64.0) : 0.0; // inline -+ double g = Mth.clamp(this.fluidLevelFloodednessNoise.compute(unblendedNoisePos), -1.0, 1.0); -+ d = g + 0.8 + (f - 1.0) * 1.2; // inline -+ d1 = g + 0.3 + (f - 1.0) * 1.1; // inline - } -+ // DivineMC end - Chunk System Optimizations - - int i; - if (d1 > 0.0) { -@@ -453,12 +340,12 @@ public interface Aquifer { - private BlockState computeFluidType(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int surfaceLevel) { - BlockState blockState = fluidStatus.fluidType; - if (surfaceLevel <= -10 && surfaceLevel != DimensionType.WAY_BELOW_MIN_Y && fluidStatus.fluidType != Blocks.LAVA.defaultBlockState()) { -- int i = 64; -- int i1 = 40; -- int i2 = Math.floorDiv(x, 64); -- int i3 = Math.floorDiv(y, 40); -- int i4 = Math.floorDiv(z, 64); -- double d = this.lavaNoise.compute(new DensityFunction.SinglePointContext(i2, i3, i4)); -+ // DivineMC start - Chunk System Optimizations -+ int k = x >> 6; -+ int l = Math.floorDiv(y, 40); -+ int m = z >> 6; -+ double d = this.lavaNoise.compute(new DensityFunction.SinglePointContext(k, l, m)); -+ // DivineMC end - Chunk System Optimizations - if (Math.abs(d) > 0.3) { - blockState = Blocks.LAVA.defaultBlockState(); - } -@@ -466,5 +353,183 @@ public interface Aquifer { - - return blockState; - } -+ -+ // DivineMC start - Chunk System Optimizations -+ private @org.jetbrains.annotations.Nullable BlockState aquiferExtracted$applyPost(DensityFunction.FunctionContext pos, double density, int j, int i, int k) { -+ Aquifer.FluidStatus fluidLevel2 = this.getAquiferStatus(this.c2me$pos1); -+ double d = similarity(this.c2me$dist1, this.c2me$dist2); -+ BlockState blockState = fluidLevel2.at(j); -+ if (d <= 0.0) { -+ this.shouldScheduleFluidUpdate = d >= FLOWING_UPDATE_SIMULARITY; -+ return blockState; -+ } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, j - 1, k).at(j - 1).is(Blocks.LAVA)) { -+ this.shouldScheduleFluidUpdate = true; -+ return blockState; -+ } else { -+ this.c2me$mutableDoubleThingy = Double.NaN; -+ Aquifer.FluidStatus fluidLevel3 = this.getAquiferStatus(this.c2me$pos2); -+ double e = d * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel3); -+ if (density + e > 0.0) { -+ this.shouldScheduleFluidUpdate = false; -+ return null; -+ } else { -+ return aquiferExtracted$getFinalBlockState(pos, density, d, fluidLevel2, fluidLevel3, blockState); -+ } -+ } -+ } -+ -+ private BlockState aquiferExtracted$getFinalBlockState(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, Aquifer.FluidStatus fluidLevel3, BlockState blockState) { -+ Aquifer.FluidStatus fluidLevel4 = this.getAquiferStatus(this.c2me$pos3); -+ double f = similarity(this.c2me$dist1, this.c2me$dist3); -+ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel2, f, fluidLevel4)) return null; -+ -+ double g = similarity(this.c2me$dist2, this.c2me$dist3); -+ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel3, g, fluidLevel4)) return null; -+ -+ this.shouldScheduleFluidUpdate = true; -+ return blockState; -+ } -+ -+ private boolean aquiferExtracted$extractedCheckFG(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, double f, Aquifer.FluidStatus fluidLevel4) { -+ if (f > 0.0) { -+ double g = d * f * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel4); -+ if (density + g > 0.0) { -+ this.shouldScheduleFluidUpdate = false; -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ private void aquiferExtracted$refreshDistPosIdx(int x, int y, int z) { -+ int gx = (x - 5) >> 4; -+ int gy = Math.floorDiv(y + 1, 12); -+ int gz = (z - 5) >> 4; -+ int dist1 = Integer.MAX_VALUE; -+ int dist2 = Integer.MAX_VALUE; -+ int dist3 = Integer.MAX_VALUE; -+ long pos1 = 0; -+ long pos2 = 0; -+ long pos3 = 0; -+ -+ for (int offY = -1; offY <= 1; ++offY) { -+ for (int offZ = 0; offZ <= 1; ++offZ) { -+ for (int offX = 0; offX <= 1; ++offX) { -+ int posIdx = this.getIndex(gx + offX, gy + offY, gz + offZ); -+ -+ long position = this.aquiferLocationCache[posIdx]; -+ -+ int dx = BlockPos.getX(position) - x; -+ int dy = BlockPos.getY(position) - y; -+ int dz = BlockPos.getZ(position) - z; -+ int dist = dx * dx + dy * dy + dz * dz; -+ -+ if (dist3 >= dist) { -+ pos3 = position; -+ dist3 = dist; -+ } -+ if (dist2 >= dist) { -+ pos3 = pos2; -+ dist3 = dist2; -+ pos2 = position; -+ dist2 = dist; -+ } -+ if (dist1 >= dist) { -+ pos2 = pos1; -+ dist2 = dist1; -+ pos1 = position; -+ dist1 = dist; -+ } -+ } -+ } -+ } -+ -+ this.c2me$dist1 = dist1; -+ this.c2me$dist2 = dist2; -+ this.c2me$dist3 = dist3; -+ this.c2me$pos1 = pos1; -+ this.c2me$pos2 = pos2; -+ this.c2me$pos3 = pos3; -+ } -+ -+ private double c2me$calculateDensityModified( -+ DensityFunction.FunctionContext pos, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2 -+ ) { -+ int i = pos.blockY(); -+ BlockState blockState = fluidLevel.at(i); -+ BlockState blockState2 = fluidLevel2.at(i); -+ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) { -+ int j = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel); -+ if (j == 0) { -+ return 0.0; -+ } else { -+ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel); -+ final double q = aquiferExtracted$getQ(i, d, j); -+ -+ return aquiferExtracted$postCalculateDensityModified(pos, q); -+ } -+ } else { -+ return 2.0; -+ } -+ } -+ -+ private double aquiferExtracted$postCalculateDensity(DensityFunction.FunctionContext pos, MutableDouble mutableDouble, double q) { -+ double r; -+ if (!(q < -2.0) && !(q > 2.0)) { -+ double s = mutableDouble.getValue(); -+ if (Double.isNaN(s)) { -+ double t = this.barrierNoise.compute(pos); -+ mutableDouble.setValue(t); -+ r = t; -+ } else { -+ r = s; -+ } -+ } else { -+ r = 0.0; -+ } -+ -+ return 2.0 * (r + q); -+ } -+ -+ private double aquiferExtracted$postCalculateDensityModified(DensityFunction.FunctionContext pos, double q) { -+ double r; -+ if (!(q < -2.0) && !(q > 2.0)) { -+ double s = this.c2me$mutableDoubleThingy; -+ if (Double.isNaN(s)) { -+ double t = this.barrierNoise.compute(pos); -+ this.c2me$mutableDoubleThingy = t; -+ r = t; -+ } else { -+ r = s; -+ } -+ } else { -+ r = 0.0; -+ } -+ -+ return 2.0 * (r + q); -+ } -+ -+ private static double aquiferExtracted$getQ(double i, double d, double j) { -+ double e = i + 0.5 - d; -+ double f = j / 2.0; -+ double o = f - Math.abs(e); -+ double q; -+ if (e > 0.0) { -+ if (o > 0.0) { -+ q = o / 1.5; -+ } else { -+ q = o / 2.5; -+ } -+ } else { -+ double p = 3.0 + o; -+ if (p > 0.0) { -+ q = p / 3.0; -+ } else { -+ q = p / 10.0; -+ } -+ } -+ return q; -+ } -+ // DivineMC end - Chunk System Optimizations - } - } -diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java -index 74d8202b5c9bb2a3ee832be70f95c0b5cbecb460..4c11b822fa65388c1d8d9aaa7fd70200d0eaa418 100644 ---- a/net/minecraft/world/level/levelgen/Beardifier.java -+++ b/net/minecraft/world/level/levelgen/Beardifier.java -@@ -29,6 +29,17 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { - }); - private final ObjectListIterator pieceIterator; - private final ObjectListIterator junctionIterator; -+ // DivineMC start - Chunk System Optimizations -+ private Beardifier.Rigid[] c2me$pieceArray; -+ private JigsawJunction[] c2me$junctionArray; -+ -+ private void c2me$initArrays() { -+ this.c2me$pieceArray = com.google.common.collect.Iterators.toArray(this.pieceIterator, Beardifier.Rigid.class); -+ this.pieceIterator.back(Integer.MAX_VALUE); -+ this.c2me$junctionArray = com.google.common.collect.Iterators.toArray(this.junctionIterator, JigsawJunction.class); -+ this.junctionIterator.back(Integer.MAX_VALUE); -+ } -+ // DivineMC end - Chunk System Optimizations - - public static Beardifier forStructuresInChunk(StructureManager structureManager, ChunkPos chunkPos) { - int minBlockX = chunkPos.getMinBlockX(); -@@ -75,50 +86,44 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { - this.junctionIterator = junctionIterator; - } - -+ // DivineMC start - Chunk System Optimizations - @Override - public double compute(DensityFunction.FunctionContext context) { -+ if (this.c2me$pieceArray == null || this.c2me$junctionArray == null) { -+ this.c2me$initArrays(); -+ } - int i = context.blockX(); -- int i1 = context.blockY(); -- int i2 = context.blockZ(); -+ int j = context.blockY(); -+ int k = context.blockZ(); - double d = 0.0; - -- while (this.pieceIterator.hasNext()) { -- Beardifier.Rigid rigid = this.pieceIterator.next(); -- BoundingBox boundingBox = rigid.box(); -- int groundLevelDelta = rigid.groundLevelDelta(); -- int max = Math.max(0, Math.max(boundingBox.minX() - i, i - boundingBox.maxX())); -- int max1 = Math.max(0, Math.max(boundingBox.minZ() - i2, i2 - boundingBox.maxZ())); -- int i3 = boundingBox.minY() + groundLevelDelta; -- int i4 = i1 - i3; -- -- int i5 = switch (rigid.terrainAdjustment()) { -- case NONE -> 0; -- case BURY, BEARD_THIN -> i4; -- case BEARD_BOX -> Math.max(0, Math.max(i3 - i1, i1 - boundingBox.maxY())); -- case ENCAPSULATE -> Math.max(0, Math.max(boundingBox.minY() - i1, i1 - boundingBox.maxY())); -- }; -+ for (Beardifier.Rigid piece : this.c2me$pieceArray) { -+ BoundingBox blockBox = piece.box(); -+ int l = piece.groundLevelDelta(); -+ int m = Math.max(0, Math.max(blockBox.minX() - i, i - blockBox.maxX())); -+ int n = Math.max(0, Math.max(blockBox.minZ() - k, k - blockBox.maxZ())); -+ int o = blockBox.minY() + l; -+ int p = j - o; - -- d += switch (rigid.terrainAdjustment()) { -+ d += switch (piece.terrainAdjustment()) { // 2 switch statement merged - case NONE -> 0.0; -- case BURY -> getBuryContribution(max, i5 / 2.0, max1); -- case BEARD_THIN, BEARD_BOX -> getBeardContribution(max, i5, max1, i4) * 0.8; -- case ENCAPSULATE -> getBuryContribution(max / 2.0, i5 / 2.0, max1 / 2.0) * 0.8; -+ case BURY -> getBuryContribution(m, (double)p / 2.0, n); -+ case BEARD_THIN -> getBeardContribution(m, p, n, p) * 0.8; -+ case BEARD_BOX -> getBeardContribution(m, Math.max(0, Math.max(o - j, j - blockBox.maxY())), n, p) * 0.8; -+ case ENCAPSULATE -> getBuryContribution((double)m / 2.0, (double)Math.max(0, Math.max(blockBox.minY() - j, j - blockBox.maxY())) / 2.0, (double)n / 2.0) * 0.8; - }; - } - -- this.pieceIterator.back(Integer.MAX_VALUE); -- -- while (this.junctionIterator.hasNext()) { -- JigsawJunction jigsawJunction = this.junctionIterator.next(); -- int i6 = i - jigsawJunction.getSourceX(); -- int groundLevelDelta = i1 - jigsawJunction.getSourceGroundY(); -- int max = i2 - jigsawJunction.getSourceZ(); -- d += getBeardContribution(i6, groundLevelDelta, max, groundLevelDelta) * 0.4; -+ for (JigsawJunction jigsawJunction : this.c2me$junctionArray) { -+ int r = i - jigsawJunction.getSourceX(); -+ int l = j - jigsawJunction.getSourceGroundY(); -+ int m = k - jigsawJunction.getSourceZ(); -+ d += getBeardContribution(r, l, m, l) * 0.4; - } - -- this.junctionIterator.back(Integer.MAX_VALUE); - return d; - } -+ // DivineMC end - Chunk System Optimizations - - @Override - public double minValue() { -@@ -131,8 +136,14 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { - } - - private static double getBuryContribution(double x, double y, double z) { -- double len = Mth.length(x, y, z); -- return Mth.clampedMap(len, 0.0, 6.0, 1.0, 0.0); -+ // DivineMC start - Chunk System Optimizations -+ double d = Math.sqrt(x * x + y * y + z * z); -+ if (d > 6.0) { -+ return 0.0; -+ } else { -+ return 1.0 - d / 6.0; -+ } -+ // DivineMC end - Chunk System Optimizations - } - - private static double getBeardContribution(int x, int y, int z, int height) { -diff --git a/net/minecraft/world/level/levelgen/BelowZeroRetrogen.java b/net/minecraft/world/level/levelgen/BelowZeroRetrogen.java -index 3379c3893227d42bb54f3a94e697a9851d279605..06b1ea5fd3b9b1c6bace8be859aabff7590481ce 100644 ---- a/net/minecraft/world/level/levelgen/BelowZeroRetrogen.java -+++ b/net/minecraft/world/level/levelgen/BelowZeroRetrogen.java -@@ -74,6 +74,7 @@ public final class BelowZeroRetrogen { - } - - public void applyBedrockMask(ProtoChunk chunk) { -+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.smoothBedrockLayer) return; // DivineMC - Smooth bedrock layer - LevelHeightAccessor heightAccessorForGeneration = chunk.getHeightAccessorForGeneration(); - int minY = heightAccessorForGeneration.getMinY(); - int maxY = heightAccessorForGeneration.getMaxY(); -diff --git a/net/minecraft/world/level/levelgen/Column.java b/net/minecraft/world/level/levelgen/Column.java -index 4a1df0f8578c9ee5538ed8c94d3c7911f36f83b8..716c2c69843234cdef34339d859babc95ffe318c 100644 ---- a/net/minecraft/world/level/levelgen/Column.java -+++ b/net/minecraft/world/level/levelgen/Column.java -@@ -156,7 +156,7 @@ public abstract class Column { - } - - public int height() { -- return this.ceiling - this.floor - 1; -+ return net.minecraft.util.Mth.abs(this.ceiling - this.floor - 1); // DivineMC - Chunk System optimization - } - - @Override -diff --git a/net/minecraft/world/level/levelgen/LegacyRandomSource.java b/net/minecraft/world/level/levelgen/LegacyRandomSource.java -index c67168517774a0ad9ca43422a79ef14a8ea0c2e8..026dfbbb6c3fd5cd274dcbf721e5cf3af889e3d9 100644 ---- a/net/minecraft/world/level/levelgen/LegacyRandomSource.java -+++ b/net/minecraft/world/level/levelgen/LegacyRandomSource.java -@@ -53,13 +53,7 @@ public class LegacyRandomSource implements BitRandomSource { - return this.gaussianSource.nextGaussian(); - } - -- public static class LegacyPositionalRandomFactory implements PositionalRandomFactory { -- private final long seed; -- -- public LegacyPositionalRandomFactory(long seed) { -- this.seed = seed; -- } -- -+ public record LegacyPositionalRandomFactory(long seed) implements PositionalRandomFactory { // DivineMC - make record - @Override - public RandomSource at(int x, int y, int z) { - long seed = Mth.getSeed(x, y, z); -diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -index 65728ef17e63d71833677fdcbd5bb90794b4822b..eb61a3c995afe5af1cd385826e882acf441e2785 100644 ---- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -+++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -@@ -65,11 +65,13 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { - } - - private static Aquifer.FluidPicker createFluidPicker(NoiseGeneratorSettings settings) { -- Aquifer.FluidStatus fluidStatus = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState()); -- int seaLevel = settings.seaLevel(); -- Aquifer.FluidStatus fluidStatus1 = new Aquifer.FluidStatus(seaLevel, settings.defaultFluid()); -- Aquifer.FluidStatus fluidStatus2 = new Aquifer.FluidStatus(DimensionType.MIN_Y * 2, Blocks.AIR.defaultBlockState()); -- return (x, y, z) -> y < Math.min(-54, seaLevel) ? fluidStatus : fluidStatus1; -+ // DivineMC start - Chunk System Optimizations -+ Aquifer.FluidStatus fluidLevel = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState()); -+ int i = settings.seaLevel(); -+ Aquifer.FluidStatus fluidLevel2 = new Aquifer.FluidStatus(i, settings.defaultFluid()); -+ final int min = Math.min(-54, i); -+ return (j, k, lx) -> k < min ? fluidLevel : fluidLevel2; -+ // DivineMC end - Chunk System Optimizations - } - - @Override -@@ -294,30 +296,32 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { - public CompletableFuture fillFromNoise(Blender blender, RandomState randomState, StructureManager structureManager, ChunkAccess chunk) { - NoiseSettings noiseSettings = this.settings.value().noiseSettings().clampToHeightAccessor(chunk.getHeightAccessorForGeneration()); - int minY = noiseSettings.minY(); -- int i = Mth.floorDiv(minY, noiseSettings.getCellHeight()); -- int i1 = Mth.floorDiv(noiseSettings.height(), noiseSettings.getCellHeight()); -- return i1 <= 0 ? CompletableFuture.completedFuture(chunk) : CompletableFuture.supplyAsync(() -> { -- int sectionIndex = chunk.getSectionIndex(i1 * noiseSettings.getCellHeight() - 1 + minY); -- int sectionIndex1 = chunk.getSectionIndex(minY); -- Set set = Sets.newHashSet(); -- -- for (int i2 = sectionIndex; i2 >= sectionIndex1; i2--) { -- LevelChunkSection section = chunk.getSection(i2); -- section.acquire(); -- set.add(section); -- } -+ // DivineMC start - Optimize noise fill -+ int minYDiv = Mth.floorDiv(minY, noiseSettings.getCellHeight()); -+ int cellHeightDiv = Mth.floorDiv(noiseSettings.height(), noiseSettings.getCellHeight()); - -- ChunkAccess var20; -- try { -- var20 = this.doFill(blender, structureManager, randomState, chunk, i, i1); -- } finally { -- for (LevelChunkSection levelChunkSection1 : set) { -- levelChunkSection1.release(); -- } -+ if (cellHeightDiv <= 0) { -+ return CompletableFuture.completedFuture(chunk); -+ } -+ -+ try { -+ int startIndex = chunk.getSectionIndex(cellHeightDiv * noiseSettings.getCellHeight() - 1 + minY); -+ int minYIndex = chunk.getSectionIndex(minY); -+ LevelChunkSection[] sections = chunk.getSections(); -+ -+ for (int i = startIndex; i >= minYIndex; --i) { -+ sections[i].acquire(); - } - -- return var20; -- }, Runnable::run); // Paper - rewrite chunk system -+ ChunkAccess access = this.doFill(blender, structureManager, randomState, chunk, minYDiv, cellHeightDiv); -+ for (int i = startIndex; i >= minYIndex; --i) { -+ sections[i].release(); -+ } -+ return CompletableFuture.completedFuture(access); -+ } catch (Throwable throwable) { -+ throw new RuntimeException("Unexpected error when running noise fill", throwable); -+ } -+ // DivineMC end - Optimize noise fill - } - - private ChunkAccess doFill(Blender blender, StructureManager structureManager, RandomState random, ChunkAccess chunk, int minCellY, int cellCountY) { -@@ -375,7 +379,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { - - interpolatedState = this.debugPreliminarySurfaceLevel(noiseChunk, i10, i7, i13, interpolatedState); - if (interpolatedState != AIR && !SharedConstants.debugVoidTerrain(chunk.getPos())) { -- section.setBlockState(i11, i8, i14, interpolatedState, false); -+ optimizedBlockSetOp(section, i11, i8, i14, interpolatedState, false); // DivineMC - Optimize noise fill - heightmapUnprimed.update(i11, i7, i14, interpolatedState); - heightmapUnprimed1.update(i11, i7, i14, interpolatedState); - if (aquifer.shouldScheduleFluidUpdate() && !interpolatedState.getFluidState().isEmpty()) { -@@ -396,6 +400,26 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { - return chunk; - } - -+ // DivineMC start - Optimize noise fill -+ private void optimizedBlockSetOp(@org.jetbrains.annotations.NotNull LevelChunkSection chunkSection, int chunkSectionBlockPosX, int chunkSectionBlockPosY, int chunkSectionBlockPosZ, @org.jetbrains.annotations.NotNull BlockState blockState, boolean lock) { -+ chunkSection.nonEmptyBlockCount += 1; -+ -+ if (!blockState.getFluidState().isEmpty()) { -+ chunkSection.tickingFluidCount += 1; -+ } -+ -+ if (blockState.isRandomlyTicking()) { -+ chunkSection.tickingBlockCount += 1; -+ } -+ -+ var blockStateId = chunkSection.states.data.palette.idFor(blockState); -+ chunkSection.states.data.storage().set( -+ chunkSection.states.strategy.getIndex(chunkSectionBlockPosX, chunkSectionBlockPosY, -+ chunkSectionBlockPosZ -+ ), blockStateId); -+ } -+ // DivineMC end - Optimize noise fill -+ - private BlockState debugPreliminarySurfaceLevel(NoiseChunk chunk, int x, int y, int z, BlockState state) { - return state; - } -diff --git a/net/minecraft/world/level/levelgen/NoiseSettings.java b/net/minecraft/world/level/levelgen/NoiseSettings.java -index 4cf3a364595ba5f81f741295695cb9a449bdf672..44df2ac0bd972c4d97fc89cd0c2d2d83480ca3e1 100644 ---- a/net/minecraft/world/level/levelgen/NoiseSettings.java -+++ b/net/minecraft/world/level/levelgen/NoiseSettings.java -@@ -8,7 +8,7 @@ import net.minecraft.core.QuartPos; - import net.minecraft.world.level.LevelHeightAccessor; - import net.minecraft.world.level.dimension.DimensionType; - --public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical) { -+public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical, int horizontalCellBlockCount, int verticalCellBlockCount) { // DivineMC - NoiseSettings optimizations - public static final Codec CODEC = RecordCodecBuilder.create( - instance -> instance.group( - Codec.intRange(DimensionType.MIN_Y, DimensionType.MAX_Y).fieldOf("min_y").forGetter(NoiseSettings::minY), -@@ -16,7 +16,10 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n - Codec.intRange(1, 4).fieldOf("size_horizontal").forGetter(NoiseSettings::noiseSizeHorizontal), - Codec.intRange(1, 4).fieldOf("size_vertical").forGetter(NoiseSettings::noiseSizeVertical) - ) -- .apply(instance, NoiseSettings::new) -+ // DivineMC start - NoiseSettings optimizations -+ .apply(instance, (Integer minY1, Integer height1, Integer noiseSizeHorizontal1, Integer noiseSizeVertical1) -> new NoiseSettings(minY1, height1, noiseSizeHorizontal1, noiseSizeVertical1, -+ QuartPos.toBlock(noiseSizeHorizontal1), QuartPos.toBlock(noiseSizeVertical1))) -+ // DivineMC end - NoiseSettings optimizations - ) - .comapFlatMap(NoiseSettings::guardY, Function.identity()); - protected static final NoiseSettings OVERWORLD_NOISE_SETTINGS = create(-64, 384, 1, 2); -@@ -36,7 +39,7 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n - } - - public static NoiseSettings create(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical) { -- NoiseSettings noiseSettings = new NoiseSettings(minY, height, noiseSizeHorizontal, noiseSizeVertical); -+ NoiseSettings noiseSettings = new NoiseSettings(minY, height, noiseSizeHorizontal, noiseSizeVertical, QuartPos.toBlock(noiseSizeHorizontal), QuartPos.toBlock(noiseSizeVertical)); // DivineMC - NoiseSettings optimizations - guardY(noiseSettings).error().ifPresent(error -> { - throw new IllegalStateException(error.message()); - }); -@@ -44,16 +47,16 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n - } - - public int getCellHeight() { -- return QuartPos.toBlock(this.noiseSizeVertical()); -+ return verticalCellBlockCount(); // DivineMC - NoiseSettings optimizations - } - - public int getCellWidth() { -- return QuartPos.toBlock(this.noiseSizeHorizontal()); -+ return horizontalCellBlockCount(); // DivineMC - NoiseSettings optimizations - } - - public NoiseSettings clampToHeightAccessor(LevelHeightAccessor heightAccessor) { - int max = Math.max(this.minY, heightAccessor.getMinY()); - int i = Math.min(this.minY + this.height, heightAccessor.getMaxY() + 1) - max; -- return new NoiseSettings(max, i, this.noiseSizeHorizontal, this.noiseSizeVertical); -+ return new NoiseSettings(max, i, this.noiseSizeHorizontal, this.noiseSizeVertical, QuartPos.toBlock(this.noiseSizeHorizontal), QuartPos.toBlock(this.noiseSizeVertical)); // DivineMC - NoiseSettings optimizations - } - } -diff --git a/net/minecraft/world/level/levelgen/SurfaceRules.java b/net/minecraft/world/level/levelgen/SurfaceRules.java -index 32757c6847cf77862a2f1b38cc53e7166e6be492..92c7aa344d00067f52829f8d97a6ee219e6c2771 100644 ---- a/net/minecraft/world/level/levelgen/SurfaceRules.java -+++ b/net/minecraft/world/level/levelgen/SurfaceRules.java -@@ -185,7 +185,7 @@ public class SurfaceRules { - - @Override - protected boolean compute() { -- return this.context.biome.get().is(BiomeConditionSource.this.biomeNameTest); -+ return this.context.biome.is(BiomeConditionSource.this.biomeNameTest); // DivineMC - Chunk System Optimizations - } - } - -@@ -281,7 +281,7 @@ public class SurfaceRules { - private int minSurfaceLevel; - long lastUpdateY = -9223372036854775807L; - final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); -- Supplier> biome; -+ Holder biome; // DivineMC - Chunk System Optimizations - public int blockY; - int waterHeight; - int stoneDepthBelow; -@@ -314,7 +314,10 @@ public class SurfaceRules { - - protected void updateY(int stoneDepthAbove, int stoneDepthBelow, int waterHeight, int blockX, int blockY, int blockZ) { - this.lastUpdateY++; -- this.biome = Suppliers.memoize(() -> this.biomeGetter.apply(this.pos.set(blockX, blockY, blockZ))); -+ // DivineMC start - Chunk System Optimizations -+ this.pos.set(blockX, blockY, blockZ); -+ this.biome = this.biomeGetter.apply(this.pos); -+ // DivineMC end - Chunk System Optimizations - this.blockY = blockY; - this.waterHeight = waterHeight; - this.stoneDepthBelow = stoneDepthBelow; -@@ -441,7 +444,6 @@ public class SurfaceRules { - protected boolean compute() { - return this.context - .biome -- .get() - .value() - .coldEnoughToSnow(this.context.pos.set(this.context.blockX, this.context.blockY, this.context.blockZ), this.context.getSeaLevel()); - } -diff --git a/net/minecraft/world/level/levelgen/WorldgenRandom.java b/net/minecraft/world/level/levelgen/WorldgenRandom.java -index c2d7cd788071e25b8ba2503c30ae80c7a9f353ed..0a2e13c4a3db6517267e1f9e74b6152c73e8351f 100644 ---- a/net/minecraft/world/level/levelgen/WorldgenRandom.java -+++ b/net/minecraft/world/level/levelgen/WorldgenRandom.java -@@ -73,7 +73,7 @@ public class WorldgenRandom extends LegacyRandomSource { - } - - public static enum Algorithm { -- LEGACY(LegacyRandomSource::new), -+ LEGACY(ThreadSafeLegacyRandomSource::new), // DivineMC - Chunk System optimization - XOROSHIRO(XoroshiroRandomSource::new); - - private final LongFunction constructor; -diff --git a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java -index 9d3a9ca1e13cd80f468f1352bbb74345f03903dd..d97b9b43686bda0a95fc02f6ca31b2d07d603a32 100644 ---- a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java -+++ b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java -@@ -106,15 +106,7 @@ public class XoroshiroRandomSource implements RandomSource { - return this.randomNumberGenerator.nextLong() >>> 64 - bits; - } - -- public static class XoroshiroPositionalRandomFactory implements PositionalRandomFactory { -- private final long seedLo; -- private final long seedHi; -- -- public XoroshiroPositionalRandomFactory(long seedLo, long seedHi) { -- this.seedLo = seedLo; -- this.seedHi = seedHi; -- } -- -+ public record XoroshiroPositionalRandomFactory(long seedLo, long seedHi) implements PositionalRandomFactory { // DivineMC - make record - @Override - public RandomSource at(int x, int y, int z) { - long seed = Mth.getSeed(x, y, z); -diff --git a/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java b/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java -index 21cbf6c1723feb1813d8cd5106e36594d140d987..29fad81878fe6902328b810e1584650cfb65aba6 100644 ---- a/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java -+++ b/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java -@@ -55,17 +55,21 @@ public class RandomizedIntStateProvider extends BlockStateProvider { - - @Override - public BlockState getState(RandomSource random, BlockPos pos) { -- BlockState state = this.source.getState(random, pos); -- if (this.property == null || !state.hasProperty(this.property)) { -- IntegerProperty integerProperty = findProperty(state, this.propertyName); -- if (integerProperty == null) { -- return state; -+ // DivineMC start - Chunk System optimization -+ BlockState blockState = this.source.getState(random, pos); -+ IntegerProperty propertyLocal = this.property; -+ if (propertyLocal == null || !blockState.hasProperty(propertyLocal)) { -+ IntegerProperty intProperty = findProperty(blockState, this.propertyName); -+ if (intProperty == null) { -+ return blockState; - } - -- this.property = integerProperty; -+ propertyLocal = intProperty; -+ this.property = intProperty; - } - -- return state.setValue(this.property, this.values.sample(random)); -+ return (BlockState) blockState.setValue(this.property, this.values.sample(random)); -+ // DivineMC end - Chunk System optimization - } - - @Nullable -diff --git a/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java b/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java -index e2036a80eff3dc1a9ec625880d4aab6ef71d84fa..6c5200a311a6c5a93a49999cc0c3a8b3f3ca8240 100644 ---- a/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java -+++ b/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java -@@ -12,7 +12,7 @@ public abstract class ScatteredFeaturePiece extends StructurePiece { - protected final int width; - protected final int height; - protected final int depth; -- protected int heightPosition = -1; -+ protected volatile int heightPosition = -1; // DivineMC - Chunk System optimization - make volatile - - protected ScatteredFeaturePiece(StructurePieceType type, int x, int y, int z, int width, int height, int depth, Direction orientation) { - super(type, 0, StructurePiece.makeBoundingBox(x, y, z, orientation, width, height, depth)); -diff --git a/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/net/minecraft/world/level/levelgen/structure/StructureCheck.java -index 7779a2f83f51465bde476776470bd77712f6be0d..c79c758ced104d2711b73b41370c43c4dc56b03e 100644 ---- a/net/minecraft/world/level/levelgen/structure/StructureCheck.java -+++ b/net/minecraft/world/level/levelgen/structure/StructureCheck.java -@@ -47,6 +47,7 @@ public class StructureCheck { - private final LevelHeightAccessor heightAccessor; - private final BiomeSource biomeSource; - private final long seed; -+ private Object mapMutex = new Object(); // DivineMC - Chunk System Optimizations - private final DataFixer fixerUpper; - // Paper start - rewrite chunk system - // make sure to purge entries from the maps to prevent memory leaks -@@ -229,15 +230,13 @@ public class StructureCheck { - } - - private void storeFullResults(long chunkPos, Object2IntMap structureChunks) { -- // Paper start - rewrite chunk system -+ // DivineMC start - Chunk System Optimizations - this.loadedChunksSafe.put(chunkPos, deduplicateEmptyMap(structureChunks)); -- // once we insert into loadedChunks, we don't really need to be very careful about removing everything -- // from this map, as everything that checks this map uses loadedChunks first -- // so, one way or another it's a race condition that doesn't matter -- for (ca.spottedleaf.moonrise.common.map.SynchronisedLong2BooleanMap value : this.featureChecksSafe.values()) { -- value.remove(chunkPos); -+ -+ synchronized (this.mapMutex) { -+ this.featureChecksSafe.values().forEach((long2BooleanMap) -> long2BooleanMap.remove(chunkPos)); - } -- // Paper end - rewrite chunk system -+ // DivineMC end - Chunk System Optimizations - } - - public void incrementReference(ChunkPos pos, Structure structure) { -diff --git a/net/minecraft/world/level/levelgen/structure/StructureStart.java b/net/minecraft/world/level/levelgen/structure/StructureStart.java -index f9a15c3769f29af1952ef880f6fcd2612119ecf0..13f6654e06f87e9a9fbeba2217ee0e0eaa95347d 100644 ---- a/net/minecraft/world/level/levelgen/structure/StructureStart.java -+++ b/net/minecraft/world/level/levelgen/structure/StructureStart.java -@@ -26,7 +26,7 @@ public final class StructureStart { - private final Structure structure; - private final PiecesContainer pieceContainer; - private final ChunkPos chunkPos; -- private int references; -+ private final java.util.concurrent.atomic.AtomicInteger references = new java.util.concurrent.atomic.AtomicInteger(); // DivineMC - Chunk System optimization - @Nullable - private volatile BoundingBox cachedBoundingBox; - -@@ -39,7 +39,7 @@ public final class StructureStart { - public StructureStart(Structure structure, ChunkPos chunkPos, int references, PiecesContainer pieceContainer) { - this.structure = structure; - this.chunkPos = chunkPos; -- this.references = references; -+ this.references.set(references); // DivineMC - Chunk System optimization - this.pieceContainer = pieceContainer; - } - -@@ -126,7 +126,7 @@ public final class StructureStart { - compoundTag.putString("id", context.registryAccess().lookupOrThrow(Registries.STRUCTURE).getKey(this.structure).toString()); - compoundTag.putInt("ChunkX", chunkPos.x); - compoundTag.putInt("ChunkZ", chunkPos.z); -- compoundTag.putInt("references", this.references); -+ compoundTag.putInt("references", this.references.get()); // DivineMC - Chunk System optimization - compoundTag.put("Children", this.pieceContainer.save(context)); - return compoundTag; - } else { -@@ -144,15 +144,15 @@ public final class StructureStart { - } - - public boolean canBeReferenced() { -- return this.references < this.getMaxReferences(); -+ return this.references.get() < this.getMaxReferences(); // DivineMC - Chunk System optimization - } - - public void addReference() { -- this.references++; -+ this.references.getAndIncrement(); // DivineMC - Chunk System optimization - } - - public int getReferences() { -- return this.references; -+ return this.references.get(); // DivineMC - Chunk System optimization - } - - protected int getMaxReferences() { -diff --git a/net/minecraft/world/level/levelgen/structure/pools/StructurePoolElement.java b/net/minecraft/world/level/levelgen/structure/pools/StructurePoolElement.java -index c84d865837e0f009fcde19e14a44fa43aefe660a..64d7adbd4aa398044a1d68d51e463b672ee81edf 100644 ---- a/net/minecraft/world/level/levelgen/structure/pools/StructurePoolElement.java -+++ b/net/minecraft/world/level/levelgen/structure/pools/StructurePoolElement.java -@@ -27,9 +27,9 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp - import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; - - public abstract class StructurePoolElement { -- public static final Codec CODEC = BuiltInRegistries.STRUCTURE_POOL_ELEMENT -+ public static final Codec CODEC = new org.bxteam.divinemc.util.SynchronizedCodec<>(BuiltInRegistries.STRUCTURE_POOL_ELEMENT // DivineMC - Chunk System Optimizations - .byNameCodec() -- .dispatch("element_type", StructurePoolElement::getType, StructurePoolElementType::codec); -+ .dispatch("element_type", StructurePoolElement::getType, StructurePoolElementType::codec)); // DivineMC - Chunk System Optimizations - private static final Holder EMPTY = Holder.direct(new StructureProcessorList(List.of())); - @Nullable - private volatile StructureTemplatePool.Projection projection; -diff --git a/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidPiece.java b/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidPiece.java -index 0d2451a9ade43650dbbcbab69ce0f6e8f69b5aee..21b8e738c8823eac5d8fc8241dd8fb0e5ce82364 100644 ---- a/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidPiece.java -+++ b/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidPiece.java -@@ -23,29 +23,45 @@ import net.minecraft.world.level.storage.loot.BuiltInLootTables; - public class DesertPyramidPiece extends ScatteredFeaturePiece { - public static final int WIDTH = 21; - public static final int DEPTH = 21; -- private final boolean[] hasPlacedChest = new boolean[4]; -- private final List potentialSuspiciousSandWorldPositions = new ArrayList<>(); -+ private final java.util.concurrent.atomic.AtomicReferenceArray hasPlacedChestAtomic = new java.util.concurrent.atomic.AtomicReferenceArray<>(new Boolean[4]); // DivineMC - Chunk System Optimizations -+ private final java.util.Set potentialSuspiciousSandWorldPositions = com.google.common.collect.Sets.newConcurrentHashSet(); // DivineMC - Chunk System Optimizations - private BlockPos randomCollapsedRoofPos = BlockPos.ZERO; - -+ // DivineMC start - Chunk System Optimizations -+ private void init() { -+ for (int i = 0; i < this.hasPlacedChestAtomic.length(); ++i) { -+ if (this.hasPlacedChestAtomic.get(i) == null) { -+ this.hasPlacedChestAtomic.set(i, false); -+ } -+ } -+ } -+ // DivineMC end - Chunk System Optimizations -+ - public DesertPyramidPiece(RandomSource random, int x, int z) { - super(StructurePieceType.DESERT_PYRAMID_PIECE, x, 64, z, 21, 15, 21, getRandomHorizontalDirection(random)); -+ init(); // DivineMC - Chunk System Optimizations - } - - public DesertPyramidPiece(CompoundTag tag) { - super(StructurePieceType.DESERT_PYRAMID_PIECE, tag); -- this.hasPlacedChest[0] = tag.getBooleanOr("hasPlacedChest0", false); -- this.hasPlacedChest[1] = tag.getBooleanOr("hasPlacedChest1", false); -- this.hasPlacedChest[2] = tag.getBooleanOr("hasPlacedChest2", false); -- this.hasPlacedChest[3] = tag.getBooleanOr("hasPlacedChest3", false); -+ // DivineMC start - Chunk System Optimizations -+ this.hasPlacedChestAtomic.set(0, tag.getBooleanOr("hasPlacedChest0", false)); -+ this.hasPlacedChestAtomic.set(1, tag.getBooleanOr("hasPlacedChest1", false)); -+ this.hasPlacedChestAtomic.set(2, tag.getBooleanOr("hasPlacedChest2", false)); -+ this.hasPlacedChestAtomic.set(3, tag.getBooleanOr("hasPlacedChest3", false)); -+ init(); -+ // DivineMC end - Chunk System Optimizations - } - - @Override - protected void addAdditionalSaveData(StructurePieceSerializationContext context, CompoundTag tag) { - super.addAdditionalSaveData(context, tag); -- tag.putBoolean("hasPlacedChest0", this.hasPlacedChest[0]); -- tag.putBoolean("hasPlacedChest1", this.hasPlacedChest[1]); -- tag.putBoolean("hasPlacedChest2", this.hasPlacedChest[2]); -- tag.putBoolean("hasPlacedChest3", this.hasPlacedChest[3]); -+ // DivineMC start - Chunk System Optimizations -+ tag.putBoolean("hasPlacedChest0", this.hasPlacedChestAtomic.get(0)); -+ tag.putBoolean("hasPlacedChest1", this.hasPlacedChestAtomic.get(1)); -+ tag.putBoolean("hasPlacedChest2", this.hasPlacedChestAtomic.get(2)); -+ tag.putBoolean("hasPlacedChest3", this.hasPlacedChestAtomic.get(3)); -+ // DivineMC end - Chunk System Optimizations - } - - @Override -@@ -287,12 +303,12 @@ public class DesertPyramidPiece extends ScatteredFeaturePiece { - this.placeBlock(level, Blocks.CUT_SANDSTONE.defaultBlockState(), 10, -11, 13, box); - - for (Direction direction : Direction.Plane.HORIZONTAL) { -- if (!this.hasPlacedChest[direction.get2DDataValue()]) { -+ if (!this.hasPlacedChestAtomic.get(direction.get2DDataValue())) { // DivineMC - Chunk System Optimizations - int i4 = direction.getStepX() * 2; - int i5 = direction.getStepZ() * 2; -- this.hasPlacedChest[direction.get2DDataValue()] = this.createChest( -+ this.hasPlacedChestAtomic.set(direction.get2DDataValue(), this.createChest( // DivineMC - Chunk System Optimizations - level, box, random, 10 + i4, -11, 10 + i5, BuiltInLootTables.DESERT_PYRAMID -- ); -+ )); // DivineMC - Chunk System Optimizations - } - } - -@@ -419,7 +435,7 @@ public class DesertPyramidPiece extends ScatteredFeaturePiece { - this.randomCollapsedRoofPos = new BlockPos(this.getWorldX(i1, randomInt), this.getWorldY(y), this.getWorldZ(i1, randomInt)); - } - -- public List getPotentialSuspiciousSandWorldPositions() { -+ public java.util.Set getPotentialSuspiciousSandWorldPositions() { // DivineMC - Chunk System Optimizations - return this.potentialSuspiciousSandWorldPositions; - } - -diff --git a/net/minecraft/world/level/levelgen/structure/structures/JungleTemplePiece.java b/net/minecraft/world/level/levelgen/structure/structures/JungleTemplePiece.java -index d28f1a25e2137955402e41679d1a4220a0136579..d751eac6d7a97b8de44c83c35ff7d3e36ca3b066 100644 ---- a/net/minecraft/world/level/levelgen/structure/structures/JungleTemplePiece.java -+++ b/net/minecraft/world/level/levelgen/structure/structures/JungleTemplePiece.java -@@ -30,10 +30,12 @@ import net.minecraft.world.level.storage.loot.BuiltInLootTables; - public class JungleTemplePiece extends ScatteredFeaturePiece { - public static final int WIDTH = 12; - public static final int DEPTH = 15; -- private boolean placedMainChest; -- private boolean placedHiddenChest; -- private boolean placedTrap1; -- private boolean placedTrap2; -+ // DivineMC start - Chunk System Optimizations -+ private final java.util.concurrent.atomic.AtomicBoolean placedMainChest = new java.util.concurrent.atomic.AtomicBoolean(false); -+ private final java.util.concurrent.atomic.AtomicBoolean placedHiddenChest = new java.util.concurrent.atomic.AtomicBoolean(false); -+ private final java.util.concurrent.atomic.AtomicBoolean placedTrap1 = new java.util.concurrent.atomic.AtomicBoolean(false); -+ private final java.util.concurrent.atomic.AtomicBoolean placedTrap2 = new java.util.concurrent.atomic.AtomicBoolean(false); -+ // DivineMC end - Chunk System Optimizations - private static final JungleTemplePiece.MossStoneSelector STONE_SELECTOR = new JungleTemplePiece.MossStoneSelector(); - - public JungleTemplePiece(RandomSource random, int x, int z) { -@@ -42,19 +44,23 @@ public class JungleTemplePiece extends ScatteredFeaturePiece { - - public JungleTemplePiece(CompoundTag tag) { - super(StructurePieceType.JUNGLE_PYRAMID_PIECE, tag); -- this.placedMainChest = tag.getBooleanOr("placedMainChest", false); -- this.placedHiddenChest = tag.getBooleanOr("placedHiddenChest", false); -- this.placedTrap1 = tag.getBooleanOr("placedTrap1", false); -- this.placedTrap2 = tag.getBooleanOr("placedTrap2", false); -+ // DivineMC start - Chunk System Optimizations -+ this.placedMainChest.set(tag.getBooleanOr("placedMainChest", false)); -+ this.placedHiddenChest.set(tag.getBooleanOr("placedHiddenChest", false)); -+ this.placedTrap1.set(tag.getBooleanOr("placedTrap1", false)); -+ this.placedTrap2.set(tag.getBooleanOr("placedTrap2", false)); -+ // DivineMC end - Chunk System Optimizations - } - - @Override - protected void addAdditionalSaveData(StructurePieceSerializationContext context, CompoundTag tag) { - super.addAdditionalSaveData(context, tag); -- tag.putBoolean("placedMainChest", this.placedMainChest); -- tag.putBoolean("placedHiddenChest", this.placedHiddenChest); -- tag.putBoolean("placedTrap1", this.placedTrap1); -- tag.putBoolean("placedTrap2", this.placedTrap2); -+ // DivineMC start - Chunk System Optimizations -+ tag.putBoolean("placedMainChest", this.placedMainChest.get()); -+ tag.putBoolean("placedHiddenChest", this.placedHiddenChest.get()); -+ tag.putBoolean("placedTrap1", this.placedTrap1.get()); -+ tag.putBoolean("placedTrap2", this.placedTrap2.get()); -+ // DivineMC end - Chunk System Optimizations - } - - @Override -@@ -236,8 +242,8 @@ public class JungleTemplePiece extends ScatteredFeaturePiece { - box - ); - this.placeBlock(level, Blocks.MOSSY_COBBLESTONE.defaultBlockState(), 3, -3, 1, box); -- if (!this.placedTrap1) { -- this.placedTrap1 = this.createDispenser(level, box, random, 3, -2, 1, Direction.NORTH, BuiltInLootTables.JUNGLE_TEMPLE_DISPENSER); -+ if (!this.placedTrap1.get()) { // DivineMC - Chunk System Optimizations -+ this.placedTrap1.set(this.createDispenser(level, box, random, 3, -2, 1, Direction.NORTH, BuiltInLootTables.JUNGLE_TEMPLE_DISPENSER)); // DivineMC - Chunk System Optimizations - } - - this.placeBlock(level, Blocks.VINE.defaultBlockState().setValue(VineBlock.SOUTH, true), 3, -2, 2, box); -@@ -328,14 +334,14 @@ public class JungleTemplePiece extends ScatteredFeaturePiece { - ); - this.placeBlock(level, Blocks.MOSSY_COBBLESTONE.defaultBlockState(), 9, -3, 4, box); - this.placeBlock(level, blockState4, 9, -2, 4, box); -- if (!this.placedTrap2) { -- this.placedTrap2 = this.createDispenser(level, box, random, 9, -2, 3, Direction.WEST, BuiltInLootTables.JUNGLE_TEMPLE_DISPENSER); -+ if (!this.placedTrap2.get()) { // DivineMC - Chunk System Optimizations -+ this.placedTrap2.set(this.createDispenser(level, box, random, 9, -2, 3, Direction.WEST, BuiltInLootTables.JUNGLE_TEMPLE_DISPENSER)); // DivineMC - Chunk System Optimizations - } - - this.placeBlock(level, Blocks.VINE.defaultBlockState().setValue(VineBlock.EAST, true), 8, -1, 3, box); - this.placeBlock(level, Blocks.VINE.defaultBlockState().setValue(VineBlock.EAST, true), 8, -2, 3, box); -- if (!this.placedMainChest) { -- this.placedMainChest = this.createChest(level, box, random, 8, -3, 3, BuiltInLootTables.JUNGLE_TEMPLE); -+ if (!this.placedMainChest.get()) { // DivineMC - Chunk System Optimizations -+ this.placedMainChest.set(this.createChest(level, box, random, 8, -3, 3, BuiltInLootTables.JUNGLE_TEMPLE)); // DivineMC - Chunk System Optimizations - } - - this.placeBlock(level, Blocks.MOSSY_COBBLESTONE.defaultBlockState(), 9, -3, 2, box); -@@ -378,8 +384,8 @@ public class JungleTemplePiece extends ScatteredFeaturePiece { - this.placeBlock(level, Blocks.STICKY_PISTON.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.WEST), 10, -2, 8, box); - this.placeBlock(level, Blocks.STICKY_PISTON.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.WEST), 10, -1, 8, box); - this.placeBlock(level, Blocks.REPEATER.defaultBlockState().setValue(RepeaterBlock.FACING, Direction.NORTH), 10, -2, 10, box); -- if (!this.placedHiddenChest) { -- this.placedHiddenChest = this.createChest(level, box, random, 9, -3, 10, BuiltInLootTables.JUNGLE_TEMPLE); -+ if (!this.placedHiddenChest.get()) { // DivineMC - Chunk System Optimizations -+ this.placedHiddenChest.set(this.createChest(level, box, random, 9, -3, 10, BuiltInLootTables.JUNGLE_TEMPLE)); // DivineMC - Chunk System Optimizations - } - } - } -diff --git a/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java b/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java -index 53d3bf1d2a1debe46e276b1db25b420be4ad9958..5212e4a4392efa0171c9d709dc2606a4e14df07f 100644 ---- a/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java -+++ b/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java -@@ -91,7 +91,7 @@ public class MineshaftPieces { - public static class MineShaftCorridor extends MineshaftPieces.MineShaftPiece { - private final boolean hasRails; - private final boolean spiderCorridor; -- private boolean hasPlacedSpider; -+ private volatile boolean hasPlacedSpider; // DivineMC - Chunk System Optimizations - private final int numSections; - - public MineShaftCorridor(CompoundTag tag) { -@@ -950,7 +950,7 @@ public class MineshaftPieces { - } - - public static class MineShaftRoom extends MineshaftPieces.MineShaftPiece { -- private final List childEntranceBoxes = Lists.newLinkedList(); -+ private final List childEntranceBoxes = java.util.Collections.synchronizedList(Lists.newLinkedList()); // DivineMC - Chunk System Optimizations - - public MineShaftRoom(int genDepth, RandomSource random, int x, int z, MineshaftStructure.Type type) { - super( -diff --git a/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java b/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java -index ae4ffcf1859e8ff7f8fbc91246e66e20f5c33dd7..b9124999f1aede4450f25e25c55bca96077670e8 100644 ---- a/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java -+++ b/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java -@@ -1112,7 +1112,7 @@ public class NetherFortressPieces { - int i = 0; - - for (NetherFortressPieces.PieceWeight pieceWeight : weights) { -- if (pieceWeight.maxPlaceCount > 0 && pieceWeight.placeCount < pieceWeight.maxPlaceCount) { -+ if (pieceWeight.maxPlaceCount > 0 && pieceWeight.placeCount.get() < pieceWeight.maxPlaceCount) { // DivineMC - Chunk System Optimizations - flag = true; - } - -@@ -1152,7 +1152,7 @@ public class NetherFortressPieces { - pieceWeight, pieces, random, x, y, z, orientation, genDepth - ); - if (netherBridgePiece != null) { -- pieceWeight.placeCount++; -+ pieceWeight.placeCount.set(pieceWeight.placeCount.get() + 1); // DivineMC - Chunk System Optimizations - startPiece.previousPiece = pieceWeight; - if (!pieceWeight.isValid()) { - weights.remove(pieceWeight); -@@ -1387,7 +1387,7 @@ public class NetherFortressPieces { - static class PieceWeight { - public final Class pieceClass; - public final int weight; -- public int placeCount; -+ public final ThreadLocal placeCount = ThreadLocal.withInitial(() -> 0); // DivineMC - Chunk System Optimizations - public final int maxPlaceCount; - public final boolean allowInRow; - -@@ -1403,11 +1403,11 @@ public class NetherFortressPieces { - } - - public boolean doPlace(int genDepth) { -- return this.maxPlaceCount == 0 || this.placeCount < this.maxPlaceCount; -+ return this.maxPlaceCount == 0 || this.placeCount.get() < this.maxPlaceCount; // DivineMC - Chunk System Optimizations - } - - public boolean isValid() { -- return this.maxPlaceCount == 0 || this.placeCount < this.maxPlaceCount; -+ return this.maxPlaceCount == 0 || this.placeCount.get() < this.maxPlaceCount; // DivineMC - Chunk System Optimizations - } - } - -@@ -1545,24 +1545,24 @@ public class NetherFortressPieces { - } - - public static class StartPiece extends NetherFortressPieces.BridgeCrossing { -- public NetherFortressPieces.PieceWeight previousPiece; -+ public volatile NetherFortressPieces.PieceWeight previousPiece; // DivineMC - Chunk System Optimizations - public List availableBridgePieces; - public List availableCastlePieces; - public final List pendingChildren = Lists.newArrayList(); - - public StartPiece(RandomSource random, int x, int z) { - super(x, z, getRandomHorizontalDirection(random)); -- this.availableBridgePieces = Lists.newArrayList(); -+ this.availableBridgePieces = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations - - for (NetherFortressPieces.PieceWeight pieceWeight : NetherFortressPieces.BRIDGE_PIECE_WEIGHTS) { -- pieceWeight.placeCount = 0; -+ pieceWeight.placeCount.remove(); // DivineMC - Chunk System Optimizations - this.availableBridgePieces.add(pieceWeight); - } - -- this.availableCastlePieces = Lists.newArrayList(); -+ this.availableCastlePieces = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations - - for (NetherFortressPieces.PieceWeight pieceWeight : NetherFortressPieces.CASTLE_PIECE_WEIGHTS) { -- pieceWeight.placeCount = 0; -+ pieceWeight.placeCount.remove(); // DivineMC - Chunk System Optimizations - this.availableCastlePieces.add(pieceWeight); - } - } -diff --git a/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java b/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java -index 1f1ee6e2d020cd06184313d19523ea928cf242c8..ab6d51b60cdbaed7ac7395d2a27eadd6d6b4518f 100644 ---- a/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java -+++ b/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java -@@ -65,32 +65,36 @@ public class StrongholdPieces { - } - } - }; -- private static List currentPieces; -- static Class imposedPiece; -- private static int totalWeight; -+ // DivineMC start - Chunk System Optimizations -+ private static final ThreadLocal> currentPieces = new ThreadLocal>(); -+ static final ThreadLocal> imposedPiece = new ThreadLocal>(); -+ private static final ThreadLocal totalWeight = ThreadLocal.withInitial(() -> 0); -+ // DivineMC end - Chunk System Optimizations - static final StrongholdPieces.SmoothStoneSelector SMOOTH_STONE_SELECTOR = new StrongholdPieces.SmoothStoneSelector(); - - public static void resetPieces() { -- currentPieces = Lists.newArrayList(); -+ // DivineMC start - Chunk System Optimizations -+ currentPieces.set(Lists.newArrayList()); - - for (StrongholdPieces.PieceWeight pieceWeight : STRONGHOLD_PIECE_WEIGHTS) { -- pieceWeight.placeCount = 0; -- currentPieces.add(pieceWeight); -+ pieceWeight.placeCount.set(0); -+ currentPieces.get().add(pieceWeight); - } - -- imposedPiece = null; -+ imposedPiece.set(null); -+ // DivineMC end - Chunk System Optimizations - } - - private static boolean updatePieceWeight() { - boolean flag = false; -- totalWeight = 0; -+ totalWeight.set(0); // DivineMC - Chunk System Optimizations - -- for (StrongholdPieces.PieceWeight pieceWeight : currentPieces) { -- if (pieceWeight.maxPlaceCount > 0 && pieceWeight.placeCount < pieceWeight.maxPlaceCount) { -+ for (StrongholdPieces.PieceWeight pieceWeight : currentPieces.get()) { // DivineMC - Chunk System Optimizations -+ if (pieceWeight.maxPlaceCount > 0 && pieceWeight.placeCount.get() < pieceWeight.maxPlaceCount) { // DivineMC - Chunk System Optimizations - flag = true; - } - -- totalWeight = totalWeight + pieceWeight.weight; -+ totalWeight.set(totalWeight.get() + pieceWeight.weight); // DivineMC - Chunk System Optimizations - } - - return flag; -@@ -140,9 +144,11 @@ public class StrongholdPieces { - if (!updatePieceWeight()) { - return null; - } else { -- if (imposedPiece != null) { -- StrongholdPieces.StrongholdPiece strongholdPiece = findAndCreatePieceFactory(imposedPiece, pieces, random, x, y, z, direction, genDepth); -- imposedPiece = null; -+ // DivineMC start - Chunk System Optimizations -+ if (imposedPiece.get() != null) { -+ StrongholdPieces.StrongholdPiece strongholdPiece = findAndCreatePieceFactory(imposedPiece.get(), pieces, random, x, y, z, direction, genDepth); -+ imposedPiece.set(null); -+ // DivineMC end - Chunk System Optimizations - if (strongholdPiece != null) { - return strongholdPiece; - } -@@ -152,9 +158,9 @@ public class StrongholdPieces { - - while (i < 5) { - i++; -- int randomInt = random.nextInt(totalWeight); -+ int randomInt = random.nextInt(totalWeight.get()); // DivineMC - Chunk System Optimizations - -- for (StrongholdPieces.PieceWeight pieceWeight : currentPieces) { -+ for (StrongholdPieces.PieceWeight pieceWeight : currentPieces.get()) { // DivineMC - Chunk System Optimizations - randomInt -= pieceWeight.weight; - if (randomInt < 0) { - if (!pieceWeight.doPlace(genDepth) || pieceWeight == piece.previousPiece) { -@@ -165,10 +171,10 @@ public class StrongholdPieces { - pieceWeight.pieceClass, pieces, random, x, y, z, direction, genDepth - ); - if (strongholdPiece1 != null) { -- pieceWeight.placeCount++; -+ pieceWeight.placeCount.set(pieceWeight.placeCount.get() + 1); // DivineMC - Chunk System Optimizations - piece.previousPiece = pieceWeight; - if (!pieceWeight.isValid()) { -- currentPieces.remove(pieceWeight); -+ currentPieces.get().remove(pieceWeight); // DivineMC - Chunk System Optimizations - } - - return strongholdPiece1; -@@ -204,7 +210,7 @@ public class StrongholdPieces { - private static final int WIDTH = 5; - private static final int HEIGHT = 5; - private static final int DEPTH = 7; -- private boolean hasPlacedChest; -+ private volatile boolean hasPlacedChest; // DivineMC - Chunk System Optimizations - - public ChestCorridor(int genDepth, RandomSource random, BoundingBox box, Direction orientation) { - super(StructurePieceType.STRONGHOLD_CHEST_CORRIDOR, genDepth, box); -@@ -690,7 +696,7 @@ public class StrongholdPieces { - static class PieceWeight { - public final Class pieceClass; - public final int weight; -- public int placeCount; -+ public final ThreadLocal placeCount = ThreadLocal.withInitial(() -> 0); // DivineMC - Chunk System Optimizations - public final int maxPlaceCount; - - public PieceWeight(Class pieceClass, int weight, int maxPlaceCount) { -@@ -700,11 +706,11 @@ public class StrongholdPieces { - } - - public boolean doPlace(int genDepth) { -- return this.maxPlaceCount == 0 || this.placeCount < this.maxPlaceCount; -+ return this.maxPlaceCount == 0 || this.placeCount.get() < this.maxPlaceCount; // DivineMC - Chunk System Optimizations - } - - public boolean isValid() { -- return this.maxPlaceCount == 0 || this.placeCount < this.maxPlaceCount; -+ return this.maxPlaceCount == 0 || this.placeCount.get() < this.maxPlaceCount; // DivineMC - Chunk System Optimizations - } - } - -@@ -712,7 +718,7 @@ public class StrongholdPieces { - protected static final int WIDTH = 11; - protected static final int HEIGHT = 8; - protected static final int DEPTH = 16; -- private boolean hasPlacedSpawner; -+ private volatile boolean hasPlacedSpawner; // DivineMC - Chunk System Optimizations - - public PortalRoom(int genDepth, BoundingBox box, Direction orientation) { - super(StructurePieceType.STRONGHOLD_PORTAL_ROOM, genDepth, box); -@@ -1174,7 +1180,7 @@ public class StrongholdPieces { - @Override - public void addChildren(StructurePiece piece, StructurePieceAccessor pieces, RandomSource random) { - if (this.isSource) { -- StrongholdPieces.imposedPiece = StrongholdPieces.FiveCrossing.class; -+ StrongholdPieces.imposedPiece.set(StrongholdPieces.FiveCrossing.class); - } - - this.generateSmallDoorChildForward((StrongholdPieces.StartPiece)piece, pieces, random, 1, 1); -@@ -1223,10 +1229,10 @@ public class StrongholdPieces { - } - - public static class StartPiece extends StrongholdPieces.StairsDown { -- public StrongholdPieces.PieceWeight previousPiece; -+ public volatile StrongholdPieces.PieceWeight previousPiece; // DivineMC - Chunk System Optimizations - @Nullable -- public StrongholdPieces.PortalRoom portalRoomPiece; -- public final List pendingChildren = Lists.newArrayList(); -+ public volatile StrongholdPieces.PortalRoom portalRoomPiece; // DivineMC - Chunk System Optimizations -+ public final List pendingChildren = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations - - public StartPiece(RandomSource random, int x, int z) { - super(StructurePieceType.STRONGHOLD_START, 0, x, z, getRandomHorizontalDirection(random)); -diff --git a/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java b/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java -index 872fd2ebe6f95cf1d59e18a4c5ca15d12a65b7b0..9e4aa26d18dd748b5f7af59e88af612ad1224d1f 100644 ---- a/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java -+++ b/net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces.java -@@ -126,7 +126,7 @@ public class WoodlandMansionPieces { - int i = 11; - this.entranceX = 7; - this.entranceY = 4; -- this.baseGrid = new WoodlandMansionPieces.SimpleGrid(11, 11, 5); -+ this.baseGrid = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(11, 11, 5); // DivineMC - Chunk System Optimizations - this.baseGrid.set(this.entranceX, this.entranceY, this.entranceX + 1, this.entranceY + 1, 3); - this.baseGrid.set(this.entranceX - 1, this.entranceY, this.entranceX - 1, this.entranceY + 1, 2); - this.baseGrid.set(this.entranceX + 2, this.entranceY - 2, this.entranceX + 3, this.entranceY + 3, 5); -@@ -145,14 +145,16 @@ public class WoodlandMansionPieces { - } - - this.floorRooms = new WoodlandMansionPieces.SimpleGrid[3]; -- this.floorRooms[0] = new WoodlandMansionPieces.SimpleGrid(11, 11, 5); -- this.floorRooms[1] = new WoodlandMansionPieces.SimpleGrid(11, 11, 5); -- this.floorRooms[2] = new WoodlandMansionPieces.SimpleGrid(11, 11, 5); -+ // DivineMC start - Chunk System Optimizations -+ this.floorRooms[0] = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(11, 11, 5); -+ this.floorRooms[1] = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(11, 11, 5); -+ this.floorRooms[2] = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(11, 11, 5); -+ // DivineMC end - Chunk System Optimizations - this.identifyRooms(this.baseGrid, this.floorRooms[0]); - this.identifyRooms(this.baseGrid, this.floorRooms[1]); - this.floorRooms[0].set(this.entranceX + 1, this.entranceY, this.entranceX + 1, this.entranceY + 1, 8388608); - this.floorRooms[1].set(this.entranceX + 1, this.entranceY, this.entranceX + 1, this.entranceY + 1, 8388608); -- this.thirdFloorGrid = new WoodlandMansionPieces.SimpleGrid(this.baseGrid.width, this.baseGrid.height, 5); -+ this.thirdFloorGrid = new org.bxteam.divinemc.util.ConcurrentFlagMatrix(this.baseGrid.width, this.baseGrid.height, 5); // DivineMC - Chunk System Optimizations - this.setupThirdFloor(); - this.identifyRooms(this.thirdFloorGrid, this.floorRooms[2]); - } -@@ -1139,9 +1141,11 @@ public class WoodlandMansionPieces { - } - - static class PlacementData { -- public Rotation rotation; -- public BlockPos position; -- public String wallType; -+ // DivineMC start - Chunk System Optimizations -+ public volatile Rotation rotation; -+ public volatile BlockPos position; -+ public volatile String wallType; -+ // DivineMC end - Chunk System Optimizations - } - - static class SecondFloorRoomCollection extends WoodlandMansionPieces.FloorRoomCollection { -diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java b/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java -index 05027cc20d174d78bef118cd2ba545ac56e1559c..32bbfe48dee44b0b491aa369dec59cbf0772c4b5 100644 ---- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java -+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java -@@ -22,7 +22,7 @@ public class StructurePlaceSettings { - @Nullable - private RandomSource random; - public int palette = -1; // CraftBukkit - Set initial value so we know if the palette has been set forcefully -- private final List processors = Lists.newArrayList(); -+ private final List processors = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations - private boolean knownShape; - private boolean finalizeEntities; - -diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -index f21e612a35d6ac4482dbf5d14e506959659e371a..5a05536e474bec574aa637f86bfc51f566d76ebf 100644 ---- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java -@@ -75,8 +75,8 @@ public class StructureTemplate { - public static final String ENTITY_TAG_BLOCKPOS = "blockPos"; - public static final String ENTITY_TAG_NBT = "nbt"; - public static final String SIZE_TAG = "size"; -- public final List palettes = Lists.newArrayList(); -- public final List entityInfoList = Lists.newArrayList(); -+ public final List palettes = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations -+ public final List entityInfoList = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System Optimizations - private Vec3i size = Vec3i.ZERO; - private String author = "?"; - // CraftBukkit start - data containers -diff --git a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java -index 46e98a99442523614284150964ba528d0c91493f..75df6465823ebacad48f3a0b3560c89ab3b6b093 100644 ---- a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java -+++ b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java -@@ -11,6 +11,27 @@ public final class ImprovedNoise { - public final double yo; - public final double zo; - -+ // DivineMC start - Chunk System Optimizations -+ private static final double[] FLAT_SIMPLEX_GRAD = new double[]{ -+ 1, 1, 0, 0, -+ -1, 1, 0, 0, -+ 1, -1, 0, 0, -+ -1, -1, 0, 0, -+ 1, 0, 1, 0, -+ -1, 0, 1, 0, -+ 1, 0, -1, 0, -+ -1, 0, -1, 0, -+ 0, 1, 1, 0, -+ 0, -1, 1, 0, -+ 0, 1, -1, 0, -+ 0, -1, -1, 0, -+ 1, 1, 0, 0, -+ 0, -1, 1, 0, -+ -1, 1, 0, 0, -+ 0, -1, -1, 0, -+ }; -+ // DivineMC end - Chunk System Optimizations -+ - public ImprovedNoise(RandomSource random) { - this.xo = random.nextDouble() * 256.0; - this.yo = random.nextDouble() * 256.0; -@@ -38,9 +59,11 @@ public final class ImprovedNoise { - double d = x + this.xo; - double d1 = y + this.yo; - double d2 = z + this.zo; -- int floor = Mth.floor(d); -- int floor1 = Mth.floor(d1); -- int floor2 = Mth.floor(d2); -+ // DivineMC start - Chunk System Optimizations -+ double floor = Math.floor(d); -+ double floor1 = Math.floor(d1); -+ double floor2 = Math.floor(d2); -+ // DivineMC end - Chunk System Optimizations - double d3 = d - floor; - double d4 = d1 - floor1; - double d5 = d2 - floor2; -@@ -53,25 +76,27 @@ public final class ImprovedNoise { - d6 = d4; - } - -- d7 = Mth.floor(d6 / yScale + 1.0E-7F) * yScale; -+ d7 = Math.floor(d6 / yScale + 1.0E-7F) * yScale; // DivineMC - Chunk System Optimizations - } else { - d7 = 0.0; - } - -- return this.sampleAndLerp(floor, floor1, floor2, d3, d4 - d7, d5, d4); -+ return this.sampleAndLerp((int) floor, (int) floor1, (int) floor2, d3, d4 - d7, d5, d4); // DivineMC - Chunk System Optimizations - } - - public double noiseWithDerivative(double x, double y, double z, double[] values) { - double d = x + this.xo; - double d1 = y + this.yo; - double d2 = z + this.zo; -- int floor = Mth.floor(d); -- int floor1 = Mth.floor(d1); -- int floor2 = Mth.floor(d2); -+ // DivineMC start - Chunk System Optimizations -+ double floor = Math.floor(d); -+ double floor1 = Math.floor(d1); -+ double floor2 = Math.floor(d2); -+ // DivineMC end - Chunk System Optimizations - double d3 = d - floor; - double d4 = d1 - floor1; - double d5 = d2 - floor2; -- return this.sampleWithDerivative(floor, floor1, floor2, d3, d4, d5, values); -+ return this.sampleWithDerivative((int) floor, (int) floor1, (int) floor2, d3, d4, d5, values); // DivineMC - Chunk System Optimizations - } - - private static double gradDot(int gradIndex, double xFactor, double yFactor, double zFactor) { -@@ -83,24 +108,69 @@ public final class ImprovedNoise { - } - - private double sampleAndLerp(int gridX, int gridY, int gridZ, double deltaX, double weirdDeltaY, double deltaZ, double deltaY) { -- int i = this.p(gridX); -- int i1 = this.p(gridX + 1); -- int i2 = this.p(i + gridY); -- int i3 = this.p(i + gridY + 1); -- int i4 = this.p(i1 + gridY); -- int i5 = this.p(i1 + gridY + 1); -- double d = gradDot(this.p(i2 + gridZ), deltaX, weirdDeltaY, deltaZ); -- double d1 = gradDot(this.p(i4 + gridZ), deltaX - 1.0, weirdDeltaY, deltaZ); -- double d2 = gradDot(this.p(i3 + gridZ), deltaX, weirdDeltaY - 1.0, deltaZ); -- double d3 = gradDot(this.p(i5 + gridZ), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ); -- double d4 = gradDot(this.p(i2 + gridZ + 1), deltaX, weirdDeltaY, deltaZ - 1.0); -- double d5 = gradDot(this.p(i4 + gridZ + 1), deltaX - 1.0, weirdDeltaY, deltaZ - 1.0); -- double d6 = gradDot(this.p(i3 + gridZ + 1), deltaX, weirdDeltaY - 1.0, deltaZ - 1.0); -- double d7 = gradDot(this.p(i5 + gridZ + 1), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ - 1.0); -- double d8 = Mth.smoothstep(deltaX); -- double d9 = Mth.smoothstep(deltaY); -- double d10 = Mth.smoothstep(deltaZ); -- return Mth.lerp3(d8, d9, d10, d, d1, d2, d3, d4, d5, d6, d7); -+ // DivineMC start - Chunk System Optimizations -+ final int var0 = gridX & 0xFF; -+ final int var1 = (gridX + 1) & 0xFF; -+ final int var2 = this.p[var0] & 0xFF; -+ final int var3 = this.p[var1] & 0xFF; -+ final int var4 = (var2 + gridY) & 0xFF; -+ final int var5 = (var3 + gridY) & 0xFF; -+ final int var6 = (var2 + gridY + 1) & 0xFF; -+ final int var7 = (var3 + gridY + 1) & 0xFF; -+ final int var8 = this.p[var4] & 0xFF; -+ final int var9 = this.p[var5] & 0xFF; -+ final int var10 = this.p[var6] & 0xFF; -+ final int var11 = this.p[var7] & 0xFF; -+ -+ final int var12 = (var8 + gridZ) & 0xFF; -+ final int var13 = (var9 + gridZ) & 0xFF; -+ final int var14 = (var10 + gridZ) & 0xFF; -+ final int var15 = (var11 + gridZ) & 0xFF; -+ final int var16 = (var8 + gridZ + 1) & 0xFF; -+ final int var17 = (var9 + gridZ + 1) & 0xFF; -+ final int var18 = (var10 + gridZ + 1) & 0xFF; -+ final int var19 = (var11 + gridZ + 1) & 0xFF; -+ final int var20 = (this.p[var12] & 15) << 2; -+ final int var21 = (this.p[var13] & 15) << 2; -+ final int var22 = (this.p[var14] & 15) << 2; -+ final int var23 = (this.p[var15] & 15) << 2; -+ final int var24 = (this.p[var16] & 15) << 2; -+ final int var25 = (this.p[var17] & 15) << 2; -+ final int var26 = (this.p[var18] & 15) << 2; -+ final int var27 = (this.p[var19] & 15) << 2; -+ final double var60 = deltaX - 1.0; -+ final double var61 = weirdDeltaY - 1.0; -+ final double var62 = deltaZ - 1.0; -+ final double var87 = FLAT_SIMPLEX_GRAD[(var20) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var20) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var20) | 2] * deltaZ; -+ final double var88 = FLAT_SIMPLEX_GRAD[(var21) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var21) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var21) | 2] * deltaZ; -+ final double var89 = FLAT_SIMPLEX_GRAD[(var22) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var22) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var22) | 2] * deltaZ; -+ final double var90 = FLAT_SIMPLEX_GRAD[(var23) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var23) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var23) | 2] * deltaZ; -+ final double var91 = FLAT_SIMPLEX_GRAD[(var24) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var24) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var24) | 2] * var62; -+ final double var92 = FLAT_SIMPLEX_GRAD[(var25) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var25) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var25) | 2] * var62; -+ final double var93 = FLAT_SIMPLEX_GRAD[(var26) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var26) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var26) | 2] * var62; -+ final double var94 = FLAT_SIMPLEX_GRAD[(var27) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var27) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var27) | 2] * var62; -+ -+ final double var95 = deltaX * 6.0 - 15.0; -+ final double var96 = deltaY * 6.0 - 15.0; -+ final double var97 = deltaZ * 6.0 - 15.0; -+ final double var98 = deltaX * var95 + 10.0; -+ final double var99 = deltaY * var96 + 10.0; -+ final double var100 = deltaZ * var97 + 10.0; -+ final double var101 = deltaX * deltaX * deltaX * var98; -+ final double var102 = deltaY * deltaY * deltaY * var99; -+ final double var103 = deltaZ * deltaZ * deltaZ * var100; -+ -+ final double var113 = var87 + var101 * (var88 - var87); -+ final double var114 = var93 + var101 * (var94 - var93); -+ final double var115 = var91 + var101 * (var92 - var91); -+ final double var116 = var89 + var101 * (var90 - var89); -+ final double var117 = var114 - var115; -+ final double var118 = var102 * (var116 - var113); -+ final double var119 = var102 * var117; -+ final double var120 = var113 + var118; -+ final double var121 = var115 + var119; -+ return var120 + (var103 * (var121 - var120)); -+ // DivineMC end - Chunk System Optimizations - } - - private double sampleWithDerivative(int gridX, int gridY, int gridZ, double deltaX, double deltaY, double deltaZ, double[] noiseValues) { -diff --git a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java -index ffac5b7b1eb1364ab8442d7145a7b4ebde68ee10..d331259b0bcf2d3c27718497ff2593a29d1558d0 100644 ---- a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java -+++ b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java -@@ -26,6 +26,10 @@ public class PerlinNoise { - public final double lowestFreqValueFactor; - public final double lowestFreqInputFactor; - private final double maxValue; -+ // DivineMC start - Chunk System Optimizations -+ private final int octaveSamplersCount; -+ private final double [] amplitudesArray; -+ // DivineMC end - Chunk System Optimizations - - @Deprecated - public static PerlinNoise createLegacyForBlendedNoise(RandomSource random, IntStream octaves) { -@@ -127,6 +131,10 @@ public class PerlinNoise { - this.lowestFreqInputFactor = Math.pow(2.0, -i); - this.lowestFreqValueFactor = Math.pow(2.0, size - 1) / (Math.pow(2.0, size) - 1.0); - this.maxValue = this.edgeValue(2.0); -+ // DivineMC start - Chunk System Optimizations -+ this.octaveSamplersCount = this.noiseLevels.length; -+ this.amplitudesArray = this.amplitudes.toDoubleArray(); -+ // DivineMC end - Chunk System Optimizations - } - - protected double maxValue() { -@@ -138,7 +146,26 @@ public class PerlinNoise { - } - - public double getValue(double x, double y, double z) { -- return this.getValue(x, y, z, 0.0, 0.0, false); -+ // DivineMC start - Chunk System Optimizations -+ double d = 0.0; -+ double e = this.lowestFreqInputFactor; -+ double f = this.lowestFreqValueFactor; -+ -+ for (int i = 0; i < this.octaveSamplersCount; ++i) { -+ ImprovedNoise perlinNoiseSampler = this.noiseLevels[i]; -+ if (perlinNoiseSampler != null) { -+ double g = perlinNoiseSampler.noise( -+ wrap(x * e), wrap(y * e), wrap(z * e), 0.0, 0.0 -+ ); -+ d += this.amplitudesArray[i] * g * f; -+ } -+ -+ e *= 2.0; -+ f /= 2.0; -+ } -+ -+ return d; -+ // DivineMC end - Chunk System Optimizations - } - - @Deprecated -@@ -187,7 +214,7 @@ public class PerlinNoise { - } - - public static double wrap(double value) { -- return value - Mth.lfloor(value / 3.3554432E7 + 0.5) * 3.3554432E7; -+ return value - Math.floor(value / 3.3554432E7 + 0.5) * 3.3554432E7; // DivineMC - Chunk System Optimizations - } - - protected int firstOctave() { -diff --git a/net/minecraft/world/ticks/LevelChunkTicks.java b/net/minecraft/world/ticks/LevelChunkTicks.java -index 66d0a6390febe929ef774b0a7813329015bc8cc2..d1917dee4ca6bba5f2c92475811c724caf2948cb 100644 ---- a/net/minecraft/world/ticks/LevelChunkTicks.java -+++ b/net/minecraft/world/ticks/LevelChunkTicks.java -@@ -14,10 +14,10 @@ import javax.annotation.Nullable; - import net.minecraft.core.BlockPos; - - public class LevelChunkTicks implements SerializableTickContainer, TickContainerAccess, ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks { // Paper - rewrite chunk system -- private final Queue> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER); -+ private final Queue> tickQueue = new java.util.concurrent.PriorityBlockingQueue<>(11, ScheduledTick.DRAIN_ORDER); // DivineMC - Chunk System Optimizations - @Nullable - private List> pendingTicks; -- private final Set> ticksPerPosition = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH); -+ private final Set> ticksPerPosition = it.unimi.dsi.fastutil.objects.ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH)); // DivineMC - Chunk System Optimizations - @Nullable - private BiConsumer, ScheduledTick> onTickAdded; - -@@ -67,10 +67,18 @@ public class LevelChunkTicks implements SerializableTickContainer, TickCon - - @Nullable - public ScheduledTick poll() { -- ScheduledTick scheduledTick = this.tickQueue.poll(); -- if (scheduledTick != null) { -- this.ticksPerPosition.remove(scheduledTick); this.dirty = true; // Paper - rewrite chunk system -+ // DivineMC start - Chunk System Optimizations -+ ScheduledTick scheduledTick = null; -+ try { -+ scheduledTick = this.tickQueue.poll(); -+ if (scheduledTick != null) { -+ this.ticksPerPosition.remove(scheduledTick); this.dirty = true; // Paper - rewrite chunk system -+ } -+ } catch (Exception e) { -+ net.minecraft.server.MinecraftServer.LOGGER.error("Encountered caught exception when polling chunk ticks, blocking and returning null.", e); -+ return null; - } -+ // DivineMC end - Chunk System Optimizations - - return scheduledTick; - } -@@ -83,6 +91,7 @@ public class LevelChunkTicks implements SerializableTickContainer, TickCon - } - - private void scheduleUnchecked(ScheduledTick tick) { -+ if (tick == null) return; // DivineMC - Chunk System Optimizations - this.tickQueue.add(tick); - if (this.onTickAdded != null) { - this.onTickAdded.accept(this, tick); -@@ -124,6 +133,7 @@ public class LevelChunkTicks implements SerializableTickContainer, TickCon - } - - for (ScheduledTick scheduledTick : this.tickQueue) { -+ if (scheduledTick == null) continue; // DivineMC - Chunk System Optimizations - fix NPE - list.add(scheduledTick.toSavedTick(gametime)); - } - -diff --git a/net/minecraft/world/ticks/LevelTicks.java b/net/minecraft/world/ticks/LevelTicks.java -index 0a9805d42142678ca5213c511235daa6505ddbf3..6e3d4e78a7d92a846e68fe60271cfe5a5cd7b569 100644 ---- a/net/minecraft/world/ticks/LevelTicks.java -+++ b/net/minecraft/world/ticks/LevelTicks.java -@@ -30,17 +30,18 @@ public class LevelTicks implements LevelTickAccess { - private static final Comparator> CONTAINER_DRAIN_ORDER = (levelChunkTicks, levelChunkTicks1) -> ScheduledTick.INTRA_TICK_DRAIN_ORDER - .compare(levelChunkTicks.peek(), levelChunkTicks1.peek()); - private final LongPredicate tickCheck; -- private final Long2ObjectMap> allContainers = new Long2ObjectOpenHashMap<>(); -- private final Long2LongMap nextTickForContainer = Util.make(new Long2LongOpenHashMap(), map -> map.defaultReturnValue(Long.MAX_VALUE)); -- private final Queue> containersToTick = new PriorityQueue<>(CONTAINER_DRAIN_ORDER); -- private final Queue> toRunThisTick = new ArrayDeque<>(); -+ private final Long2ObjectMap> allContainers = it.unimi.dsi.fastutil.longs.Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); // DivineMC - Chunk System Optimizations -+ private final java.util.Map nextTickForContainer = new java.util.concurrent.ConcurrentHashMap<>(); // DivineMC - Chunk System Optimizations -+ private final Queue> containersToTick = new java.util.concurrent.PriorityBlockingQueue<>(11, CONTAINER_DRAIN_ORDER); // DivineMC - Chunk System Optimizations -+ private final Queue> toRunThisTick = new java.util.concurrent.ConcurrentLinkedQueue<>(); // DivineMC - Chunk System Optimizations - private final List> alreadyRunThisTick = new ArrayList<>(); -- private final Set> toRunThisTickSet = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH); -+ private final Set> toRunThisTickSet = com.google.common.collect.Sets.newConcurrentHashSet(); // DivineMC - Chunk System Optimizations - private final BiConsumer, ScheduledTick> chunkScheduleUpdater = (levelChunkTicks, scheduledTick) -> { - if (scheduledTick.equals(levelChunkTicks.peek())) { - this.updateContainerScheduling(scheduledTick); - } - }; -+ private final java.util.concurrent.atomic.AtomicInteger toRunThisTickCount = new java.util.concurrent.atomic.AtomicInteger(0); // DivineMC - Chunk System Optimizations - - public LevelTicks(LongPredicate tickCheck) { - this.tickCheck = tickCheck; -@@ -90,12 +91,14 @@ public class LevelTicks implements LevelTickAccess { - } - - private void sortContainersToTick(long gameTime) { -- ObjectIterator objectIterator = Long2LongMaps.fastIterator(this.nextTickForContainer); -+ java.util.Iterator> objectIterator = this.nextTickForContainer.entrySet().iterator(); // DivineMC - Chunk System Optimizations - - while (objectIterator.hasNext()) { -- Entry entry = objectIterator.next(); -- long longKey = entry.getLongKey(); -- long longValue = entry.getLongValue(); -+ // DivineMC start - Chunk System Optimizations -+ java.util.Map.Entry entry = objectIterator.next(); -+ long longKey = entry.getKey(); -+ long longValue = entry.getValue(); -+ // DivineMC end - Chunk System Optimizations - if (longValue <= gameTime) { - LevelChunkTicks levelChunkTicks = this.allContainers.get(longKey); - if (levelChunkTicks == null) { -@@ -162,16 +165,19 @@ public class LevelTicks implements LevelTickAccess { - } - - private void scheduleForThisTick(ScheduledTick tick) { -+ if (tick == null) return; // DivineMC - Chunk System Optimizations - this.toRunThisTick.add(tick); -+ this.toRunThisTickCount.incrementAndGet(); // DivineMC - Chunk System Optimizations - } - - private boolean canScheduleMoreTicks(int maxAllowedTicks) { -- return this.toRunThisTick.size() < maxAllowedTicks; -+ return this.toRunThisTickCount.get() < maxAllowedTicks; // DivineMC - Chunk System Optimizations - } - - private void runCollectedTicks(BiConsumer ticker) { - while (!this.toRunThisTick.isEmpty()) { - ScheduledTick scheduledTick = this.toRunThisTick.poll(); -+ this.toRunThisTickCount.decrementAndGet(); // DivineMC - Chunk System Optimizations - if (!this.toRunThisTickSet.isEmpty()) { - this.toRunThisTickSet.remove(scheduledTick); - } -@@ -182,7 +188,7 @@ public class LevelTicks implements LevelTickAccess { - } - - private void cleanupAfterTick() { -- this.toRunThisTick.clear(); -+ this.toRunThisTickCount.set(0); // DivineMC - Chunk System Optimizations - this.containersToTick.clear(); - this.alreadyRunThisTick.clear(); - this.toRunThisTickSet.clear(); diff --git a/patches/work/server/minecraft/0009-Regionized-Chunk-Ticking.patch b/patches/work/server/minecraft/0078-Regionized-Chunk-Ticking.patch similarity index 94% rename from patches/work/server/minecraft/0009-Regionized-Chunk-Ticking.patch rename to patches/work/server/minecraft/0078-Regionized-Chunk-Ticking.patch index a6fd509..6b6b5a5 100644 --- a/patches/work/server/minecraft/0009-Regionized-Chunk-Ticking.patch +++ b/patches/work/server/minecraft/0078-Regionized-Chunk-Ticking.patch @@ -10,7 +10,7 @@ Original idea by Dueris, modified by NONPLAYT and heavily optimized by dan28000 TODO: switchable VT diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index cdacbfa64bda461d4f24c2a85db9feae7766b597..07370cb7bc0bb5a8abfd0062df999ed24c936113 100644 +index e72eda830644851656fae3118c513d7bd701be45..4ab30d291de7db5ad7d5684662f41348270802b9 100644 --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java @@ -326,7 +326,7 @@ public class Connection extends SimpleChannelInboundHandler> { @@ -23,7 +23,7 @@ index cdacbfa64bda461d4f24c2a85db9feae7766b597..07370cb7bc0bb5a8abfd0062df999ed2 if (var2 instanceof ClosedChannelException) { LOGGER.info("Connection closed during protocol change"); diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 3cf54630d36f821a232fa03f9094c4c1f70902a1..5f62eee8a60d7fcadb1f9efb7473bc5c20c47263 100644 +index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee4019e6e1c7c 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -57,6 +57,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -47,7 +47,7 @@ index 3cf54630d36f821a232fa03f9094c4c1f70902a1..5f62eee8a60d7fcadb1f9efb7473bc5c @Nullable @VisibleForDebug private NaturalSpawner.SpawnState lastSpawnState; -@@ -153,31 +156,240 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -153,32 +156,241 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon return load ? this.syncLoad(chunkX, chunkZ, toStatus) : null; } // Paper end - rewrite chunk system @@ -236,7 +236,11 @@ index 3cf54630d36f821a232fa03f9094c4c1f70902a1..5f62eee8a60d7fcadb1f9efb7473bc5c + return regionChunksIDs; + }, REGION_EXECUTOR)); + } -+ + +- // call mid-tick tasks for chunk system +- if ((i & 7) == 0) { +- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks(); +- continue; + CompletableFuture.runAsync(() -> { + try { + CompletableFuture.allOf(ticked.toArray(new CompletableFuture[0])).join(); @@ -283,12 +287,10 @@ index 3cf54630d36f821a232fa03f9094c4c1f70902a1..5f62eee8a60d7fcadb1f9efb7473bc5c + java.util.Objects.checkFromToIndex(0, size, raw.length); + for (int i = 0; i < size; ++i) { + world.tickChunk(raw[i], randomTickSpeed); - -- // call mid-tick tasks for chunk system -- if ((i & 7) == 0) { -- continue; ++ + // call mid-tick tasks for chunk system + if ((i & 7) == 0) { ++ ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks(); + continue; + } } @@ -297,7 +299,7 @@ index 3cf54630d36f821a232fa03f9094c4c1f70902a1..5f62eee8a60d7fcadb1f9efb7473bc5c } // Paper end - chunk tick iteration optimisations -@@ -501,14 +713,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -503,14 +715,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon long gameTime = this.level.getGameTime(); long l = gameTime - this.lastInhabitedUpdate; this.lastInhabitedUpdate = gameTime; @@ -323,7 +325,7 @@ index 3cf54630d36f821a232fa03f9094c4c1f70902a1..5f62eee8a60d7fcadb1f9efb7473bc5c // DivineMC start - Async mob spawning if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) { for (ServerPlayer player : this.level.players) { -@@ -537,14 +756,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -554,14 +773,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } private void broadcastChangedChunks() { @@ -348,34 +350,31 @@ index 3cf54630d36f821a232fa03f9094c4c1f70902a1..5f62eee8a60d7fcadb1f9efb7473bc5c } private void tickChunks(long timeInhabited) { -@@ -594,25 +817,28 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -611,23 +834,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon filteredSpawningCategories = List.of(); } - List list = this.spawningChunks; -- -- try { -- this.chunkMap.collectSpawningChunks(list); -- // Paper start - chunk tick iteration optimisation -- if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { -- this.shuffleRandom.setSeed(this.level.random.nextLong()); // DivineMC - Misc Optimizations -- Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled -- } -- // Paper end - chunk tick iteration optimisation + // DivineMC start - Regionized Chunk Ticking + final java.util.concurrent.CompletableFuture spawns = java.util.concurrent.CompletableFuture.runAsync(() -> { + List list = this.spawningChunks; + +- try { +- this.chunkMap.collectSpawningChunks(list); +- // Paper start - chunk tick iteration optimisation +- this.shuffleRandom.setSeed(this.level.random.nextLong()); +- if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled +- // Paper end - chunk tick iteration optimisation +- +- for (LevelChunk levelChunk : list) { +- this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Async mob spawning + try { + this.chunkMap.collectSpawningChunks(list); + // Paper start - chunk tick iteration optimisation -+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { -+ this.shuffleRandom.setSeed(this.level.random.nextLong()); // DivineMC - Misc Optimizations -+ Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled -+ } ++ this.shuffleRandom.setSeed(this.level.random.nextLong()); ++ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled + // Paper end - chunk tick iteration optimisation - -- for (LevelChunk levelChunk : list) { -- this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Async mob spawning ++ + for (LevelChunk levelChunk : list) { + this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Async mob spawning + } @@ -394,10 +393,10 @@ index 3cf54630d36f821a232fa03f9094c4c1f70902a1..5f62eee8a60d7fcadb1f9efb7473bc5c this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); } diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index d39d15dcb6964aed0bf9c2f64952d229d64cff62..69b2ce6647edacabdff5079114e067a69d485e96 100644 +index 3c1795eb56900cd80cfec38bd1d922d566463ecb..97f3c9de6e472fc271afd3373846cce954293997 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -192,7 +192,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -191,7 +191,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe private final LevelTicks blockTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded); private final LevelTicks fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded); private final PathTypeCache pathTypesByPosCache = new PathTypeCache(); @@ -406,7 +405,7 @@ index d39d15dcb6964aed0bf9c2f64952d229d64cff62..69b2ce6647edacabdff5079114e067a6 volatile boolean isUpdatingNavigations; protected final Raids raids; private final ObjectLinkedOpenHashSet blockEvents = new ObjectLinkedOpenHashSet<>(); -@@ -808,6 +808,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -798,6 +798,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.dragonFight.tick(); } @@ -420,7 +419,7 @@ index d39d15dcb6964aed0bf9c2f64952d229d64cff62..69b2ce6647edacabdff5079114e067a6 io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR this.entityTickList .forEach( -@@ -1815,22 +1822,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1813,22 +1820,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe if (Shapes.joinIsNotEmpty(collisionShape, collisionShape1, BooleanOp.NOT_SAME)) { List list = new ObjectArrayList<>(); @@ -452,7 +451,7 @@ index d39d15dcb6964aed0bf9c2f64952d229d64cff62..69b2ce6647edacabdff5079114e067a6 try { this.isUpdatingNavigations = true; diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index dc82e12783989c307be2ac709a21321dac25f217..f6b548dbb8b1bd82b5ddc73e2613cdcde059ce74 100644 +index bf38e3bfcb0b96c4529d5e535893043512f52b02..82afe39d85395182acbd36a89db7b4436ecc1297 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -106,7 +106,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @@ -473,7 +472,7 @@ index dc82e12783989c307be2ac709a21321dac25f217..f6b548dbb8b1bd82b5ddc73e2613cdcd public Map capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates @Nullable public List captureDrops; -@@ -1503,10 +1503,14 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1501,10 +1501,14 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl protected void tickBlockEntities() { this.tickingBlockEntities = true; diff --git a/patches/work/server/paper/0006-Chunk-System-Optimizations.patch b/patches/work/server/paper/0006-Chunk-System-Optimizations.patch deleted file mode 100644 index 585d87f..0000000 --- a/patches/work/server/paper/0006-Chunk-System-Optimizations.patch +++ /dev/null @@ -1,693 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Apr 2025 18:03:38 +0300 -Subject: [PATCH] Chunk System Optimizations - - -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java -index 7fed43a1e7bcf35c4d7fd3224837a47fedd59860..353f1412b6edf481162ded50fa9a23d3442b9ed5 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java -@@ -1,5 +1,7 @@ - package ca.spottedleaf.moonrise.common.list; - -+import it.unimi.dsi.fastutil.ints.Int2IntMap; -+import it.unimi.dsi.fastutil.ints.Int2IntMaps; - import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; - import net.minecraft.world.entity.Entity; - import java.util.Arrays; -@@ -13,7 +15,7 @@ import java.util.NoSuchElementException; - */ - public final class EntityList implements Iterable { - -- private final Int2IntOpenHashMap entityToIndex = new Int2IntOpenHashMap(2, 0.8f); -+ private final Int2IntMap entityToIndex = Int2IntMaps.synchronize(new Int2IntOpenHashMap(2, 0.8f)); // DivineMC - Chunk System Optimizations - { - this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE); - } -@@ -27,11 +29,11 @@ public final class EntityList implements Iterable { - return this.count; - } - -- public boolean contains(final Entity entity) { -+ public synchronized boolean contains(final Entity entity) { // DivineMC - Chunk System Optimizations - return this.entityToIndex.containsKey(entity.getId()); - } - -- public boolean remove(final Entity entity) { -+ public synchronized boolean remove(final Entity entity) { // DivineMC - Chunk System Optimizations - final int index = this.entityToIndex.remove(entity.getId()); - if (index == Integer.MIN_VALUE) { - return false; -@@ -50,7 +52,7 @@ public final class EntityList implements Iterable { - return true; - } - -- public boolean add(final Entity entity) { -+ public synchronized boolean add(final Entity entity) { // DivineMC - Chunk System Optimizations - final int count = this.count; - final int currIndex = this.entityToIndex.putIfAbsent(entity.getId(), count); - -@@ -82,18 +84,18 @@ public final class EntityList implements Iterable { - return this.entities[index]; - } - -- public Entity[] getRawData() { -+ public synchronized Entity[] getRawData() { // DivineMC - Chunk System Optimizations - return this.entities; - } - -- public void clear() { -+ public synchronized void clear() { // DivineMC - Chunk System Optimizations - this.entityToIndex.clear(); - Arrays.fill(this.entities, 0, this.count, null); - this.count = 0; - } - - @Override -- public Iterator iterator() { -+ public synchronized Iterator iterator() { // DivineMC - Chunk System Optimizations - return new Iterator<>() { - private Entity lastRet; - private int current; -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java -index 2e876b918672e8ef3b5197b7e6b1597247fdeaa1..aab585e226e0928d778dc83a33bdcaf5f5a6f213 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java -@@ -1,142 +1,26 @@ - package ca.spottedleaf.moonrise.common.list; - --import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; --import java.util.Arrays; --import java.util.Iterator; --import java.util.NoSuchElementException; -+// DivineMC start - Chunk System Optimizations - rewrite -+import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -+import it.unimi.dsi.fastutil.objects.ReferenceLists; - --public final class ReferenceList implements Iterable { -- -- private static final Object[] EMPTY_LIST = new Object[0]; -- -- private final Reference2IntOpenHashMap referenceToIndex; -- private E[] references; -- private int count; -- -- public ReferenceList() { -- this((E[])EMPTY_LIST); -- } -- -- public ReferenceList(final E[] referenceArray) { -- this.references = referenceArray; -- this.referenceToIndex = new Reference2IntOpenHashMap<>(2, 0.8f); -- this.referenceToIndex.defaultReturnValue(Integer.MIN_VALUE); -- } -- -- private ReferenceList(final E[] references, final int count, final Reference2IntOpenHashMap referenceToIndex) { -- this.references = references; -- this.count = count; -- this.referenceToIndex = referenceToIndex; -- } -- -- public ReferenceList copy() { -- return new ReferenceList<>(this.references.clone(), this.count, this.referenceToIndex.clone()); -- } -- -- public int size() { -- return this.count; -- } -- -- public boolean contains(final E obj) { -- return this.referenceToIndex.containsKey(obj); -+public class ReferenceList extends ReferenceLists.SynchronizedList { -+ public ReferenceList(E[] elements) { -+ super(new RefListInner<>(elements)); - } - -- public boolean remove(final E obj) { -- final int index = this.referenceToIndex.removeInt(obj); -- if (index == Integer.MIN_VALUE) { -- return false; -- } -- -- // move the object at the end to this index -- final int endIndex = --this.count; -- final E end = (E)this.references[endIndex]; -- if (index != endIndex) { -- // not empty after this call -- this.referenceToIndex.put(end, index); // update index -- } -- this.references[index] = end; -- this.references[endIndex] = null; -- -- return true; -+ public synchronized E[] getRawDataUnchecked() { -+ return ((RefListInner) this.list).getRawDataUnchecked(); - } - -- public boolean add(final E obj) { -- final int count = this.count; -- final int currIndex = this.referenceToIndex.putIfAbsent(obj, count); -- -- if (currIndex != Integer.MIN_VALUE) { -- return false; // already in this list -+ public static class RefListInner extends ReferenceArrayList { -+ public RefListInner(A[] elements) { -+ super(elements, true); - } - -- E[] list = this.references; -- -- if (list.length == count) { -- // resize required -- list = this.references = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative -+ public A[] getRawDataUnchecked() { -+ return this.a; - } -- -- list[count] = obj; -- this.count = count + 1; -- -- return true; -- } -- -- public E getChecked(final int index) { -- if (index < 0 || index >= this.count) { -- throw new IndexOutOfBoundsException("Index: " + index + " is out of bounds, size: " + this.count); -- } -- return this.references[index]; -- } -- -- public E getUnchecked(final int index) { -- return this.references[index]; -- } -- -- public Object[] getRawData() { -- return this.references; -- } -- -- public E[] getRawDataUnchecked() { -- return this.references; -- } -- -- public void clear() { -- this.referenceToIndex.clear(); -- Arrays.fill(this.references, 0, this.count, null); -- this.count = 0; -- } -- -- @Override -- public Iterator iterator() { -- return new Iterator<>() { -- private E lastRet; -- private int current; -- -- @Override -- public boolean hasNext() { -- return this.current < ReferenceList.this.count; -- } -- -- @Override -- public E next() { -- if (this.current >= ReferenceList.this.count) { -- throw new NoSuchElementException(); -- } -- return this.lastRet = ReferenceList.this.references[this.current++]; -- } -- -- @Override -- public void remove() { -- final E lastRet = this.lastRet; -- -- if (lastRet == null) { -- throw new IllegalStateException(); -- } -- this.lastRet = null; -- -- ReferenceList.this.remove(lastRet); -- --this.current; -- } -- }; - } - } -+// DivineMC end - Chunk System Optimizations - rewrite -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java -index 2bae9949ef325d0001aa638150fbbdf968367e75..11bf4ddb298bb39f7f39a9c33c90b48a3171266b 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java -@@ -1,11 +1,13 @@ - package ca.spottedleaf.moonrise.common.list; - -+import it.unimi.dsi.fastutil.shorts.Short2ShortMap; -+import it.unimi.dsi.fastutil.shorts.Short2ShortMaps; - import it.unimi.dsi.fastutil.shorts.Short2ShortOpenHashMap; - import java.util.Arrays; - - public final class ShortList { - -- private final Short2ShortOpenHashMap map = new Short2ShortOpenHashMap(); -+ private final Short2ShortMap map = Short2ShortMaps.synchronize(new Short2ShortOpenHashMap()); // DivineMC - Chunk System Optimizations - { - this.map.defaultReturnValue(Short.MIN_VALUE); - } -@@ -13,13 +15,13 @@ public final class ShortList { - private static final short[] EMPTY_LIST = new short[0]; - - private short[] byIndex = EMPTY_LIST; -- private short count; -+ private volatile short count; // DivineMC - Chunk System Optimizations - - public int size() { -- return (int)this.count; -+ return this.count; // DivineMC - Chunk System Optimizations - } - -- public short getRaw(final int index) { -+ public synchronized short getRaw(final int index) { // DivineMC - Chunk System Optimizations - return this.byIndex[index]; - } - -@@ -30,8 +32,8 @@ public final class ShortList { - } - } - -- public boolean add(final short value) { -- final int count = (int)this.count; -+ public synchronized boolean add(final short value) { // DivineMC - Chunk System Optimizations -+ final int count = this.count; // DivineMC - Chunk System Optimizations - final short currIndex = this.map.putIfAbsent(value, (short)count); - - if (currIndex != Short.MIN_VALUE) { -@@ -51,7 +53,7 @@ public final class ShortList { - return true; - } - -- public boolean remove(final short value) { -+ public synchronized boolean remove(final short value) { // DivineMC - Chunk System Optimizations - final short index = this.map.remove(value); - if (index == Short.MIN_VALUE) { - return false; -@@ -70,7 +72,7 @@ public final class ShortList { - return true; - } - -- public void clear() { -+ public synchronized void clear() { // DivineMC - Chunk System Optimizations - this.count = (short)0; - this.map.clear(); - } -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java -index 460e27ab0506c83a28934800ee74ee886d4b025e..49e53bf85352f4d1b9997fa3c30e37e40c0ff01c 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java -@@ -15,7 +15,7 @@ public final class Delayed26WayDistancePropagator3D { - - // Generally updates to positions are made close to other updates, so we link to decrease cache misses when - // propagating updates -- protected final LongLinkedOpenHashSet updatedSources = new LongLinkedOpenHashSet(); -+ protected final it.unimi.dsi.fastutil.longs.LongSet updatedSources = it.unimi.dsi.fastutil.longs.LongSets.synchronize(new LongLinkedOpenHashSet()); // DivineMC - Chunk System Optimizations - - @FunctionalInterface - public static interface LevelChangeCallback { -@@ -94,29 +94,29 @@ public final class Delayed26WayDistancePropagator3D { - - protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) { - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[level]; -- queue.queuedCoordinates.enqueue(coordinate); -- queue.queuedLevels.enqueue(level); -+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations -+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations - - this.levelIncreaseWorkQueueBitset |= (1L << level); - } - - protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) { - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[index]; -- queue.queuedCoordinates.enqueue(coordinate); -- queue.queuedLevels.enqueue(level); -+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations -+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations - - this.levelIncreaseWorkQueueBitset |= (1L << index); - } - - protected final void addToRemoveWorkQueue(final long coordinate, final byte level) { - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[level]; -- queue.queuedCoordinates.enqueue(coordinate); -- queue.queuedLevels.enqueue(level); -+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations -+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations - - this.levelRemoveWorkQueueBitset |= (1L << level); - } - -- public boolean propagateUpdates() { -+ public synchronized boolean propagateUpdates() { // DivineMC - Chunk System Optimizations - if (this.updatedSources.isEmpty()) { - return false; - } -@@ -157,15 +157,15 @@ public final class Delayed26WayDistancePropagator3D { - return ret; - } - -- protected void propagateIncreases() { -+ protected synchronized void propagateIncreases() { // DivineMC - Chunk System Optimizations - for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset); - this.levelIncreaseWorkQueueBitset != 0L; - this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) { - - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex]; - while (!queue.queuedLevels.isEmpty()) { -- final long coordinate = queue.queuedCoordinates.removeFirstLong(); -- byte level = queue.queuedLevels.removeFirstByte(); -+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations -+ byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations - - final boolean neighbourCheck = level < 0; - -@@ -226,15 +226,15 @@ public final class Delayed26WayDistancePropagator3D { - } - } - -- protected void propagateDecreases() { -+ protected synchronized void propagateDecreases() { // DivineMC - Chunk System Optimizations - for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset); - this.levelRemoveWorkQueueBitset != 0L; - this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) { - - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[queueIndex]; - while (!queue.queuedLevels.isEmpty()) { -- final long coordinate = queue.queuedCoordinates.removeFirstLong(); -- final byte level = queue.queuedLevels.removeFirstByte(); -+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations -+ final byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations - - final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level); - if (currentLevel == 0) { -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java -index ab2fa1563d5e32a5313dfcc1da411cab45fb5ca0..1bababc2515d8c805e4ee0c943065f451a38b7b8 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java -@@ -356,24 +356,24 @@ public final class Delayed8WayDistancePropagator2D { - - protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) { - final WorkQueue queue = this.levelIncreaseWorkQueues[level]; -- queue.queuedCoordinates.enqueue(coordinate); -- queue.queuedLevels.enqueue(level); -+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations -+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations - - this.levelIncreaseWorkQueueBitset |= (1L << level); - } - - protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) { - final WorkQueue queue = this.levelIncreaseWorkQueues[index]; -- queue.queuedCoordinates.enqueue(coordinate); -- queue.queuedLevels.enqueue(level); -+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations -+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations - - this.levelIncreaseWorkQueueBitset |= (1L << index); - } - - protected final void addToRemoveWorkQueue(final long coordinate, final byte level) { - final WorkQueue queue = this.levelRemoveWorkQueues[level]; -- queue.queuedCoordinates.enqueue(coordinate); -- queue.queuedLevels.enqueue(level); -+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations -+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations - - this.levelRemoveWorkQueueBitset |= (1L << level); - } -@@ -426,8 +426,8 @@ public final class Delayed8WayDistancePropagator2D { - - final WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex]; - while (!queue.queuedLevels.isEmpty()) { -- final long coordinate = queue.queuedCoordinates.removeFirstLong(); -- byte level = queue.queuedLevels.removeFirstByte(); -+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations -+ byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations - - final boolean neighbourCheck = level < 0; - -@@ -492,8 +492,8 @@ public final class Delayed8WayDistancePropagator2D { - - final WorkQueue queue = this.levelRemoveWorkQueues[queueIndex]; - while (!queue.queuedLevels.isEmpty()) { -- final long coordinate = queue.queuedCoordinates.removeFirstLong(); -- final byte level = queue.queuedLevels.removeFirstByte(); -+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations -+ final byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations - - final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level); - if (currentLevel == 0) { -@@ -561,7 +561,7 @@ public final class Delayed8WayDistancePropagator2D { - } - - // copied from superclass -- private int find(final long k) { -+ private synchronized int find(final long k) { // DivineMC - Chunk System Optimizations - if (k == 0L) { - return this.containsNullKey ? this.n : -(this.n + 1); - } else { -@@ -585,7 +585,7 @@ public final class Delayed8WayDistancePropagator2D { - } - - // copied from superclass -- private void insert(final int pos, final long k, final byte v) { -+ private synchronized void insert(final int pos, final long k, final byte v) { // DivineMC - Chunk System Optimizations - if (pos == this.n) { - this.containsNullKey = true; - } -@@ -598,7 +598,7 @@ public final class Delayed8WayDistancePropagator2D { - } - - // copied from superclass -- public byte putIfGreater(final long key, final byte value) { -+ public synchronized byte putIfGreater(final long key, final byte value) { // DivineMC - Chunk System Optimizations - final int pos = this.find(key); - if (pos < 0) { - if (this.defRetValue < value) { -@@ -616,7 +616,7 @@ public final class Delayed8WayDistancePropagator2D { - } - - // copied from superclass -- private void removeEntry(final int pos) { -+ private synchronized void removeEntry(final int pos) { // DivineMC - Chunk System Optimizations - --this.size; - this.shiftKeys(pos); - if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) { -@@ -625,7 +625,7 @@ public final class Delayed8WayDistancePropagator2D { - } - - // copied from superclass -- private void removeNullEntry() { -+ private synchronized void removeNullEntry() { // DivineMC - Chunk System Optimizations - this.containsNullKey = false; - --this.size; - if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) { -@@ -634,7 +634,7 @@ public final class Delayed8WayDistancePropagator2D { - } - - // copied from superclass -- public byte removeIfGreaterOrEqual(final long key, final byte value) { -+ public synchronized byte removeIfGreaterOrEqual(final long key, final byte value) { // DivineMC - Chunk System Optimizations - if (key == 0L) { - if (!this.containsNullKey) { - return this.defRetValue; -@@ -679,8 +679,8 @@ public final class Delayed8WayDistancePropagator2D { - - protected static final class WorkQueue { - -- public final NoResizeLongArrayFIFODeque queuedCoordinates = new NoResizeLongArrayFIFODeque(); -- public final NoResizeByteArrayFIFODeque queuedLevels = new NoResizeByteArrayFIFODeque(); -+ public final java.util.concurrent.ConcurrentLinkedDeque queuedCoordinates = new java.util.concurrent.ConcurrentLinkedDeque<>(); -+ public final java.util.concurrent.ConcurrentLinkedDeque queuedLevels = new java.util.concurrent.ConcurrentLinkedDeque<>(); - - } - -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java -index 632920e04686d8a0fd0a60e87348be1fe7862a3c..03e7344661b6aea258918bd388dc0e4e6fb5bc96 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java -@@ -3,6 +3,11 @@ package ca.spottedleaf.moonrise.common.util; - import ca.spottedleaf.concurrentutil.executor.thread.PrioritisedThreadPool; - import ca.spottedleaf.moonrise.common.PlatformHooks; - import com.mojang.logging.LogUtils; -+import org.bxteam.divinemc.config.DivineConfig; -+import org.bxteam.divinemc.server.chunk.TheChunkSystem; -+import org.bxteam.divinemc.spark.ThreadDumperRegistry; -+import org.bxteam.divinemc.util.ThreadBuilder; -+import org.jetbrains.annotations.NotNull; - import org.slf4j.Logger; - import java.util.concurrent.TimeUnit; - import java.util.concurrent.atomic.AtomicInteger; -@@ -12,83 +17,73 @@ public final class MoonriseCommon { - - private static final Logger LOGGER = LogUtils.getClassLogger(); - -- public static final PrioritisedThreadPool WORKER_POOL = new PrioritisedThreadPool( -- new Consumer<>() { -- private final AtomicInteger idGenerator = new AtomicInteger(); -- -- @Override -- public void accept(Thread thread) { -- thread.setDaemon(true); -- thread.setName(PlatformHooks.get().getBrand() + " Common Worker #" + this.idGenerator.getAndIncrement()); -- thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { -- @Override -- public void uncaughtException(final Thread thread, final Throwable throwable) { -- LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable); -- } -- }); -- } -- } -- ); -- public static final long WORKER_QUEUE_HOLD_TIME = (long)(20.0e6); // 20ms -- public static final int CLIENT_DIVISION = 0; -- public static final PrioritisedThreadPool.ExecutorGroup RENDER_EXECUTOR_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(CLIENT_DIVISION, 0); -- public static final int SERVER_DIVISION = 1; -- public static final PrioritisedThreadPool.ExecutorGroup PARALLEL_GEN_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0); -- public static final PrioritisedThreadPool.ExecutorGroup RADIUS_AWARE_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0); -- public static final PrioritisedThreadPool.ExecutorGroup LOAD_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0); -- -- public static void adjustWorkerThreads(final int configWorkerThreads, final int configIoThreads) { -- int defaultWorkerThreads = Runtime.getRuntime().availableProcessors() / 2; -- if (defaultWorkerThreads <= 4) { -- defaultWorkerThreads = defaultWorkerThreads <= 3 ? 1 : 2; -- } else { -- defaultWorkerThreads = defaultWorkerThreads / 2; -- } -- defaultWorkerThreads = Integer.getInteger(PlatformHooks.get().getBrand() + ".WorkerThreadCount", Integer.valueOf(defaultWorkerThreads)); -+ public static TheChunkSystem WORKER_POOL; -+ public static TheChunkSystem.ExecutorGroup PARALLEL_GEN_GROUP; -+ public static TheChunkSystem.ExecutorGroup RADIUS_AWARE_GROUP; -+ public static TheChunkSystem.ExecutorGroup LOAD_GROUP; - -+ public static void init(final int configWorkerThreads, final int configIoThreads) { - int workerThreads = configWorkerThreads; - -- if (workerThreads <= 0) { -- workerThreads = defaultWorkerThreads; -+ if (configWorkerThreads <= 0) { -+ boolean isWindows = io.netty.util.internal.PlatformDependent.isWindows(); -+ int cpus = Runtime.getRuntime().availableProcessors(); -+ double memGb = Runtime.getRuntime().maxMemory() / 1024.0 / 1024.0 / 1024.0; -+ -+ double cpuBased = isWindows ? (cpus / 1.6) : (cpus / 1.3); -+ double memBased = (memGb - 0.5) / 0.6; -+ -+ workerThreads = (int) Math.max(1, Math.min(cpuBased, memBased)); - } - -- final int ioThreads = Math.max(1, configIoThreads); -+ int ioThreads = Math.max(1, configIoThreads); - -- WORKER_POOL.adjustThreadCount(workerThreads); -+ WORKER_POOL = buildChunkSystem(workerThreads); -+ PARALLEL_GEN_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(); -+ RADIUS_AWARE_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(); -+ LOAD_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(); - IO_POOL.adjustThreadCount(ioThreads); - -- LOGGER.info(PlatformHooks.get().getBrand() + " is using " + workerThreads + " worker threads, " + ioThreads + " I/O threads"); -+ LOGGER.info("Running ChunkSystem with {} worker threads and {} I/O threads", workerThreads, ioThreads); -+ } -+ -+ private static @NotNull TheChunkSystem buildChunkSystem(int workerThreads) { -+ return new TheChunkSystem(workerThreads, new ThreadBuilder() { -+ @Override -+ public void accept(final Thread thread) { -+ thread.setPriority(DivineConfig.PerformanceCategory.threadPoolPriority); -+ thread.setDaemon(true); -+ thread.setUncaughtExceptionHandler((thread1, throwable) -> LOGGER.error("Uncaught exception in thread {}", thread1.getName(), throwable)); -+ thread.setName("World Gen Worker #" + getAndIncrementId()); -+ ThreadDumperRegistry.REGISTRY.add(thread.getName()); -+ } -+ }); - } - - public static final PrioritisedThreadPool IO_POOL = new PrioritisedThreadPool( -- new Consumer<>() { -- private final AtomicInteger idGenerator = new AtomicInteger(); -- -- @Override -- public void accept(final Thread thread) { -- thread.setDaemon(true); -- thread.setName(PlatformHooks.get().getBrand() + " I/O Worker #" + this.idGenerator.getAndIncrement()); -- thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { -- @Override -- public void uncaughtException(final Thread thread, final Throwable throwable) { -- LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable); -- } -- }); -- } -+ new Consumer<>() { -+ private final AtomicInteger idGenerator = new AtomicInteger(); -+ -+ @Override -+ public void accept(final Thread thread) { -+ thread.setDaemon(true); -+ thread.setName(PlatformHooks.get().getBrand() + " I/O Worker #" + this.idGenerator.getAndIncrement()); -+ ThreadDumperRegistry.REGISTRY.add(thread.getName()); -+ thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { -+ @Override -+ public void uncaughtException(final Thread thread, final Throwable throwable) { -+ LOGGER.error("Uncaught exception in thread {}", thread.getName(), throwable); -+ } -+ }); - } -+ } - ); - public static final long IO_QUEUE_HOLD_TIME = (long)(100.0e6); // 100ms -- public static final PrioritisedThreadPool.ExecutorGroup CLIENT_PROFILER_IO_GROUP = IO_POOL.createExecutorGroup(CLIENT_DIVISION, 0); -- public static final PrioritisedThreadPool.ExecutorGroup SERVER_REGION_IO_GROUP = IO_POOL.createExecutorGroup(SERVER_DIVISION, 0); -+ public static final PrioritisedThreadPool.ExecutorGroup SERVER_REGION_IO_GROUP = IO_POOL.createExecutorGroup(1, 0); - - public static void haltExecutors() { -- MoonriseCommon.WORKER_POOL.shutdown(false); -- LOGGER.info("Awaiting termination of worker pool for up to 60s..."); -- if (!MoonriseCommon.WORKER_POOL.join(TimeUnit.SECONDS.toMillis(60L))) { -- LOGGER.error("Worker pool did not shut down in time!"); -- MoonriseCommon.WORKER_POOL.halt(false); -- } -- -+ LOGGER.info("Shutting down ChunkSystem..."); -+ MoonriseCommon.WORKER_POOL.shutdown(); - MoonriseCommon.IO_POOL.shutdown(false); - LOGGER.info("Awaiting termination of I/O pool for up to 60s..."); - if (!MoonriseCommon.IO_POOL.join(TimeUnit.SECONDS.toMillis(60L))) { -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java -index 559c959aff3c9deef867b9e425fba3e2e669cac6..7d0281cc946d6b0dc6f21fa6798e5320ae589bcf 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java -@@ -4,7 +4,7 @@ import ca.spottedleaf.moonrise.common.PlatformHooks; - - public final class MoonriseConstants { - -- public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", 32); -+ public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.maxViewDistance); // DivineMC - Configurable view distance - - private MoonriseConstants() {} - -diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -index c5a491acfe4b93bfa8fd21861edbaf464a178bf3..d13c749cfb49ce3c70b4c24ece780a4fc9482d78 100644 ---- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -227,7 +227,7 @@ public class GlobalConfiguration extends ConfigurationPart { - - @PostProcess - private void postProcess() { -- ca.spottedleaf.moonrise.common.util.MoonriseCommon.adjustWorkerThreads(this.workerThreads, this.ioThreads); -+ ca.spottedleaf.moonrise.common.util.MoonriseCommon.init(this.workerThreads, this.ioThreads); - String newChunkSystemGenParallelism = this.genParallelism; - if (newChunkSystemGenParallelism.equalsIgnoreCase("default")) { - newChunkSystemGenParallelism = "true"; -@@ -243,7 +243,6 @@ public class GlobalConfiguration extends ConfigurationPart { - } else { - throw new IllegalStateException("Invalid option for gen-parallelism: must be one of [on, off, enabled, disabled, true, false, default]"); - } -- FeatureHooks.initChunkTaskScheduler(useParallelGen); - } - } - From 2485087165f5e529e5b94f09fd18f5fc9f9cba96 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 9 Jul 2025 03:46:15 +0300 Subject: [PATCH 12/67] final applies, continuing config update --- .../0081-Regionized-Chunk-Ticking.patch | 54 +++--- ...0082-Use-fastutil-for-criterion-data.patch | 19 ++ .../features/0020-Rewrite-ReferenceList.patch | 167 ++++++++++++++++++ .../SimpleCriterionTrigger.java.patch | 11 -- 4 files changed, 215 insertions(+), 36 deletions(-) rename patches/work/server/minecraft/0078-Regionized-Chunk-Ticking.patch => divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch (95%) create mode 100644 divinemc-server/minecraft-patches/features/0082-Use-fastutil-for-criterion-data.patch create mode 100644 divinemc-server/paper-patches/features/0020-Rewrite-ReferenceList.patch delete mode 100644 patches/work/server/sources/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java.patch diff --git a/patches/work/server/minecraft/0078-Regionized-Chunk-Ticking.patch b/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch similarity index 95% rename from patches/work/server/minecraft/0078-Regionized-Chunk-Ticking.patch rename to divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch index 6b6b5a5..e3b20d7 100644 --- a/patches/work/server/minecraft/0078-Regionized-Chunk-Ticking.patch +++ b/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch @@ -23,7 +23,7 @@ index e72eda830644851656fae3118c513d7bd701be45..4ab30d291de7db5ad7d5684662f41348 if (var2 instanceof ClosedChannelException) { LOGGER.info("Connection closed during protocol change"); diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee4019e6e1c7c 100644 +index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afad669ae9f 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -57,6 +57,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -47,7 +47,7 @@ index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee401 @Nullable @VisibleForDebug private NaturalSpawner.SpawnState lastSpawnState; -@@ -153,32 +156,241 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -153,31 +156,246 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon return load ? this.syncLoad(chunkX, chunkZ, toStatus) : null; } // Paper end - rewrite chunk system @@ -130,15 +130,21 @@ index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee401 + + final Set firstTick = java.util.Collections.newSetFromMap(new java.util.concurrent.ConcurrentHashMap<>()); + -+ level.entityTickList.entities.parallelStream().forEach(entity -> { -+ long chunkKey = entity.chunkPosition().longKey; -+ int regionIndex = chunkToRegion.get(chunkKey); -+ if (regionIndex != -1) { -+ regions.get(regionIndex).entities().add(entity); -+ } else { -+ firstTick.add(entity); ++ final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator iterator = level.entityTickList.entities.iterator(); ++ try { ++ while (iterator.hasNext()) { ++ Entity entity = iterator.next(); ++ long chunkKey = entity.chunkPosition().longKey; ++ int regionIndex = chunkToRegion.get(chunkKey); ++ if (regionIndex != -1) { ++ regions.get(regionIndex).entities().add(entity); ++ } else { ++ firstTick.add(entity); ++ } + } -+ }); ++ } finally { ++ iterator.finishedIterating(); ++ } + + return new Output(regions.toArray(new RegionData[0]), firstTick); + } @@ -236,11 +242,7 @@ index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee401 + return regionChunksIDs; + }, REGION_EXECUTOR)); + } - -- // call mid-tick tasks for chunk system -- if ((i & 7) == 0) { -- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks(); -- continue; ++ + CompletableFuture.runAsync(() -> { + try { + CompletableFuture.allOf(ticked.toArray(new CompletableFuture[0])).join(); @@ -274,7 +276,10 @@ index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee401 + latch.await(); + return true; + } -+ + +- // call mid-tick tasks for chunk system +- if ((i & 7) == 0) { +- continue; + @Override + public boolean isReleasable() { + return latch.getCount() == 0; @@ -290,7 +295,6 @@ index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee401 + + // call mid-tick tasks for chunk system + if ((i & 7) == 0) { -+ ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks(); + continue; + } } @@ -299,7 +303,7 @@ index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee401 } // Paper end - chunk tick iteration optimisations -@@ -503,14 +715,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -502,14 +720,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon long gameTime = this.level.getGameTime(); long l = gameTime - this.lastInhabitedUpdate; this.lastInhabitedUpdate = gameTime; @@ -325,7 +329,7 @@ index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee401 // DivineMC start - Async mob spawning if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) { for (ServerPlayer player : this.level.players) { -@@ -554,14 +773,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -553,14 +778,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } private void broadcastChangedChunks() { @@ -350,7 +354,7 @@ index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee401 } private void tickChunks(long timeInhabited) { -@@ -611,23 +834,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -610,23 +839,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon filteredSpawningCategories = List.of(); } @@ -393,7 +397,7 @@ index a76f7ce474cc1d6ff918737e845666a7529bd4a3..af3875e88020d6265522f07b263ee401 this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); } diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 3c1795eb56900cd80cfec38bd1d922d566463ecb..97f3c9de6e472fc271afd3373846cce954293997 100644 +index 07138e724d46ecfd09aa75008428502fa01c05fc..d4841095157106c3c69501ac2cd09511f62cfea0 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -191,7 +191,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -405,7 +409,7 @@ index 3c1795eb56900cd80cfec38bd1d922d566463ecb..97f3c9de6e472fc271afd3373846cce9 volatile boolean isUpdatingNavigations; protected final Raids raids; private final ObjectLinkedOpenHashSet blockEvents = new ObjectLinkedOpenHashSet<>(); -@@ -798,6 +798,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -806,6 +806,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.dragonFight.tick(); } @@ -419,7 +423,7 @@ index 3c1795eb56900cd80cfec38bd1d922d566463ecb..97f3c9de6e472fc271afd3373846cce9 io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR this.entityTickList .forEach( -@@ -1813,22 +1820,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1828,22 +1835,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe if (Shapes.joinIsNotEmpty(collisionShape, collisionShape1, BooleanOp.NOT_SAME)) { List list = new ObjectArrayList<>(); @@ -451,7 +455,7 @@ index 3c1795eb56900cd80cfec38bd1d922d566463ecb..97f3c9de6e472fc271afd3373846cce9 try { this.isUpdatingNavigations = true; diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index bf38e3bfcb0b96c4529d5e535893043512f52b02..82afe39d85395182acbd36a89db7b4436ecc1297 100644 +index dc82e12783989c307be2ac709a21321dac25f217..f6b548dbb8b1bd82b5ddc73e2613cdcde059ce74 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -106,7 +106,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @@ -472,7 +476,7 @@ index bf38e3bfcb0b96c4529d5e535893043512f52b02..82afe39d85395182acbd36a89db7b443 public Map capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates @Nullable public List captureDrops; -@@ -1501,10 +1501,14 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1503,10 +1503,14 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl protected void tickBlockEntities() { this.tickingBlockEntities = true; diff --git a/divinemc-server/minecraft-patches/features/0082-Use-fastutil-for-criterion-data.patch b/divinemc-server/minecraft-patches/features/0082-Use-fastutil-for-criterion-data.patch new file mode 100644 index 0000000..e0e5ac1 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0082-Use-fastutil-for-criterion-data.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 9 Jul 2025 03:41:32 +0300 +Subject: [PATCH] Use fastutil for criterion data + + +diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java +index 8efed0ffdc906b6c1ba054831e481f53c11f102d..1aab02441e4dfa7703963855d77bb918dee7a6fc 100644 +--- a/net/minecraft/server/PlayerAdvancements.java ++++ b/net/minecraft/server/PlayerAdvancements.java +@@ -61,7 +61,7 @@ public class PlayerAdvancements { + private AdvancementHolder lastSelectedTab; + private boolean isFirstPacket = true; + private final Codec codec; +- public final Map, Set>> criterionData = new java.util.IdentityHashMap<>(); // Paper - fix advancement data player leakage ++ public final Map, Set>> criterionData = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(); // Paper - fix advancement data player leakage // DivineMC - Use fastutil for criterion data + + public PlayerAdvancements(DataFixer dataFixer, PlayerList playerList, ServerAdvancementManager manager, Path playerSavePath, ServerPlayer player) { + this.playerList = playerList; diff --git a/divinemc-server/paper-patches/features/0020-Rewrite-ReferenceList.patch b/divinemc-server/paper-patches/features/0020-Rewrite-ReferenceList.patch new file mode 100644 index 0000000..1135f2e --- /dev/null +++ b/divinemc-server/paper-patches/features/0020-Rewrite-ReferenceList.patch @@ -0,0 +1,167 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 9 Jul 2025 03:37:51 +0300 +Subject: [PATCH] Rewrite ReferenceList + + +diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java +index 2e876b918672e8ef3b5197b7e6b1597247fdeaa1..94232d9ab2b1b064c032d9710734f6fbcdb52e10 100644 +--- a/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java ++++ b/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java +@@ -1,142 +1,26 @@ + package ca.spottedleaf.moonrise.common.list; + +-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +-import java.util.Arrays; +-import java.util.Iterator; +-import java.util.NoSuchElementException; ++// DivineMC start - Rewrite ReferenceList ++import it.unimi.dsi.fastutil.objects.ReferenceArrayList; ++import it.unimi.dsi.fastutil.objects.ReferenceLists; + +-public final class ReferenceList implements Iterable { +- +- private static final Object[] EMPTY_LIST = new Object[0]; +- +- private final Reference2IntOpenHashMap referenceToIndex; +- private E[] references; +- private int count; +- +- public ReferenceList() { +- this((E[])EMPTY_LIST); +- } +- +- public ReferenceList(final E[] referenceArray) { +- this.references = referenceArray; +- this.referenceToIndex = new Reference2IntOpenHashMap<>(2, 0.8f); +- this.referenceToIndex.defaultReturnValue(Integer.MIN_VALUE); +- } +- +- private ReferenceList(final E[] references, final int count, final Reference2IntOpenHashMap referenceToIndex) { +- this.references = references; +- this.count = count; +- this.referenceToIndex = referenceToIndex; +- } +- +- public ReferenceList copy() { +- return new ReferenceList<>(this.references.clone(), this.count, this.referenceToIndex.clone()); +- } +- +- public int size() { +- return this.count; +- } +- +- public boolean contains(final E obj) { +- return this.referenceToIndex.containsKey(obj); ++public class ReferenceList extends ReferenceLists.SynchronizedList { ++ public ReferenceList(E[] elements) { ++ super(new RefListInner<>(elements)); + } + +- public boolean remove(final E obj) { +- final int index = this.referenceToIndex.removeInt(obj); +- if (index == Integer.MIN_VALUE) { +- return false; +- } +- +- // move the object at the end to this index +- final int endIndex = --this.count; +- final E end = (E)this.references[endIndex]; +- if (index != endIndex) { +- // not empty after this call +- this.referenceToIndex.put(end, index); // update index +- } +- this.references[index] = end; +- this.references[endIndex] = null; +- +- return true; ++ public synchronized E[] getRawDataUnchecked() { ++ return ((RefListInner) this.list).getRawDataUnchecked(); + } + +- public boolean add(final E obj) { +- final int count = this.count; +- final int currIndex = this.referenceToIndex.putIfAbsent(obj, count); +- +- if (currIndex != Integer.MIN_VALUE) { +- return false; // already in this list ++ public static class RefListInner extends ReferenceArrayList { ++ public RefListInner(A[] elements) { ++ super(elements, true); + } + +- E[] list = this.references; +- +- if (list.length == count) { +- // resize required +- list = this.references = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative ++ public A[] getRawDataUnchecked() { ++ return this.a; + } +- +- list[count] = obj; +- this.count = count + 1; +- +- return true; +- } +- +- public E getChecked(final int index) { +- if (index < 0 || index >= this.count) { +- throw new IndexOutOfBoundsException("Index: " + index + " is out of bounds, size: " + this.count); +- } +- return this.references[index]; +- } +- +- public E getUnchecked(final int index) { +- return this.references[index]; +- } +- +- public Object[] getRawData() { +- return this.references; +- } +- +- public E[] getRawDataUnchecked() { +- return this.references; +- } +- +- public void clear() { +- this.referenceToIndex.clear(); +- Arrays.fill(this.references, 0, this.count, null); +- this.count = 0; +- } +- +- @Override +- public Iterator iterator() { +- return new Iterator<>() { +- private E lastRet; +- private int current; +- +- @Override +- public boolean hasNext() { +- return this.current < ReferenceList.this.count; +- } +- +- @Override +- public E next() { +- if (this.current >= ReferenceList.this.count) { +- throw new NoSuchElementException(); +- } +- return this.lastRet = ReferenceList.this.references[this.current++]; +- } +- +- @Override +- public void remove() { +- final E lastRet = this.lastRet; +- +- if (lastRet == null) { +- throw new IllegalStateException(); +- } +- this.lastRet = null; +- +- ReferenceList.this.remove(lastRet); +- --this.current; +- } +- }; + } + } ++// DivineMC end - Rewrite ReferenceList diff --git a/patches/work/server/sources/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java.patch b/patches/work/server/sources/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java.patch deleted file mode 100644 index 2ee5bd7..0000000 --- a/patches/work/server/sources/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -+++ b/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -@@ -19,7 +_,7 @@ - - @Override - public final void addPlayerListener(PlayerAdvancements playerAdvancements, CriterionTrigger.Listener listener) { -- playerAdvancements.criterionData.computeIfAbsent(this, managerx -> Sets.newHashSet()).add(listener); // Paper - fix PlayerAdvancements leak -+ playerAdvancements.criterionData.computeIfAbsent(this, managerx -> Sets.newConcurrentHashSet()).add(listener); // Paper - fix PlayerAdvancements leak // DivineMC - use concurrent set - } - - @Override From c730ddc5c1a20d4e310bd0471e82cf6bd48eb67f Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 9 Jul 2025 03:46:59 +0300 Subject: [PATCH 13/67] cleanup --- divinemc-server/build.gradle.kts.patch | 5 +- .../bxteam/divinemc/config/DivineConfig.java | 69 ------------------- 2 files changed, 1 insertion(+), 73 deletions(-) diff --git a/divinemc-server/build.gradle.kts.patch b/divinemc-server/build.gradle.kts.patch index 1d48aea..b526f81 100644 --- a/divinemc-server/build.gradle.kts.patch +++ b/divinemc-server/build.gradle.kts.patch @@ -72,7 +72,7 @@ } } val log4jPlugins = sourceSets.create("log4jPlugins") { -@@ -156,10 +_,23 @@ +@@ -156,10 +_,20 @@ } dependencies { @@ -84,9 +84,6 @@ + implementation ("me.carleslc.Simple-YAML:Simple-Yaml:1.8.4") { + exclude(group="org.yaml", module="snakeyaml") + } -+ implementation("net.objecthunter:exp4j:0.4.8") -+ implementation("org.agrona:agrona:2.0.1") -+ implementation("net.openhft:zero-allocation-hashing:0.16") + implementation("com.github.luben:zstd-jni:1.5.6-9") + implementation("org.lz4:lz4-java:1.8.0") + // DivineMC end - Dependencies diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index ed4da85..1d82b0c 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -10,12 +10,10 @@ import org.apache.logging.log4j.Logger; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy; -import org.bxteam.divinemc.region.LinearImplementation; import org.jetbrains.annotations.Nullable; import org.simpleyaml.configuration.comments.CommentType; import org.simpleyaml.configuration.file.YamlFile; import org.simpleyaml.exceptions.InvalidConfigurationException; -import org.bxteam.divinemc.region.RegionFileFormat; import java.io.File; import java.io.IOException; @@ -343,11 +341,6 @@ public class DivineConfig { public static boolean enableStructureLayoutOptimizer = true; public static boolean deduplicateShuffledTemplatePoolElementList = false; - // TNT optimization - public static boolean enableFasterTntOptimization = true; - public static boolean explosionNoBlockDamage = false; - public static double tntRandomRange = -1; - // General optimizations public static boolean skipUselessSecondaryPoiSensor = true; public static boolean clumpOrbs = true; @@ -382,7 +375,6 @@ public class DivineConfig { public static void load() { chunkSettings(); - tntOptimization(); optimizationSettings(); dab(); virtualThreads(); @@ -433,12 +425,6 @@ public class DivineConfig { "modpacks where many structure mods are using very high weight values in their template pools."); } - private static void tntOptimization() { - enableFasterTntOptimization = getBoolean(ConfigCategory.PERFORMANCE.key("tnt-optimization.enable-faster-tnt-optimization"), enableFasterTntOptimization); - explosionNoBlockDamage = getBoolean(ConfigCategory.PERFORMANCE.key("tnt-optimization.explosion-no-block-damage"), explosionNoBlockDamage); - tntRandomRange = getDouble(ConfigCategory.PERFORMANCE.key("tnt-optimization.tnt-random-range"), tntRandomRange); - } - private static void optimizationSettings() { skipUselessSecondaryPoiSensor = getBoolean(ConfigCategory.PERFORMANCE.key("optimizations.skip-useless-secondary-poi-sensor"), skipUselessSecondaryPoiSensor); clumpOrbs = getBoolean(ConfigCategory.PERFORMANCE.key("optimizations.clump-orbs"), clumpOrbs, @@ -581,14 +567,6 @@ public class DivineConfig { public static boolean timeAcceleration = true; public static boolean randomTickSpeedAcceleration = true; - // Region format - public static RegionFileFormat regionFormatTypeName = RegionFileFormat.ANVIL; - public static LinearImplementation linearImplementation = LinearImplementation.V2; - public static int linearFlushMaxThreads = 4; - public static int linearFlushDelay = 100; - public static boolean linearUseVirtualThread = false; - public static int linearCompressionLevel = 1; - // Sentry public static String sentryDsn = ""; public static String logLevel = "WARN"; @@ -597,7 +575,6 @@ public class DivineConfig { public static void load() { secureSeed(); lagCompensation(); - linearRegionFormat(); sentrySettings(); } @@ -623,49 +600,6 @@ public class DivineConfig { randomTickSpeedAcceleration = getBoolean(ConfigCategory.MISC.key("lag-compensation.random-tick-speed-acceleration"), randomTickSpeedAcceleration); } - private static void linearRegionFormat() { - regionFormatTypeName = RegionFileFormat.fromName(getString(ConfigCategory.MISC.key("region-format.type"), regionFormatTypeName.name(), - "The type of region file format to use for storing chunk data.", - "Valid values:", - " - LINEAR: Linear region file format", - " - ANVIL: Anvil region file format (default)")); - linearImplementation = LinearImplementation.valueOf(getString(ConfigCategory.MISC.key("region-format.implementation"), linearImplementation.name(), - "The implementation of the linear region file format to use.", - "Valid values:", - " - V1: Basic and default linear implementation", - " - V2: Introduces a grid-based compression scheme for better data management and flexibility (default)")); - - linearFlushMaxThreads = getInt(ConfigCategory.MISC.key("region-format.flush-max-threads"), linearFlushMaxThreads, - "The maximum number of threads to use for flushing linear region files.", - "If this value is less than or equal to 0, it will be set to the number of available processors + this value."); - linearFlushDelay = getInt(ConfigCategory.MISC.key("region-format.flush-delay"), linearFlushDelay, - "The delay in milliseconds to wait before flushing next files."); - linearUseVirtualThread = getBoolean(ConfigCategory.MISC.key("region-format.use-virtual-thread"), linearUseVirtualThread, - "Whether to use virtual threads for flushing."); - linearCompressionLevel = getInt(ConfigCategory.MISC.key("region-format.compression-level"), linearCompressionLevel, - "The compression level to use for the linear region file format."); - - setComment(ConfigCategory.MISC.key("region-format"), - "The linear region file format is a custom region file format that is designed to be more efficient than the ANVIL format.", - "It uses uses ZSTD compression instead of ZLIB. This format saves about 50% of disk space.", - "Read more information about linear region format at https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools", - "WARNING: If you are want to use this format, make sure to create backup of your world before switching to it, there is potential risk to lose chunk data."); - - if (regionFormatTypeName == RegionFileFormat.UNKNOWN) { - LOGGER.error("Unknown region file type: {}, falling back to ANVIL format.", regionFormatTypeName); - regionFormatTypeName = RegionFileFormat.ANVIL; - } - - if (linearFlushMaxThreads <= 0) { - linearFlushMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + linearFlushMaxThreads, 1); - } - - if (linearCompressionLevel > 22 || linearCompressionLevel < 1) { - LOGGER.warn("Invalid linear compression level: {}, resetting to default (1)", linearCompressionLevel); - linearCompressionLevel = 1; - } - } - private static void sentrySettings() { sentryDsn = getString(ConfigCategory.MISC.key("sentry.dsn"), sentryDsn, "The DSN for Sentry, a service that provides real-time crash reporting that helps you monitor and fix crashes in real time. Leave blank to disable. Obtain link at https://sentry.io"); @@ -681,7 +615,6 @@ public class DivineConfig { public static class NetworkCategory { // General network settings public static boolean disableDisconnectSpam = false; - public static boolean gracefulTeleportHandling = false; public static boolean dontRespondPingBeforeStart = true; public static boolean playerProfileResultCachingEnabled = true; public static int playerProfileResultCachingTimeout = 1440; @@ -702,8 +635,6 @@ public class DivineConfig { private static void networkSettings() { disableDisconnectSpam = getBoolean(ConfigCategory.NETWORK.key("general.disable-disconnect-spam"), disableDisconnectSpam, "Prevents players being disconnected by 'disconnect.spam' when sending too many chat packets"); - gracefulTeleportHandling = getBoolean(ConfigCategory.NETWORK.key("general.graceful-teleport-handling"), gracefulTeleportHandling, - "Disables being disconnected from 'multiplayer.disconnect.invalid_player_movement' (also declines the packet handling)."); dontRespondPingBeforeStart = getBoolean(ConfigCategory.NETWORK.key("general.dont-respond-ping-before-start"), dontRespondPingBeforeStart, "Prevents the server from responding to pings before the server is fully booted."); From cdfb9e3e514bad1952a6022f20f29d4ce207fc49 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 9 Jul 2025 04:07:04 +0300 Subject: [PATCH 14/67] add VT support to RCT, fix player cache --- .../0069-Player-ProfileResult-caching.patch | 4 ++-- .../0081-Regionized-Chunk-Ticking.patch | 24 +++++++++++-------- .../bxteam/divinemc/config/DivineConfig.java | 3 +++ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0069-Player-ProfileResult-caching.patch b/divinemc-server/minecraft-patches/features/0069-Player-ProfileResult-caching.patch index 841c59d..d172351 100644 --- a/divinemc-server/minecraft-patches/features/0069-Player-ProfileResult-caching.patch +++ b/divinemc-server/minecraft-patches/features/0069-Player-ProfileResult-caching.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Player ProfileResult caching diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 10aecbb88a9a3dae3ecdf28aa449f1a1475a1905..13b468d4d3b92bf71fdfa112dfe56464c4f9dbed 100644 +index 10aecbb88a9a3dae3ecdf28aa449f1a1475a1905..9285697a1da3f216e03b8ea824f07f7f7c716c53 100644 --- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -75,6 +75,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, @@ -14,7 +14,7 @@ index 10aecbb88a9a3dae3ecdf28aa449f1a1475a1905..13b468d4d3b92bf71fdfa112dfe56464 private volatile boolean disconnecting = false; // Paper - Fix disconnect still ticking login + // DivineMC start - Player ProfileResult caching + private static final com.google.common.cache.Cache playerProfileResultCache = com.google.common.cache.CacheBuilder.newBuilder() -+ .expireAfterWrite(1, java.util.concurrent.TimeUnit.MINUTES) ++ .expireAfterWrite(org.bxteam.divinemc.config.DivineConfig.NetworkCategory.playerProfileResultCachingTimeout, java.util.concurrent.TimeUnit.MINUTES) + .build(); + // DivineMC end - Player ProfileResult caching diff --git a/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch b/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch index e3b20d7..987f1e0 100644 --- a/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch +++ b/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch @@ -7,8 +7,6 @@ This patch adds regionized chunk ticking feature, by grouping adjacent chunks in Original idea by Dueris, modified by NONPLAYT and heavily optimized by dan28000 -TODO: switchable VT - diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java index e72eda830644851656fae3118c513d7bd701be45..4ab30d291de7db5ad7d5684662f41348270802b9 100644 --- a/net/minecraft/network/Connection.java @@ -23,18 +21,24 @@ index e72eda830644851656fae3118c513d7bd701be45..4ab30d291de7db5ad7d5684662f41348 if (var2 instanceof ClosedChannelException) { LOGGER.info("Connection closed during protocol change"); diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afad669ae9f 100644 +index 4fe0f6ba751666e436053536f7607fb50c8471f6..b61580cd7216bd35f5bfade2aaf922b646dd61d8 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -57,6 +57,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -57,6 +57,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon private static final Logger LOGGER = LogUtils.getLogger(); private final DistanceManager distanceManager; private final ServerLevel level; -+ public static final Executor REGION_EXECUTOR = java.util.concurrent.Executors.newFixedThreadPool(org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadCount, new org.bxteam.divinemc.util.NamedAgnosticThreadFactory<>("Region Ticking", ca.spottedleaf.moonrise.common.util.TickThread::new, org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadPriority)); // DivineMC - Regionized Chunk Ticking ++ // DivineMC start - Regionized Chunk Ticking ++ public static final Executor REGION_EXECUTOR = org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingUseVirtualThreads ++ ? java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor() ++ : java.util.concurrent.Executors.newFixedThreadPool(org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadCount, ++ new org.bxteam.divinemc.util.NamedAgnosticThreadFactory<>("Region Ticking", ca.spottedleaf.moonrise.common.util.TickThread::new, ++ org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadPriority)); ++ // DivineMC end - Regionized Chunk Ticking public final Thread mainThread; final ThreadedLevelLightEngine lightEngine; public final ServerChunkCache.MainThreadExecutor mainThreadProcessor; -@@ -70,8 +71,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -70,8 +77,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon private final long[] lastChunkPos = new long[4]; private final ChunkStatus[] lastChunkStatus = new ChunkStatus[4]; private final ChunkAccess[] lastChunk = new ChunkAccess[4]; @@ -47,7 +51,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afa @Nullable @VisibleForDebug private NaturalSpawner.SpawnState lastSpawnState; -@@ -153,31 +156,246 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -153,31 +162,246 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon return load ? this.syncLoad(chunkX, chunkZ, toStatus) : null; } // Paper end - rewrite chunk system @@ -303,7 +307,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afa } // Paper end - chunk tick iteration optimisations -@@ -502,14 +720,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -502,14 +726,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon long gameTime = this.level.getGameTime(); long l = gameTime - this.lastInhabitedUpdate; this.lastInhabitedUpdate = gameTime; @@ -329,7 +333,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afa // DivineMC start - Async mob spawning if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) { for (ServerPlayer player : this.level.players) { -@@ -553,14 +778,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -553,14 +784,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } private void broadcastChangedChunks() { @@ -354,7 +358,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afa } private void tickChunks(long timeInhabited) { -@@ -610,23 +839,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -610,23 +845,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon filteredSpawningCategories = List.of(); } diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 1d82b0c..14ac0ee 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -198,6 +198,7 @@ public class DivineConfig { // Regionized chunk ticking public static boolean enableRegionizedChunkTicking = false; public static int regionizedChunkTickingExecutorThreadCount = 4; + public static boolean regionizedChunkTickingUseVirtualThreads = false; public static int regionizedChunkTickingExecutorThreadPriority = Thread.NORM_PRIORITY + 2; // Async pathfinding settings @@ -252,6 +253,8 @@ public class DivineConfig { regionizedChunkTickingExecutorThreadCount = getInt(ConfigCategory.ASYNC.key("regionized-chunk-ticking.executor-thread-count"), regionizedChunkTickingExecutorThreadCount, "The amount of threads to allocate to regionized chunk ticking."); + regionizedChunkTickingUseVirtualThreads = getBoolean(ConfigCategory.ASYNC.key("regionized-chunk-ticking.use-virtual-threads"), regionizedChunkTickingUseVirtualThreads, + "If enabled, regionized chunk ticking will use virtual threads for the executor that was introduced in Java 21."); regionizedChunkTickingExecutorThreadPriority = getInt(ConfigCategory.ASYNC.key("regionized-chunk-ticking.executor-thread-priority"), regionizedChunkTickingExecutorThreadPriority, "Configures the thread priority of the executor"); From 8b280d389c8771a57f46776657f0155991e9fd74 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 9 Jul 2025 04:27:17 +0300 Subject: [PATCH 15/67] cleanup access transformers --- build-data/divinemc.at | 48 +------------------ ...7-lithium-faster-chunk-serialization.patch | 4 +- .../0031-C2ME-optimize-noise-generation.patch | 8 ++-- .../features/0042-Optimize-entity-brain.patch | 21 ++++---- ...-BlockEntity-ticking-isRemoved-check.patch | 8 ++-- ...-SparklyPaper-Parallel-world-ticking.patch | 26 ++++++++++ 6 files changed, 48 insertions(+), 67 deletions(-) diff --git a/build-data/divinemc.at b/build-data/divinemc.at index 3384a7b..af17be0 100644 --- a/build-data/divinemc.at +++ b/build-data/divinemc.at @@ -6,39 +6,13 @@ private-f net.minecraft.world.level.levelgen.NoiseChunk$FlatCache noiseFiller private-f net.minecraft.world.level.levelgen.NoiseChunk$NoiseInterpolator noiseFiller private-f net.minecraft.world.level.levelgen.RandomState router private-f net.minecraft.world.level.levelgen.RandomState sampler -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.executor.RadiusAwarePrioritisedExecutor$Task -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.executor.RadiusAwarePrioritisedExecutor$Task chunkX -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.executor.RadiusAwarePrioritisedExecutor$Task chunkZ -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgressionTask chunkX -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgressionTask chunkZ -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgressionTask world -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask chunkX -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask chunkZ -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask world -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask$ProcessOffMainTask -public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask$ProcessOnMainTask public net.minecraft.util.Mth SIN public net.minecraft.world.entity.ai.Brain sensors public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities lineOfSightTest public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities nearbyEntities public net.minecraft.world.entity.ai.sensing.Sensor scanRate public net.minecraft.world.entity.ai.sensing.Sensor timeToTick -public net.minecraft.world.level.ServerExplosion damageSource -public net.minecraft.world.level.ServerExplosion source -public net.minecraft.world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapper -public net.minecraft.world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapper rebind(Lnet/minecraft/world/level/block/entity/TickingBlockEntity;)V -public net.minecraft.world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapper ticker -public net.minecraft.world.level.chunk.LevelChunkSection nonEmptyBlockCount -public net.minecraft.world.level.chunk.LevelChunkSection tickingBlockCount -public net.minecraft.world.level.chunk.LevelChunkSection tickingFluidCount -public net.minecraft.world.level.chunk.PalettedContainer palette -public net.minecraft.world.level.chunk.PalettedContainer strategy -public net.minecraft.world.level.chunk.PalettedContainer$Data palette -public net.minecraft.world.level.chunk.storage.RegionFile getOversizedData(II)Lnet/minecraft/nbt/CompoundTag; -public net.minecraft.world.level.chunk.storage.RegionFile isOversized(II)Z -public net.minecraft.world.level.chunk.storage.RegionFile recalculateHeader()Z -public net.minecraft.world.level.chunk.storage.RegionFile setOversized(IIZ)V -public net.minecraft.world.level.chunk.storage.RegionFile write(Lnet/minecraft/world/level/ChunkPos;Ljava/nio/ByteBuffer;)V +public net.minecraft.world.level.chunk.PaletteResize public net.minecraft.world.level.entity.EntityTickList entities public net.minecraft.world.level.levelgen.DensityFunctions$BlendAlpha public net.minecraft.world.level.levelgen.DensityFunctions$BlendDensity @@ -62,26 +36,6 @@ public net.minecraft.world.level.levelgen.NoiseChunk$BlendOffset public net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity public net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity getSpaghettiRarity3D(D)D public net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity getSphaghettiRarity2D(D)D -public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedHi -public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedLo -public net.minecraft.world.level.levelgen.XoroshiroRandomSource randomNumberGenerator public net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool rawTemplates -public net.minecraft.world.level.levelgen.structure.structures.WoodlandMansionPieces$SimpleGrid -public net.minecraft.world.level.levelgen.synth.BlendedNoise mainNoise -public net.minecraft.world.level.levelgen.synth.BlendedNoise maxLimitNoise -public net.minecraft.world.level.levelgen.synth.BlendedNoise minLimitNoise -public net.minecraft.world.level.levelgen.synth.BlendedNoise smearScaleMultiplier -public net.minecraft.world.level.levelgen.synth.BlendedNoise xzFactor -public net.minecraft.world.level.levelgen.synth.BlendedNoise xzMultiplier -public net.minecraft.world.level.levelgen.synth.BlendedNoise xzScale -public net.minecraft.world.level.levelgen.synth.BlendedNoise yFactor -public net.minecraft.world.level.levelgen.synth.BlendedNoise yMultiplier -public net.minecraft.world.level.levelgen.synth.BlendedNoise yScale -public net.minecraft.world.level.levelgen.synth.ImprovedNoise p -public net.minecraft.world.level.levelgen.synth.PerlinNoise amplitudes -public net.minecraft.world.level.levelgen.synth.PerlinNoise lowestFreqInputFactor -public net.minecraft.world.level.levelgen.synth.PerlinNoise lowestFreqValueFactor -public net.minecraft.world.level.levelgen.synth.PerlinNoise noiseLevels -public net.minecraft.world.level.levelgen.synth.SimplexNoise p public net.minecraft.world.level.pathfinder.SwimNodeEvaluator allowBreaching public-f ca.spottedleaf.moonrise.paper.PaperHooks diff --git a/divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch b/divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch index 5c05869..31012a8 100644 --- a/divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch +++ b/divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch @@ -84,11 +84,11 @@ index 09fd99c9cbd23b5f3c899bfb00c9b89651948ed8..6e264b311894f510112beb996190f5ff + @Override public void compact(net.minecraft.world.level.chunk.Palette srcPalette, net.minecraft.world.level.chunk.Palette dstPalette, short[] out) { } // DivineMC - lithium: faster chunk serialization } diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java -index baa006132b1fa3d73fd4a14f6bc747a3957d1a0c..be11a87ab1badca64219d74bc7a4f5d51b818a8c 100644 +index a251ba67644cd02a0b00d7c8b0e2c64aa5e26291..9d892c1c3890e0aaf13fd5cd7b7d138afeaad260 100644 --- a/net/minecraft/world/level/chunk/PalettedContainer.java +++ b/net/minecraft/world/level/chunk/PalettedContainer.java @@ -32,6 +32,23 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - public final PalettedContainer.Strategy strategy; + private final PalettedContainer.Strategy strategy; //private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused + // DivineMC start - lithium: faster chunk serialization diff --git a/divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch b/divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch index dd47d8c..771f7f7 100644 --- a/divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch +++ b/divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch @@ -11,7 +11,7 @@ As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric) Licensed under: MIT (https://opensource.org/licenses/MIT) diff --git a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java -index 46e98a99442523614284150964ba528d0c91493f..55ae29a5e846bb2a6d6991ce071aefe6a8113ebb 100644 +index fb11a2eea540d55e50eab59f9857ca5d99f556f8..c40f65c30b6422a27154295a2b3a63483496dcca 100644 --- a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java +++ b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java @@ -11,6 +11,27 @@ public final class ImprovedNoise { @@ -180,12 +180,12 @@ index 46e98a99442523614284150964ba528d0c91493f..55ae29a5e846bb2a6d6991ce071aefe6 private double sampleWithDerivative(int gridX, int gridY, int gridZ, double deltaX, double deltaY, double deltaZ, double[] noiseValues) { diff --git a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java -index ffac5b7b1eb1364ab8442d7145a7b4ebde68ee10..667d464e61aea2aa7f7b7f1ed082daadc17f723b 100644 +index da3c26fbad32d75d71f7e59c8c3341316a754756..23e12c26e6035b429c89b98a796a048557e8c9b2 100644 --- a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java +++ b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java @@ -26,6 +26,10 @@ public class PerlinNoise { - public final double lowestFreqValueFactor; - public final double lowestFreqInputFactor; + private final double lowestFreqValueFactor; + private final double lowestFreqInputFactor; private final double maxValue; + // DivineMC start - C2ME: optimize noise generation + private final int octaveSamplersCount; diff --git a/divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch b/divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch index cd63311..44089cc 100644 --- a/divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch +++ b/divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch @@ -26,16 +26,17 @@ index 04875840085541ebfc7014868beec49bb7ab9976..bbfb1de1a03c4208406feb803a2f378d super.onSyncedDataUpdated(key); diff --git a/net/minecraft/world/entity/ai/Brain.java b/net/minecraft/world/entity/ai/Brain.java -index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e985deecd05 100644 +index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d5068096603b03980 100644 --- a/net/minecraft/world/entity/ai/Brain.java +++ b/net/minecraft/world/entity/ai/Brain.java -@@ -45,16 +45,73 @@ public class Brain { +@@ -45,16 +45,74 @@ public class Brain { static final Logger LOGGER = LogUtils.getLogger(); private final Supplier>> codec; private static final int SCHEDULE_UPDATE_DELAY = 20; - private final Map, Optional>> memories = Maps.newHashMap(); - public final Map>, Sensor> sensors = Maps.newLinkedHashMap(); - private final Map>>> availableBehaviorsByPriority = Maps.newTreeMap(); ++ + private Map, Optional>> memories = Maps.newConcurrentMap(); // DivineMC - concurrent map + public Map>, Sensor> sensors = Maps.newLinkedHashMap(); // DivineMC - linked hash map + private final Map>>> availableBehaviorsByPriority = Maps.newTreeMap(); // DivineMC - tree map @@ -107,7 +108,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e98 public static Brain.Provider provider( Collection> memoryTypes, Collection>> sensorTypes -@@ -146,6 +203,12 @@ public class Brain { +@@ -146,6 +204,12 @@ public class Brain { for (Brain.MemoryValue memoryValue : memoryValues) { memoryValue.setMemoryInternal(this); } @@ -120,7 +121,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e98 } public DataResult serializeStart(DynamicOps ops) { -@@ -165,6 +228,7 @@ public class Brain { +@@ -165,6 +229,7 @@ public class Brain { } public void eraseMemory(MemoryModuleType type) { @@ -128,7 +129,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e98 this.setMemory(type, Optional.empty()); } -@@ -180,16 +244,33 @@ public class Brain { +@@ -180,16 +245,33 @@ public class Brain { this.setMemoryInternal(memoryType, memory.map(ExpirableValue::of)); } @@ -167,7 +168,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e98 public Optional getMemory(MemoryModuleType type) { Optional> optional = this.memories.get(type); if (optional == null) { -@@ -251,19 +332,7 @@ public class Brain { +@@ -251,19 +333,7 @@ public class Brain { @Deprecated @VisibleForDebug public List> getRunningBehaviors() { @@ -188,7 +189,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e98 } public void useDefaultActivity() { -@@ -294,6 +363,7 @@ public class Brain { +@@ -294,6 +364,7 @@ public class Brain { this.activeActivities.clear(); this.activeActivities.addAll(this.coreActivities); this.activeActivities.add(activity); @@ -196,7 +197,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e98 } } -@@ -383,11 +453,13 @@ public class Brain { +@@ -383,11 +454,13 @@ public class Brain { .computeIfAbsent(activity, activity1 -> Sets.newLinkedHashSet()) .add((BehaviorControl)pair.getSecond()); } @@ -210,7 +211,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e98 } public boolean isActive(Activity activity) { -@@ -404,6 +476,7 @@ public class Brain { +@@ -404,6 +477,7 @@ public class Brain { } } @@ -218,7 +219,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..78bd18006fc2b9b59f044de9767e4e98 return brain; } -@@ -438,31 +511,38 @@ public class Brain { +@@ -438,31 +512,38 @@ public class Brain { for (BehaviorControl behaviorControl : this.getRunningBehaviors()) { behaviorControl.doStop(level, owner, gameTime); diff --git a/divinemc-server/minecraft-patches/features/0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch b/divinemc-server/minecraft-patches/features/0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch index 236f9a5..46be04b 100644 --- a/divinemc-server/minecraft-patches/features/0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch +++ b/divinemc-server/minecraft-patches/features/0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch @@ -8,13 +8,13 @@ Original project: https://github.com/Winds-Studio/Leaf This should help for massive hopper chains or hopper matrix. diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index 6d9274f0da9507d0152611d6b7785e0524dedb2d..a2b21970841a0f7f2b4b469c7b8737440041ebaa 100644 +index dbb4142ea38cdf484e74c81103cebb024ae8813d..32f17328b7980a9dc382c90af76cca04b74c639a 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -982,13 +982,26 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - public static class RebindableTickingBlockEntityWrapper implements TickingBlockEntity { - public TickingBlockEntity ticker; + static class RebindableTickingBlockEntityWrapper implements TickingBlockEntity { + private TickingBlockEntity ticker; + private @Nullable BlockEntity blockEntityReference = null; // DivineMC - Improve BlockEntity ticking isRemoved check RebindableTickingBlockEntityWrapper(TickingBlockEntity ticker) { @@ -26,7 +26,7 @@ index 6d9274f0da9507d0152611d6b7785e0524dedb2d..a2b21970841a0f7f2b4b469c7b873744 + // DivineMC end - Improve BlockEntity ticking isRemoved check } - public void rebind(TickingBlockEntity ticker) { + void rebind(TickingBlockEntity ticker) { this.ticker = ticker; + // DivineMC start - Improve BlockEntity ticking isRemoved check + if (ticker instanceof BoundTickingBlockEntity boundTicker) { diff --git a/divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch index fc2f0c4..2ccad76 100644 --- a/divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch +++ b/divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch @@ -626,3 +626,29 @@ index e4e2e42d0ca25df7fe9f2dd4275610e45fcb2c84..93bf7beab3b00973a19e51d48a9dfb26 final Thread thread = Thread.currentThread(); // Paper start - name threads according to running plugin final String nameBefore = thread.getName(); +diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java +index dffff76bf6df39dd26892edc2b4988fafab282e7..26659624c5fcad5f4e05fd9174dab89118ab7be7 100644 +--- a/src/main/java/org/spigotmc/WatchdogThread.java ++++ b/src/main/java/org/spigotmc/WatchdogThread.java +@@ -112,6 +112,21 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre + WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.threadId(), Integer.MAX_VALUE), logger); + logger.log(Level.SEVERE, "------------------------------"); + ++ // DivineMC start - Dump Parallel World Ticking thread ++ logger.log(Level.SEVERE, "Parallel world ticking thread dump"); ++ for (Thread thread : org.apache.commons.lang3.ThreadUtils.getAllThreads()) { ++ if (MinecraftServer.getServer().serverThread == thread || thread instanceof WatchdogThread) { ++ continue; ++ } ++ if (thread instanceof ca.spottedleaf.moonrise.common.util.TickThread tickThread) { ++ if (tickThread instanceof ServerLevelTickThread tickThread1) { ++ WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(tickThread1.threadId(), Integer.MAX_VALUE), logger); ++ } ++ } ++ } ++ logger.log(Level.SEVERE, "------------------------------"); ++ // DivineMC end - Dump Parallel World Ticking thread ++ + // Paper start - Only print full dump on long timeouts + if (isLongTimeout) { + logger.log(Level.SEVERE, "Entire Thread Dump:"); From 4b57eed3fbb90cca5402b5159973a65c17ab4af0 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 9 Jul 2025 04:42:13 +0300 Subject: [PATCH 16/67] add chunks settings back --- .../features/0083-C2ME-Limit-NBT-cache.patch | 54 +++++++++++++++++++ ...igurable-player-spawn-tracking-range.patch | 19 +++++++ .../0021-Configurable-Max-View-Distance.patch | 19 +++++++ 3 files changed, 92 insertions(+) create mode 100644 divinemc-server/minecraft-patches/features/0083-C2ME-Limit-NBT-cache.patch create mode 100644 divinemc-server/minecraft-patches/features/0084-Configurable-player-spawn-tracking-range.patch create mode 100644 divinemc-server/paper-patches/features/0021-Configurable-Max-View-Distance.patch diff --git a/divinemc-server/minecraft-patches/features/0083-C2ME-Limit-NBT-cache.patch b/divinemc-server/minecraft-patches/features/0083-C2ME-Limit-NBT-cache.patch new file mode 100644 index 0000000..c8de5e9 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0083-C2ME-Limit-NBT-cache.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 9 Jul 2025 04:37:59 +0300 +Subject: [PATCH] C2ME: Limit NBT cache + +This patch is based on the following mixins: +* "com/ishland/c2me/opts/chunkio/mixin/limit_nbt_cache/MixinStorageIoWorker.java" +By: ishland +As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric) +Licensed under: MIT (https://opensource.org/licenses/MIT) + +diff --git a/net/minecraft/world/level/chunk/storage/IOWorker.java b/net/minecraft/world/level/chunk/storage/IOWorker.java +index 27e1edbd8d8ffd80c1a3df17bc47f4a6936619f7..c3326e753ecf8a0ba1930d8c7573ebd2c594cf45 100644 +--- a/net/minecraft/world/level/chunk/storage/IOWorker.java ++++ b/net/minecraft/world/level/chunk/storage/IOWorker.java +@@ -212,7 +212,38 @@ public class IOWorker implements ChunkScanAccess, AutoCloseable { + }); + } + ++ // DivineMC start - C2ME: Limit NBT cache ++ private void checkHardLimit() { ++ if (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheLimit) { ++ LOGGER.warn("Chunk data cache size exceeded hard limit ({} >= {}), forcing writes to disk (you can increase chunkDataCacheLimit in divinemc.yml)", this.pendingWrites.size(), org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheLimit); ++ while (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit * 0.75) { ++ writeResult0(); ++ } ++ } ++ } ++ ++ private void writeResult0() { ++ java.util.Iterator> iterator = this.pendingWrites.entrySet().iterator(); ++ if (iterator.hasNext()) { ++ java.util.Map.Entry entry = iterator.next(); ++ iterator.remove(); ++ this.runStore(entry.getKey(), entry.getValue()); ++ } ++ } ++ // DivineMC end - C2ME: Limit NBT cache ++ + private void storePendingChunk() { ++ // DivineMC start - C2ME: Limit NBT cache ++ if (!this.pendingWrites.isEmpty()) { ++ checkHardLimit(); ++ if (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit) { ++ int writeFrequency = Math.min(1, (this.pendingWrites.size() - (int) org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit) / 16); ++ for (int i = 0; i < writeFrequency; i++) { ++ writeResult0(); ++ } ++ } ++ } ++ // DivineMC end - C2ME: Limit NBT cache + Entry entry = this.pendingWrites.pollFirstEntry(); + if (entry != null) { + this.runStore(entry.getKey(), entry.getValue()); diff --git a/divinemc-server/minecraft-patches/features/0084-Configurable-player-spawn-tracking-range.patch b/divinemc-server/minecraft-patches/features/0084-Configurable-player-spawn-tracking-range.patch new file mode 100644 index 0000000..aa79ad8 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0084-Configurable-player-spawn-tracking-range.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 9 Jul 2025 04:40:45 +0300 +Subject: [PATCH] Configurable player spawn tracking range + + +diff --git a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java +index 6d1fe8028739145b11fce98ad62b2f8044299548..9f086ded18d1fc8850877c6be113d88074427526 100644 +--- a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java +@@ -2,7 +2,7 @@ package ca.spottedleaf.moonrise.patches.chunk_tick_iteration; + + public final class ChunkTickConstants { + +- public static final int PLAYER_SPAWN_TRACK_RANGE = 8; ++ public static final int PLAYER_SPAWN_TRACK_RANGE = (int) Math.round(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange / 16.0); // DivineMC - Configurable player spawn tracking range + // the smallest distance on x/z is at 45 degrees, we need to subtract 0.5 since this is calculated from chunk center and not chunk perimeter + // note: vanilla does not subtract 0.5 but the result is (luckily!) the same + public static final int NARROW_SPAWN_TRACK_RANGE = (int)Math.floor(((double)PLAYER_SPAWN_TRACK_RANGE / Math.sqrt(2.0)) - 0.5); diff --git a/divinemc-server/paper-patches/features/0021-Configurable-Max-View-Distance.patch b/divinemc-server/paper-patches/features/0021-Configurable-Max-View-Distance.patch new file mode 100644 index 0000000..fdc3795 --- /dev/null +++ b/divinemc-server/paper-patches/features/0021-Configurable-Max-View-Distance.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 9 Jul 2025 04:40:05 +0300 +Subject: [PATCH] Configurable Max View Distance + + +diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java +index 559c959aff3c9deef867b9e425fba3e2e669cac6..00aac7b5b610746f619b07502ceea5dd87e36ff7 100644 +--- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java ++++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java +@@ -4,7 +4,7 @@ import ca.spottedleaf.moonrise.common.PlatformHooks; + + public final class MoonriseConstants { + +- public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", 32); ++ public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.maxViewDistance); // DivineMC - Configurable Max View Distance + + private MoonriseConstants() {} + From 5d52cbcbcd21bb1c11a903b1597b5e9b35891697 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 9 Jul 2025 04:56:47 +0300 Subject: [PATCH 17/67] forgot some things --- .../features/0015-Virtual-Threads.patch | 59 +++++++++++++++++++ ...patch => 0016-Implement-Secure-Seed.patch} | 0 ...=> 0017-Petal-Multithreaded-Tracker.patch} | 0 ...18-Pufferfish-Optimize-mob-spawning.patch} | 0 ...r-ShapelessRecipes-comparison-for-V.patch} | 0 ...SparklyPaper-Parallel-world-ticking.patch} | 0 ...patch => 0021-Rewrite-ReferenceList.patch} | 0 ...0022-Configurable-Max-View-Distance.patch} | 0 .../bxteam/divinemc/config/DivineConfig.java | 4 -- 9 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 divinemc-server/paper-patches/features/0015-Virtual-Threads.patch rename divinemc-server/paper-patches/features/{0015-Implement-Secure-Seed.patch => 0016-Implement-Secure-Seed.patch} (100%) rename divinemc-server/paper-patches/features/{0016-Petal-Multithreaded-Tracker.patch => 0017-Petal-Multithreaded-Tracker.patch} (100%) rename divinemc-server/paper-patches/features/{0017-Pufferfish-Optimize-mob-spawning.patch => 0018-Pufferfish-Optimize-mob-spawning.patch} (100%) rename divinemc-server/paper-patches/features/{0018-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch => 0019-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch} (100%) rename divinemc-server/paper-patches/features/{0019-SparklyPaper-Parallel-world-ticking.patch => 0020-SparklyPaper-Parallel-world-ticking.patch} (100%) rename divinemc-server/paper-patches/features/{0020-Rewrite-ReferenceList.patch => 0021-Rewrite-ReferenceList.patch} (100%) rename divinemc-server/paper-patches/features/{0021-Configurable-Max-View-Distance.patch => 0022-Configurable-Max-View-Distance.patch} (100%) diff --git a/divinemc-server/paper-patches/features/0015-Virtual-Threads.patch b/divinemc-server/paper-patches/features/0015-Virtual-Threads.patch new file mode 100644 index 0000000..80f48f8 --- /dev/null +++ b/divinemc-server/paper-patches/features/0015-Virtual-Threads.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 24 Feb 2025 19:36:33 +0300 +Subject: [PATCH] Virtual Threads + + +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +index 8492a06883e2ff597bbbdaa74fe5e5cdd0a0a1b1..862e49f510720f3546c339f5c4cf1945303dd8c9 100644 +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -37,7 +37,7 @@ public final class MCUtil { + run.run(); + } + }; +- public static final ExecutorService ASYNC_EXECUTOR = Executors.newFixedThreadPool(2, new ThreadFactoryBuilder() ++ public static final ExecutorService ASYNC_EXECUTOR = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualAsyncExecutor ? Executors.newVirtualThreadPerTaskExecutor() : Executors.newFixedThreadPool(2, new ThreadFactoryBuilder() // DivineMC - Virtual Threads + .setNameFormat("Paper Async Task Handler Thread - %1$d") + .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) + .build() +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java +index 0ca279fb71d39c81b1f608e0ee9ba3e498d55fa3..8f82c034de320af7b65bad1602ebb561dd844e59 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java +@@ -31,14 +31,18 @@ import java.util.ArrayList; + import java.util.Iterator; + import java.util.List; + import java.util.concurrent.Executor; ++import java.util.concurrent.ExecutorService; + import java.util.concurrent.Executors; + import java.util.concurrent.SynchronousQueue; + import java.util.concurrent.ThreadPoolExecutor; + import java.util.concurrent.TimeUnit; + + public class CraftAsyncScheduler extends CraftScheduler { +- +- private final ThreadPoolExecutor executor = new ThreadPoolExecutor( ++ // DivineMC start - Virtual Threads ++ private final ExecutorService executor = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualBukkitScheduler ++ ? Executors.newVirtualThreadPerTaskExecutor() ++ : new ThreadPoolExecutor( ++ // DivineMC end - Virtual Threads + 4, Integer.MAX_VALUE,30L, TimeUnit.SECONDS, new SynchronousQueue<>(), + new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build()); + private final Executor management = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder() +@@ -47,8 +51,12 @@ public class CraftAsyncScheduler extends CraftScheduler { + + CraftAsyncScheduler() { + super(true); +- executor.allowCoreThreadTimeOut(true); +- executor.prestartAllCoreThreads(); ++ // DivineMC start - Virtual Threads ++ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && !org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualBukkitScheduler) { ++ ((ThreadPoolExecutor) executor).allowCoreThreadTimeOut(true); ++ ((ThreadPoolExecutor) executor).prestartAllCoreThreads(); ++ } ++ // DivineMC end - Virtual Threads + } + + @Override diff --git a/divinemc-server/paper-patches/features/0015-Implement-Secure-Seed.patch b/divinemc-server/paper-patches/features/0016-Implement-Secure-Seed.patch similarity index 100% rename from divinemc-server/paper-patches/features/0015-Implement-Secure-Seed.patch rename to divinemc-server/paper-patches/features/0016-Implement-Secure-Seed.patch diff --git a/divinemc-server/paper-patches/features/0016-Petal-Multithreaded-Tracker.patch b/divinemc-server/paper-patches/features/0017-Petal-Multithreaded-Tracker.patch similarity index 100% rename from divinemc-server/paper-patches/features/0016-Petal-Multithreaded-Tracker.patch rename to divinemc-server/paper-patches/features/0017-Petal-Multithreaded-Tracker.patch diff --git a/divinemc-server/paper-patches/features/0017-Pufferfish-Optimize-mob-spawning.patch b/divinemc-server/paper-patches/features/0018-Pufferfish-Optimize-mob-spawning.patch similarity index 100% rename from divinemc-server/paper-patches/features/0017-Pufferfish-Optimize-mob-spawning.patch rename to divinemc-server/paper-patches/features/0018-Pufferfish-Optimize-mob-spawning.patch diff --git a/divinemc-server/paper-patches/features/0018-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch b/divinemc-server/paper-patches/features/0019-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch similarity index 100% rename from divinemc-server/paper-patches/features/0018-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch rename to divinemc-server/paper-patches/features/0019-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch diff --git a/divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/paper-patches/features/0020-SparklyPaper-Parallel-world-ticking.patch similarity index 100% rename from divinemc-server/paper-patches/features/0019-SparklyPaper-Parallel-world-ticking.patch rename to divinemc-server/paper-patches/features/0020-SparklyPaper-Parallel-world-ticking.patch diff --git a/divinemc-server/paper-patches/features/0020-Rewrite-ReferenceList.patch b/divinemc-server/paper-patches/features/0021-Rewrite-ReferenceList.patch similarity index 100% rename from divinemc-server/paper-patches/features/0020-Rewrite-ReferenceList.patch rename to divinemc-server/paper-patches/features/0021-Rewrite-ReferenceList.patch diff --git a/divinemc-server/paper-patches/features/0021-Configurable-Max-View-Distance.patch b/divinemc-server/paper-patches/features/0022-Configurable-Max-View-Distance.patch similarity index 100% rename from divinemc-server/paper-patches/features/0021-Configurable-Max-View-Distance.patch rename to divinemc-server/paper-patches/features/0022-Configurable-Max-View-Distance.patch diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 14ac0ee..933eb96 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -338,7 +338,6 @@ public class DivineConfig { public static long chunkDataCacheLimit = 32678L; public static int maxViewDistance = 32; public static int playerNearChunkDetectionRange = 128; - public static int threadPoolPriority = Thread.NORM_PRIORITY + 1; public static boolean smoothBedrockLayer = false; public static boolean enableDensityFunctionCompiler = false; public static boolean enableStructureLayoutOptimizer = true; @@ -401,9 +400,6 @@ public class DivineConfig { playerNearChunkDetectionRange = 128; } - threadPoolPriority = getInt(ConfigCategory.PERFORMANCE.key("chunks.thread-pool-priority"), threadPoolPriority, - "Sets the priority of the thread pool used for chunk generation"); - smoothBedrockLayer = getBoolean(ConfigCategory.PERFORMANCE.key("chunks.smooth-bedrock-layer"), smoothBedrockLayer, "Smoothens the bedrock layer at the bottom of overworld, and on the top of nether during the world generation."); From 0fb69a9136bfbd1253a6a0c0bfee82a411212d66 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 03:42:12 +0300 Subject: [PATCH 18/67] nah, remove VT from RCT --- .../0081-Regionized-Chunk-Ticking.patch | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch b/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch index 987f1e0..994a345 100644 --- a/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch +++ b/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch @@ -21,24 +21,18 @@ index e72eda830644851656fae3118c513d7bd701be45..4ab30d291de7db5ad7d5684662f41348 if (var2 instanceof ClosedChannelException) { LOGGER.info("Connection closed during protocol change"); diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 4fe0f6ba751666e436053536f7607fb50c8471f6..b61580cd7216bd35f5bfade2aaf922b646dd61d8 100644 +index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afad669ae9f 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -57,6 +57,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -57,6 +57,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon private static final Logger LOGGER = LogUtils.getLogger(); private final DistanceManager distanceManager; private final ServerLevel level; -+ // DivineMC start - Regionized Chunk Ticking -+ public static final Executor REGION_EXECUTOR = org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingUseVirtualThreads -+ ? java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor() -+ : java.util.concurrent.Executors.newFixedThreadPool(org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadCount, -+ new org.bxteam.divinemc.util.NamedAgnosticThreadFactory<>("Region Ticking", ca.spottedleaf.moonrise.common.util.TickThread::new, -+ org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadPriority)); -+ // DivineMC end - Regionized Chunk Ticking ++ public static final Executor REGION_EXECUTOR = java.util.concurrent.Executors.newFixedThreadPool(org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadCount, new org.bxteam.divinemc.util.NamedAgnosticThreadFactory<>("Region Ticking", ca.spottedleaf.moonrise.common.util.TickThread::new, org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadPriority)); // DivineMC - Regionized Chunk Ticking public final Thread mainThread; final ThreadedLevelLightEngine lightEngine; public final ServerChunkCache.MainThreadExecutor mainThreadProcessor; -@@ -70,8 +77,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -70,8 +71,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon private final long[] lastChunkPos = new long[4]; private final ChunkStatus[] lastChunkStatus = new ChunkStatus[4]; private final ChunkAccess[] lastChunk = new ChunkAccess[4]; @@ -51,7 +45,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..b61580cd7216bd35f5bfade2aaf922b6 @Nullable @VisibleForDebug private NaturalSpawner.SpawnState lastSpawnState; -@@ -153,31 +162,246 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -153,31 +156,246 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon return load ? this.syncLoad(chunkX, chunkZ, toStatus) : null; } // Paper end - rewrite chunk system @@ -307,7 +301,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..b61580cd7216bd35f5bfade2aaf922b6 } // Paper end - chunk tick iteration optimisations -@@ -502,14 +726,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -502,14 +720,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon long gameTime = this.level.getGameTime(); long l = gameTime - this.lastInhabitedUpdate; this.lastInhabitedUpdate = gameTime; @@ -333,7 +327,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..b61580cd7216bd35f5bfade2aaf922b6 // DivineMC start - Async mob spawning if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) { for (ServerPlayer player : this.level.players) { -@@ -553,14 +784,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -553,14 +778,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } private void broadcastChangedChunks() { @@ -358,7 +352,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..b61580cd7216bd35f5bfade2aaf922b6 } private void tickChunks(long timeInhabited) { -@@ -610,23 +845,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -610,23 +839,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon filteredSpawningCategories = List.of(); } From 5f54cc34f39814948eab3d842e3a4275b60a478e Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 04:03:15 +0300 Subject: [PATCH 19/67] Optimize Aquifer and Beardifier --- build-data/divinemc.at | 3 + ...C2ME-Optimize-Aquifer-and-Beardifier.patch | 705 +++++++++++++++++ .../divinemc/util/CollectionWrapperUtil.java | 744 ------------------ .../org/bxteam/divinemc/util/RandomUtil.java | 40 + .../util/map/Int2ObjectConcurrentHashMap.java | 160 ---- 5 files changed, 748 insertions(+), 904 deletions(-) create mode 100644 divinemc-server/minecraft-patches/features/0085-C2ME-Optimize-Aquifer-and-Beardifier.patch delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/util/CollectionWrapperUtil.java create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/util/map/Int2ObjectConcurrentHashMap.java diff --git a/build-data/divinemc.at b/build-data/divinemc.at index af17be0..457eb6b 100644 --- a/build-data/divinemc.at +++ b/build-data/divinemc.at @@ -36,6 +36,9 @@ public net.minecraft.world.level.levelgen.NoiseChunk$BlendOffset public net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity public net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity getSpaghettiRarity3D(D)D public net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity getSphaghettiRarity2D(D)D +public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedHi +public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedLo +public net.minecraft.world.level.levelgen.XoroshiroRandomSource randomNumberGenerator public net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool rawTemplates public net.minecraft.world.level.pathfinder.SwimNodeEvaluator allowBreaching public-f ca.spottedleaf.moonrise.paper.PaperHooks diff --git a/divinemc-server/minecraft-patches/features/0085-C2ME-Optimize-Aquifer-and-Beardifier.patch b/divinemc-server/minecraft-patches/features/0085-C2ME-Optimize-Aquifer-and-Beardifier.patch new file mode 100644 index 0000000..04bc812 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0085-C2ME-Optimize-Aquifer-and-Beardifier.patch @@ -0,0 +1,705 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 10 Jul 2025 03:48:14 +0300 +Subject: [PATCH] C2ME: Optimize Aquifer and Beardifier + +This patch is based on the following mixins: +* "com/ishland/c2me/opts/worldgen/vanilla/mixin/aquifer/MixinAquiferSamplerImpl.java" +* "com/ishland/c2me/opts/worldgen/general/common/random_instances/RandomUtils.java" +By: ishland +As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric) +Licensed under: MIT (https://opensource.org/licenses/MIT) + +diff --git a/net/minecraft/world/level/levelgen/Aquifer.java b/net/minecraft/world/level/levelgen/Aquifer.java +index c62a15ea4a1bb22e7bcc2fc544acf8a601892029..2efa0b8bb7189d768cb43e55376b397f4f806374 100644 +--- a/net/minecraft/world/level/levelgen/Aquifer.java ++++ b/net/minecraft/world/level/levelgen/Aquifer.java +@@ -85,6 +85,15 @@ public interface Aquifer { + private final int minGridZ; + private final int gridSizeX; + private final int gridSizeZ; ++ // DivineMC start - C2ME: Optimize Aquifer ++ private int c2me$dist1; ++ private int c2me$dist2; ++ private int c2me$dist3; ++ private long c2me$pos1; ++ private long c2me$pos2; ++ private long c2me$pos3; ++ private double c2me$mutableDoubleThingy; ++ // DivineMC end - C2ME: Optimize Aquifer + private static final int[][] SURFACE_SAMPLING_OFFSETS_IN_CHUNKS = new int[][]{ + {0, 0}, {-2, -1}, {-1, -1}, {0, -1}, {1, -1}, {-3, 0}, {-2, 0}, {-1, 0}, {1, 0}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1} + }; +@@ -120,6 +129,36 @@ public interface Aquifer { + this.aquiferCache = new Aquifer.FluidStatus[i4]; + this.aquiferLocationCache = new long[i4]; + Arrays.fill(this.aquiferLocationCache, Long.MAX_VALUE); ++ // DivineMC start - C2ME: Optimize Aquifer ++ if (this.aquiferLocationCache.length % (this.gridSizeX * this.gridSizeZ) != 0) { ++ throw new AssertionError("Array length"); ++ } ++ ++ int sizeY = this.aquiferLocationCache.length / (this.gridSizeX * this.gridSizeZ); ++ ++ final RandomSource random = org.bxteam.divinemc.util.RandomUtil.getRandom(this.positionalRandomFactory); ++ // index: y, z, x ++ for (int y = 0; y < sizeY; y++) { ++ for (int z = 0; z < this.gridSizeZ; z++) { ++ for (int x = 0; x < this.gridSizeX; x++) { ++ final int x1 = x + this.minGridX; ++ final int y1 = y + this.minGridY; ++ final int z1 = z + this.minGridZ; ++ org.bxteam.divinemc.util.RandomUtil.derive(this.positionalRandomFactory, random, x1, y1, z1); ++ int x2 = x1 * 16 + random.nextInt(10); ++ int y2 = y1 * 12 + random.nextInt(9); ++ int z2 = z1 * 16 + random.nextInt(10); ++ int index = this.getIndex(x1, y1, z1); ++ this.aquiferLocationCache[index] = BlockPos.asLong(x2, y2, z2); ++ } ++ } ++ } ++ for (long blockPosition : this.aquiferLocationCache) { ++ if (blockPosition == Long.MAX_VALUE) { ++ throw new AssertionError("Array initialization"); ++ } ++ } ++ // DivineMC end - C2ME: Optimize Aquifer + } + + private int getIndex(int gridX, int gridY, int gridZ) { +@@ -132,140 +171,24 @@ public interface Aquifer { + @Nullable + @Override + public BlockState computeSubstance(DensityFunction.FunctionContext context, double substance) { ++ // DivineMC start - C2ME: Optimize Aquifer + int i = context.blockX(); +- int i1 = context.blockY(); +- int i2 = context.blockZ(); ++ int j = context.blockY(); ++ int k = context.blockZ(); + if (substance > 0.0) { + this.shouldScheduleFluidUpdate = false; + return null; + } else { +- Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(i, i1, i2); +- if (fluidStatus.at(i1).is(Blocks.LAVA)) { ++ Aquifer.FluidStatus fluidLevel = this.globalFluidPicker.computeFluid(i, j, k); ++ if (fluidLevel.at(j).is(Blocks.LAVA)) { + this.shouldScheduleFluidUpdate = false; + return Blocks.LAVA.defaultBlockState(); + } else { +- int i3 = Math.floorDiv(i - 5, 16); +- int i4 = Math.floorDiv(i1 + 1, 12); +- int i5 = Math.floorDiv(i2 - 5, 16); +- int i6 = Integer.MAX_VALUE; +- int i7 = Integer.MAX_VALUE; +- int i8 = Integer.MAX_VALUE; +- int i9 = Integer.MAX_VALUE; +- long l = 0L; +- long l1 = 0L; +- long l2 = 0L; +- long l3 = 0L; +- +- for (int i10 = 0; i10 <= 1; i10++) { +- for (int i11 = -1; i11 <= 1; i11++) { +- for (int i12 = 0; i12 <= 1; i12++) { +- int i13 = i3 + i10; +- int i14 = i4 + i11; +- int i15 = i5 + i12; +- int index = this.getIndex(i13, i14, i15); +- long l4 = this.aquiferLocationCache[index]; +- long l5; +- if (l4 != Long.MAX_VALUE) { +- l5 = l4; +- } else { +- RandomSource randomSource = this.positionalRandomFactory.at(i13, i14, i15); +- l5 = BlockPos.asLong( +- i13 * 16 + randomSource.nextInt(10), i14 * 12 + randomSource.nextInt(9), i15 * 16 + randomSource.nextInt(10) +- ); +- this.aquiferLocationCache[index] = l5; +- } +- +- int i16 = BlockPos.getX(l5) - i; +- int i17 = BlockPos.getY(l5) - i1; +- int i18 = BlockPos.getZ(l5) - i2; +- int i19 = i16 * i16 + i17 * i17 + i18 * i18; +- if (i6 >= i19) { +- l3 = l2; +- l2 = l1; +- l1 = l; +- l = l5; +- i9 = i8; +- i8 = i7; +- i7 = i6; +- i6 = i19; +- } else if (i7 >= i19) { +- l3 = l2; +- l2 = l1; +- l1 = l5; +- i9 = i8; +- i8 = i7; +- i7 = i19; +- } else if (i8 >= i19) { +- l3 = l2; +- l2 = l5; +- i9 = i8; +- i8 = i19; +- } else if (i9 >= i19) { +- l3 = l5; +- i9 = i19; +- } +- } +- } +- } +- +- Aquifer.FluidStatus aquiferStatus = this.getAquiferStatus(l); +- double d = similarity(i6, i7); +- BlockState blockState = aquiferStatus.at(i1); +- if (d <= 0.0) { +- if (d >= FLOWING_UPDATE_SIMULARITY) { +- Aquifer.FluidStatus aquiferStatus1 = this.getAquiferStatus(l1); +- this.shouldScheduleFluidUpdate = !aquiferStatus.equals(aquiferStatus1); +- } else { +- this.shouldScheduleFluidUpdate = false; +- } +- +- return blockState; +- } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, i1 - 1, i2).at(i1 - 1).is(Blocks.LAVA)) { +- this.shouldScheduleFluidUpdate = true; +- return blockState; +- } else { +- MutableDouble mutableDouble = new MutableDouble(Double.NaN); +- Aquifer.FluidStatus aquiferStatus2 = this.getAquiferStatus(l1); +- double d1 = d * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus2); +- if (substance + d1 > 0.0) { +- this.shouldScheduleFluidUpdate = false; +- return null; +- } else { +- Aquifer.FluidStatus aquiferStatus3 = this.getAquiferStatus(l2); +- double d2 = similarity(i6, i8); +- if (d2 > 0.0) { +- double d3 = d * d2 * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus3); +- if (substance + d3 > 0.0) { +- this.shouldScheduleFluidUpdate = false; +- return null; +- } +- } +- +- double d3 = similarity(i7, i8); +- if (d3 > 0.0) { +- double d4 = d * d3 * this.calculatePressure(context, mutableDouble, aquiferStatus2, aquiferStatus3); +- if (substance + d4 > 0.0) { +- this.shouldScheduleFluidUpdate = false; +- return null; +- } +- } +- +- boolean flag = !aquiferStatus.equals(aquiferStatus2); +- boolean flag1 = d3 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus2.equals(aquiferStatus3); +- boolean flag2 = d2 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus.equals(aquiferStatus3); +- if (!flag && !flag1 && !flag2) { +- this.shouldScheduleFluidUpdate = d2 >= FLOWING_UPDATE_SIMULARITY +- && similarity(i6, i9) >= FLOWING_UPDATE_SIMULARITY +- && !aquiferStatus.equals(this.getAquiferStatus(l3)); +- } else { +- this.shouldScheduleFluidUpdate = true; +- } +- +- return blockState; +- } +- } ++ aquiferExtracted$refreshDistPosIdx(i, j, k); ++ return aquiferExtracted$applyPost(context, substance, j, i, k); + } + } ++ // DivineMC end - C2ME: Optimize Aquifer + } + + @Override +@@ -278,65 +201,28 @@ public interface Aquifer { + return 1.0 - Math.abs(secondDistance - firstDistance) / 25.0; + } + ++ // DivineMC start - C2ME: Optimize Aquifer + private double calculatePressure( +- DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus firstFluid, Aquifer.FluidStatus secondFluid ++ DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2 // DivineMC - rename args + ) { + int i = context.blockY(); +- BlockState blockState = firstFluid.at(i); +- BlockState blockState1 = secondFluid.at(i); +- if ((!blockState.is(Blocks.LAVA) || !blockState1.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState1.is(Blocks.LAVA))) { +- int abs = Math.abs(firstFluid.fluidLevel - secondFluid.fluidLevel); ++ BlockState blockState = fluidLevel.at(i); ++ BlockState blockState2 = fluidLevel2.at(i); ++ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) { ++ int abs = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel); + if (abs == 0) { + return 0.0; + } else { +- double d = 0.5 * (firstFluid.fluidLevel + secondFluid.fluidLevel); +- double d1 = i + 0.5 - d; +- double d2 = abs / 2.0; +- double d3 = 0.0; +- double d4 = 2.5; +- double d5 = 1.5; +- double d6 = 3.0; +- double d7 = 10.0; +- double d8 = 3.0; +- double d9 = d2 - Math.abs(d1); +- double d11; +- if (d1 > 0.0) { +- double d10 = 0.0 + d9; +- if (d10 > 0.0) { +- d11 = d10 / 1.5; +- } else { +- d11 = d10 / 2.5; +- } +- } else { +- double d10 = 3.0 + d9; +- if (d10 > 0.0) { +- d11 = d10 / 3.0; +- } else { +- d11 = d10 / 10.0; +- } +- } +- +- double d10x = 2.0; +- double d12; +- if (!(d11 < -2.0) && !(d11 > 2.0)) { +- double value = substance.getValue(); +- if (Double.isNaN(value)) { +- double d13 = this.barrierNoise.compute(context); +- substance.setValue(d13); +- d12 = d13; +- } else { +- d12 = value; +- } +- } else { +- d12 = 0.0; +- } ++ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel); ++ final double q = aquiferExtracted$getQ(i, d, abs); + +- return 2.0 * (d12 + d11); ++ return aquiferExtracted$postCalculateDensity(context, substance, q); + } + } else { + return 2.0; + } + } ++ // DivineMC end - C2ME: Optimize Aquifer + + private int gridX(int x) { + return Math.floorDiv(x, 16); +@@ -350,23 +236,25 @@ public interface Aquifer { + return Math.floorDiv(z, 16); + } + +- private Aquifer.FluidStatus getAquiferStatus(long packedPos) { +- int x = BlockPos.getX(packedPos); +- int y = BlockPos.getY(packedPos); +- int z = BlockPos.getZ(packedPos); +- int i = this.gridX(x); +- int i1 = this.gridY(y); +- int i2 = this.gridZ(z); +- int index = this.getIndex(i, i1, i2); +- Aquifer.FluidStatus fluidStatus = this.aquiferCache[index]; +- if (fluidStatus != null) { +- return fluidStatus; ++ // DivineMC start - C2ME: Optimize Aquifer ++ private Aquifer.FluidStatus getAquiferStatus(long pos) { ++ int i = BlockPos.getX(pos); ++ int j = BlockPos.getY(pos); ++ int k = BlockPos.getZ(pos); ++ int l = i >> 4; // C2ME - inline: floorDiv(i, 16) ++ int m = Math.floorDiv(j, 12); // C2ME - inline ++ int n = k >> 4; // C2ME - inline: floorDiv(k, 16) ++ int o = this.getIndex(l, m, n); ++ Aquifer.FluidStatus fluidLevel = this.aquiferCache[o]; ++ if (fluidLevel != null) { ++ return fluidLevel; + } else { +- Aquifer.FluidStatus fluidStatus1 = this.computeFluid(x, y, z); +- this.aquiferCache[index] = fluidStatus1; +- return fluidStatus1; ++ Aquifer.FluidStatus fluidLevel2 = this.computeFluid(i, j, k); ++ this.aquiferCache[o] = fluidLevel2; ++ return fluidLevel2; + } + } ++ // DivineMC end - C2ME: Optimize Aquifer + + private Aquifer.FluidStatus computeFluid(int x, int y, int z) { + Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(x, y, z); +@@ -407,22 +295,21 @@ public interface Aquifer { + } + + private int computeSurfaceLevel(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int maxSurfaceLevel, boolean fluidPresent) { +- DensityFunction.SinglePointContext singlePointContext = new DensityFunction.SinglePointContext(x, y, z); ++ // DivineMC start - C2ME: Optimize Aquifer ++ DensityFunction.SinglePointContext unblendedNoisePos = new DensityFunction.SinglePointContext(x, y, z); + double d; + double d1; +- if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, singlePointContext)) { ++ if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, unblendedNoisePos)) { + d = -1.0; + d1 = -1.0; + } else { + int i = maxSurfaceLevel + 8 - y; +- int i1 = 64; +- double d2 = fluidPresent ? Mth.clampedMap((double)i, 0.0, 64.0, 1.0, 0.0) : 0.0; +- double d3 = Mth.clamp(this.fluidLevelFloodednessNoise.compute(singlePointContext), -1.0, 1.0); +- double d4 = Mth.map(d2, 1.0, 0.0, -0.3, 0.8); +- double d5 = Mth.map(d2, 1.0, 0.0, -0.8, 0.4); +- d = d3 - d5; +- d1 = d3 - d4; ++ double f = fluidPresent ? Mth.clampedLerp(1.0, 0.0, ((double) i) / 64.0) : 0.0; // inline ++ double g = Mth.clamp(this.fluidLevelFloodednessNoise.compute(unblendedNoisePos), -1.0, 1.0); ++ d = g + 0.8 + (f - 1.0) * 1.2; // inline ++ d1 = g + 0.3 + (f - 1.0) * 1.1; // inline + } ++ // DivineMC end - C2ME: Optimize Aquifer + + int i; + if (d1 > 0.0) { +@@ -453,12 +340,12 @@ public interface Aquifer { + private BlockState computeFluidType(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int surfaceLevel) { + BlockState blockState = fluidStatus.fluidType; + if (surfaceLevel <= -10 && surfaceLevel != DimensionType.WAY_BELOW_MIN_Y && fluidStatus.fluidType != Blocks.LAVA.defaultBlockState()) { +- int i = 64; +- int i1 = 40; +- int i2 = Math.floorDiv(x, 64); +- int i3 = Math.floorDiv(y, 40); +- int i4 = Math.floorDiv(z, 64); +- double d = this.lavaNoise.compute(new DensityFunction.SinglePointContext(i2, i3, i4)); ++ // DivineMC start - C2ME: Optimize Aquifer ++ int k = x >> 6; ++ int l = Math.floorDiv(y, 40); ++ int m = z >> 6; ++ double d = this.lavaNoise.compute(new DensityFunction.SinglePointContext(k, l, m)); ++ // DivineMC end - C2ME: Optimize Aquifer + if (Math.abs(d) > 0.3) { + blockState = Blocks.LAVA.defaultBlockState(); + } +@@ -466,5 +353,183 @@ public interface Aquifer { + + return blockState; + } ++ ++ // DivineMC start - C2ME: Optimize Aquifer ++ private @org.jetbrains.annotations.Nullable BlockState aquiferExtracted$applyPost(DensityFunction.FunctionContext pos, double density, int j, int i, int k) { ++ Aquifer.FluidStatus fluidLevel2 = this.getAquiferStatus(this.c2me$pos1); ++ double d = similarity(this.c2me$dist1, this.c2me$dist2); ++ BlockState blockState = fluidLevel2.at(j); ++ if (d <= 0.0) { ++ this.shouldScheduleFluidUpdate = d >= FLOWING_UPDATE_SIMULARITY; ++ return blockState; ++ } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, j - 1, k).at(j - 1).is(Blocks.LAVA)) { ++ this.shouldScheduleFluidUpdate = true; ++ return blockState; ++ } else { ++ this.c2me$mutableDoubleThingy = Double.NaN; ++ Aquifer.FluidStatus fluidLevel3 = this.getAquiferStatus(this.c2me$pos2); ++ double e = d * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel3); ++ if (density + e > 0.0) { ++ this.shouldScheduleFluidUpdate = false; ++ return null; ++ } else { ++ return aquiferExtracted$getFinalBlockState(pos, density, d, fluidLevel2, fluidLevel3, blockState); ++ } ++ } ++ } ++ ++ private BlockState aquiferExtracted$getFinalBlockState(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, Aquifer.FluidStatus fluidLevel3, BlockState blockState) { ++ Aquifer.FluidStatus fluidLevel4 = this.getAquiferStatus(this.c2me$pos3); ++ double f = similarity(this.c2me$dist1, this.c2me$dist3); ++ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel2, f, fluidLevel4)) return null; ++ ++ double g = similarity(this.c2me$dist2, this.c2me$dist3); ++ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel3, g, fluidLevel4)) return null; ++ ++ this.shouldScheduleFluidUpdate = true; ++ return blockState; ++ } ++ ++ private boolean aquiferExtracted$extractedCheckFG(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, double f, Aquifer.FluidStatus fluidLevel4) { ++ if (f > 0.0) { ++ double g = d * f * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel4); ++ if (density + g > 0.0) { ++ this.shouldScheduleFluidUpdate = false; ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ private void aquiferExtracted$refreshDistPosIdx(int x, int y, int z) { ++ int gx = (x - 5) >> 4; ++ int gy = Math.floorDiv(y + 1, 12); ++ int gz = (z - 5) >> 4; ++ int dist1 = Integer.MAX_VALUE; ++ int dist2 = Integer.MAX_VALUE; ++ int dist3 = Integer.MAX_VALUE; ++ long pos1 = 0; ++ long pos2 = 0; ++ long pos3 = 0; ++ ++ for (int offY = -1; offY <= 1; ++offY) { ++ for (int offZ = 0; offZ <= 1; ++offZ) { ++ for (int offX = 0; offX <= 1; ++offX) { ++ int posIdx = this.getIndex(gx + offX, gy + offY, gz + offZ); ++ ++ long position = this.aquiferLocationCache[posIdx]; ++ ++ int dx = BlockPos.getX(position) - x; ++ int dy = BlockPos.getY(position) - y; ++ int dz = BlockPos.getZ(position) - z; ++ int dist = dx * dx + dy * dy + dz * dz; ++ ++ if (dist3 >= dist) { ++ pos3 = position; ++ dist3 = dist; ++ } ++ if (dist2 >= dist) { ++ pos3 = pos2; ++ dist3 = dist2; ++ pos2 = position; ++ dist2 = dist; ++ } ++ if (dist1 >= dist) { ++ pos2 = pos1; ++ dist2 = dist1; ++ pos1 = position; ++ dist1 = dist; ++ } ++ } ++ } ++ } ++ ++ this.c2me$dist1 = dist1; ++ this.c2me$dist2 = dist2; ++ this.c2me$dist3 = dist3; ++ this.c2me$pos1 = pos1; ++ this.c2me$pos2 = pos2; ++ this.c2me$pos3 = pos3; ++ } ++ ++ private double c2me$calculateDensityModified( ++ DensityFunction.FunctionContext pos, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2 ++ ) { ++ int i = pos.blockY(); ++ BlockState blockState = fluidLevel.at(i); ++ BlockState blockState2 = fluidLevel2.at(i); ++ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) { ++ int j = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel); ++ if (j == 0) { ++ return 0.0; ++ } else { ++ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel); ++ final double q = aquiferExtracted$getQ(i, d, j); ++ ++ return aquiferExtracted$postCalculateDensityModified(pos, q); ++ } ++ } else { ++ return 2.0; ++ } ++ } ++ ++ private double aquiferExtracted$postCalculateDensity(DensityFunction.FunctionContext pos, MutableDouble mutableDouble, double q) { ++ double r; ++ if (!(q < -2.0) && !(q > 2.0)) { ++ double s = mutableDouble.getValue(); ++ if (Double.isNaN(s)) { ++ double t = this.barrierNoise.compute(pos); ++ mutableDouble.setValue(t); ++ r = t; ++ } else { ++ r = s; ++ } ++ } else { ++ r = 0.0; ++ } ++ ++ return 2.0 * (r + q); ++ } ++ ++ private double aquiferExtracted$postCalculateDensityModified(DensityFunction.FunctionContext pos, double q) { ++ double r; ++ if (!(q < -2.0) && !(q > 2.0)) { ++ double s = this.c2me$mutableDoubleThingy; ++ if (Double.isNaN(s)) { ++ double t = this.barrierNoise.compute(pos); ++ this.c2me$mutableDoubleThingy = t; ++ r = t; ++ } else { ++ r = s; ++ } ++ } else { ++ r = 0.0; ++ } ++ ++ return 2.0 * (r + q); ++ } ++ ++ private static double aquiferExtracted$getQ(double i, double d, double j) { ++ double e = i + 0.5 - d; ++ double f = j / 2.0; ++ double o = f - Math.abs(e); ++ double q; ++ if (e > 0.0) { ++ if (o > 0.0) { ++ q = o / 1.5; ++ } else { ++ q = o / 2.5; ++ } ++ } else { ++ double p = 3.0 + o; ++ if (p > 0.0) { ++ q = p / 3.0; ++ } else { ++ q = p / 10.0; ++ } ++ } ++ return q; ++ } ++ // DivineMC end - C2ME: Optimize Aquifer + } + } +diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java +index 86c15d2d90e63d21cb83622a7b29e11151a4f64a..2c0c0546046857056b8445f59828fdf9821ea001 100644 +--- a/net/minecraft/world/level/levelgen/Beardifier.java ++++ b/net/minecraft/world/level/levelgen/Beardifier.java +@@ -29,6 +29,17 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { + }); + private final ObjectListIterator pieceIterator; + private final ObjectListIterator junctionIterator; ++ // DivineMC start - C2ME: Optimize Beardifier ++ private Beardifier.Rigid[] c2me$pieceArray; ++ private JigsawJunction[] c2me$junctionArray; ++ ++ private void c2me$initArrays() { ++ this.c2me$pieceArray = com.google.common.collect.Iterators.toArray(this.pieceIterator, Beardifier.Rigid.class); ++ this.pieceIterator.back(Integer.MAX_VALUE); ++ this.c2me$junctionArray = com.google.common.collect.Iterators.toArray(this.junctionIterator, JigsawJunction.class); ++ this.junctionIterator.back(Integer.MAX_VALUE); ++ } ++ // DivineMC end - C2ME: Optimize Beardifier + + public static Beardifier forStructuresInChunk(StructureManager structureManager, ChunkPos chunkPos) { + int minBlockX = chunkPos.getMinBlockX(); +@@ -75,50 +86,44 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { + this.junctionIterator = junctionIterator; + } + ++ // DivineMC start - C2ME: Optimize Beardifier + @Override + public double compute(DensityFunction.FunctionContext context) { ++ if (this.c2me$pieceArray == null || this.c2me$junctionArray == null) { ++ this.c2me$initArrays(); ++ } + int i = context.blockX(); +- int i1 = context.blockY(); +- int i2 = context.blockZ(); ++ int j = context.blockY(); ++ int k = context.blockZ(); + double d = 0.0; + +- while (this.pieceIterator.hasNext()) { +- Beardifier.Rigid rigid = this.pieceIterator.next(); +- BoundingBox boundingBox = rigid.box(); +- int groundLevelDelta = rigid.groundLevelDelta(); +- int max = Math.max(0, Math.max(boundingBox.minX() - i, i - boundingBox.maxX())); +- int max1 = Math.max(0, Math.max(boundingBox.minZ() - i2, i2 - boundingBox.maxZ())); +- int i3 = boundingBox.minY() + groundLevelDelta; +- int i4 = i1 - i3; +- +- int i5 = switch (rigid.terrainAdjustment()) { +- case NONE -> 0; +- case BURY, BEARD_THIN -> i4; +- case BEARD_BOX -> Math.max(0, Math.max(i3 - i1, i1 - boundingBox.maxY())); +- case ENCAPSULATE -> Math.max(0, Math.max(boundingBox.minY() - i1, i1 - boundingBox.maxY())); +- }; ++ for (Beardifier.Rigid piece : this.c2me$pieceArray) { ++ BoundingBox blockBox = piece.box(); ++ int l = piece.groundLevelDelta(); ++ int m = Math.max(0, Math.max(blockBox.minX() - i, i - blockBox.maxX())); ++ int n = Math.max(0, Math.max(blockBox.minZ() - k, k - blockBox.maxZ())); ++ int o = blockBox.minY() + l; ++ int p = j - o; + +- d += switch (rigid.terrainAdjustment()) { ++ d += switch (piece.terrainAdjustment()) { // 2 switch statement merged + case NONE -> 0.0; +- case BURY -> getBuryContribution(max, i5 / 2.0, max1); +- case BEARD_THIN, BEARD_BOX -> getBeardContribution(max, i5, max1, i4) * 0.8; +- case ENCAPSULATE -> getBuryContribution(max / 2.0, i5 / 2.0, max1 / 2.0) * 0.8; ++ case BURY -> getBuryContribution(m, (double)p / 2.0, n); ++ case BEARD_THIN -> getBeardContribution(m, p, n, p) * 0.8; ++ case BEARD_BOX -> getBeardContribution(m, Math.max(0, Math.max(o - j, j - blockBox.maxY())), n, p) * 0.8; ++ case ENCAPSULATE -> getBuryContribution((double)m / 2.0, (double)Math.max(0, Math.max(blockBox.minY() - j, j - blockBox.maxY())) / 2.0, (double)n / 2.0) * 0.8; + }; + } + +- this.pieceIterator.back(Integer.MAX_VALUE); +- +- while (this.junctionIterator.hasNext()) { +- JigsawJunction jigsawJunction = this.junctionIterator.next(); +- int i6 = i - jigsawJunction.getSourceX(); +- int groundLevelDelta = i1 - jigsawJunction.getSourceGroundY(); +- int max = i2 - jigsawJunction.getSourceZ(); +- d += getBeardContribution(i6, groundLevelDelta, max, groundLevelDelta) * 0.4; ++ for (JigsawJunction jigsawJunction : this.c2me$junctionArray) { ++ int r = i - jigsawJunction.getSourceX(); ++ int l = j - jigsawJunction.getSourceGroundY(); ++ int m = k - jigsawJunction.getSourceZ(); ++ d += getBeardContribution(r, l, m, l) * 0.4; + } + +- this.junctionIterator.back(Integer.MAX_VALUE); + return d; + } ++ // DivineMC end - C2ME: Optimize Beardifier + + @Override + public double minValue() { +diff --git a/net/minecraft/world/level/levelgen/LegacyRandomSource.java b/net/minecraft/world/level/levelgen/LegacyRandomSource.java +index c67168517774a0ad9ca43422a79ef14a8ea0c2e8..026dfbbb6c3fd5cd274dcbf721e5cf3af889e3d9 100644 +--- a/net/minecraft/world/level/levelgen/LegacyRandomSource.java ++++ b/net/minecraft/world/level/levelgen/LegacyRandomSource.java +@@ -53,13 +53,7 @@ public class LegacyRandomSource implements BitRandomSource { + return this.gaussianSource.nextGaussian(); + } + +- public static class LegacyPositionalRandomFactory implements PositionalRandomFactory { +- private final long seed; +- +- public LegacyPositionalRandomFactory(long seed) { +- this.seed = seed; +- } +- ++ public record LegacyPositionalRandomFactory(long seed) implements PositionalRandomFactory { // DivineMC - make record + @Override + public RandomSource at(int x, int y, int z) { + long seed = Mth.getSeed(x, y, z); +diff --git a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java +index 9d3a9ca1e13cd80f468f1352bbb74345f03903dd..d97b9b43686bda0a95fc02f6ca31b2d07d603a32 100644 +--- a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java ++++ b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java +@@ -106,15 +106,7 @@ public class XoroshiroRandomSource implements RandomSource { + return this.randomNumberGenerator.nextLong() >>> 64 - bits; + } + +- public static class XoroshiroPositionalRandomFactory implements PositionalRandomFactory { +- private final long seedLo; +- private final long seedHi; +- +- public XoroshiroPositionalRandomFactory(long seedLo, long seedHi) { +- this.seedLo = seedLo; +- this.seedHi = seedHi; +- } +- ++ public record XoroshiroPositionalRandomFactory(long seedLo, long seedHi) implements PositionalRandomFactory { // DivineMC - make record + @Override + public RandomSource at(int x, int y, int z) { + long seed = Mth.getSeed(x, y, z); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/CollectionWrapperUtil.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/CollectionWrapperUtil.java deleted file mode 100644 index 1edb1f2..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/CollectionWrapperUtil.java +++ /dev/null @@ -1,744 +0,0 @@ -package org.bxteam.divinemc.util; - -import it.unimi.dsi.fastutil.bytes.ByteIterator; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.IntCollection; -import it.unimi.dsi.fastutil.ints.IntIterator; -import it.unimi.dsi.fastutil.ints.IntSet; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongListIterator; -import it.unimi.dsi.fastutil.objects.ObjectCollection; -import it.unimi.dsi.fastutil.objects.ObjectIterator; -import it.unimi.dsi.fastutil.objects.ObjectSet; -import it.unimi.dsi.fastutil.objects.ReferenceSet; -import it.unimi.dsi.fastutil.shorts.ShortIterator; -import org.apache.commons.lang3.ArrayUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.Iterator; -import java.util.ListIterator; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -public final class CollectionWrapperUtil { - private CollectionWrapperUtil() { - throw new IllegalStateException("This class cannot be instantiated"); - } - - private static Int2ObjectMap.@NotNull Entry intEntryForwards(Map.Entry entry) { - return new Int2ObjectMap.Entry<>() { - @Override - public T getValue() { - return entry.getValue(); - } - - @Override - public T setValue(T value) { - return entry.setValue(value); - } - - @Override - public int getIntKey() { - return entry.getKey(); - } - - @Override - public boolean equals(Object obj) { - if (obj == entry) { - return true; - } - return super.equals(obj); - } - - @Override - public int hashCode() { - return entry.hashCode(); - } - }; - } - - private static Map.Entry intEntryBackwards(Int2ObjectMap.Entry entry) { - return entry; - } - - public static ObjectSet> entrySetIntWrap(Map map) { - return new ConvertingObjectSet<>( - map.entrySet(), - CollectionWrapperUtil::intEntryForwards, - CollectionWrapperUtil::intEntryBackwards - ); - } - - public static IntSet wrapIntSet(Set intset) { - return new WrappingIntSet(intset); - } - - public static ByteIterator itrByteWrap(Iterator backing) { - return new WrappingByteIterator(backing); - } - - public static ByteIterator itrByteWrap(Iterable backing) { - return itrByteWrap(backing.iterator()); - } - - public static IntIterator itrIntWrap(Iterator backing) { - return new WrappingIntIterator(backing); - } - - public static IntIterator itrIntWrap(Iterable backing) { - return itrIntWrap(backing.iterator()); - } - - public static LongIterator itrLongWrap(Iterator backing) { - return new WrappingLongIterator(backing); - } - - public static LongIterator itrLongWrap(Iterable backing) { - return itrLongWrap(backing.iterator()); - } - - public static ShortIterator itrShortWrap(Iterator backing) { - return new WrappingShortIterator(backing); - } - - public static ShortIterator itrShortWrap(Iterable backing) { - return itrShortWrap(backing.iterator()); - } - - public static LongListIterator wrap(ListIterator c) { - return new WrappingLongListIterator(c); - } - - public static LongListIterator wrap(Iterator c) { - return new SlimWrappingLongListIterator(c); - } - - public static ObjectCollection wrap(Collection c) { - return new WrappingObjectCollection<>(c); - } - - public static ReferenceSet wrap(Set s) { - return new WrappingRefSet<>(s); - } - - public static ObjectIterator itrWrap(Iterable in) { - return new WrapperObjectIterator<>(in.iterator()); - } - - public static class ConvertingObjectSet implements ObjectSet { - private final Set backing; - private final Function forward; - private final Function back; - - public ConvertingObjectSet(Set backing, Function forward, Function back) { - this.backing = Objects.requireNonNull(backing, "Backing set cannot be null"); - this.forward = Objects.requireNonNull(forward, "Forward function cannot be null"); - this.back = Objects.requireNonNull(back, "Backward function cannot be null"); - } - - @Override - public int size() { - return backing.size(); - } - - @Override - public boolean isEmpty() { - return backing.isEmpty(); - } - - @SuppressWarnings("unchecked") - @Override - public boolean contains(Object o) { - try { - return backing.contains(back.apply((T) o)); - } catch (ClassCastException cce) { - return false; - } - } - - @Override - public Object[] toArray() { - return backing.stream().map(forward).toArray(); - } - - @Override - public R[] toArray(R[] a) { - return backing.stream().map(forward).collect(Collectors.toSet()).toArray(a); - } - - @Override - public boolean add(T e) { - return backing.add(back.apply(e)); - } - - @SuppressWarnings("unchecked") - @Override - public boolean remove(Object o) { - try { - return backing.remove(back.apply((T) o)); - } catch (ClassCastException cce) { - return false; - } - } - - @SuppressWarnings("unchecked") - @Override - public boolean containsAll(Collection c) { - try { - return backing.containsAll(c.stream() - .map(i -> back.apply((T) i)) - .collect(Collectors.toSet())); - } catch (ClassCastException cce) { - return false; - } - } - - @Override - public boolean addAll(Collection c) { - return backing.addAll(c.stream().map(back).collect(Collectors.toSet())); - } - - @SuppressWarnings("unchecked") - @Override - public boolean removeAll(Collection c) { - try { - return backing.removeAll(c.stream() - .map(i -> back.apply((T) i)) - .collect(Collectors.toSet())); - } catch (ClassCastException cce) { - return false; - } - } - - @SuppressWarnings("unchecked") - @Override - public boolean retainAll(Collection c) { - try { - return backing.retainAll(c.stream() - .map(i -> back.apply((T) i)) - .collect(Collectors.toSet())); - } catch (ClassCastException cce) { - return false; - } - } - - @Override - public void clear() { - backing.clear(); - } - - @Override - public ObjectIterator iterator() { - return new ObjectIterator<>() { - private final Iterator backg = backing.iterator(); - - @Override - public boolean hasNext() { - return backg.hasNext(); - } - - @Override - public T next() { - return forward.apply(backg.next()); - } - - @Override - public void remove() { - backg.remove(); - } - }; - } - } - - static class WrappingIntIterator implements IntIterator { - private final Iterator backing; - - WrappingIntIterator(Iterator backing) { - this.backing = Objects.requireNonNull(backing); - } - - @Override - public boolean hasNext() { - return backing.hasNext(); - } - - @Override - public int nextInt() { - return backing.next(); - } - - @Override - public Integer next() { - return backing.next(); - } - - @Override - public void remove() { - backing.remove(); - } - } - - static class WrappingLongIterator implements LongIterator { - private final Iterator backing; - - WrappingLongIterator(Iterator backing) { - this.backing = Objects.requireNonNull(backing); - } - - @Override - public boolean hasNext() { - return backing.hasNext(); - } - - @Override - public long nextLong() { - return backing.next(); - } - - @Override - public Long next() { - return backing.next(); - } - - @Override - public void remove() { - backing.remove(); - } - } - - static class WrappingShortIterator implements ShortIterator { - private final Iterator backing; - - WrappingShortIterator(Iterator backing) { - this.backing = Objects.requireNonNull(backing); - } - - @Override - public boolean hasNext() { - return backing.hasNext(); - } - - @Override - public short nextShort() { - return backing.next(); - } - - @Override - public Short next() { - return backing.next(); - } - - @Override - public void remove() { - backing.remove(); - } - } - - static class WrappingByteIterator implements ByteIterator { - private final Iterator backing; - - WrappingByteIterator(Iterator backing) { - this.backing = Objects.requireNonNull(backing); - } - - @Override - public boolean hasNext() { - return backing.hasNext(); - } - - @Override - public byte nextByte() { - return next(); - } - - @Override - public Byte next() { - return backing.next(); - } - - @Override - public void remove() { - backing.remove(); - } - } - - public static class WrappingIntSet implements IntSet { - private final Set backing; - - public WrappingIntSet(Set backing) { - this.backing = Objects.requireNonNull(backing); - } - - @Override - public boolean add(int key) { - return backing.add(key); - } - - @Override - public boolean contains(int key) { - return backing.contains(key); - } - - @Override - public int[] toIntArray() { - return backing.stream().mapToInt(Integer::intValue).toArray(); - } - - @Override - public int[] toArray(int[] a) { - return ArrayUtils.toPrimitive(backing.toArray(new Integer[0])); - } - - @Override - public boolean addAll(IntCollection c) { - return backing.addAll(c); - } - - @Override - public boolean containsAll(IntCollection c) { - return backing.containsAll(c); - } - - @Override - public boolean removeAll(IntCollection c) { - return backing.removeAll(c); - } - - @Override - public boolean retainAll(IntCollection c) { - return backing.retainAll(c); - } - - @Override - public int size() { - return backing.size(); - } - - @Override - public boolean isEmpty() { - return backing.isEmpty(); - } - - @Override - public Object[] toArray() { - return backing.toArray(); - } - - @Override - public T[] toArray(T[] a) { - return backing.toArray(a); - } - - @Override - public boolean containsAll(Collection c) { - return backing.containsAll(c); - } - - @Override - public boolean addAll(Collection c) { - return backing.addAll(c); - } - - @Override - public boolean removeAll(Collection c) { - return backing.removeAll(c); - } - - @Override - public boolean retainAll(Collection c) { - return backing.retainAll(c); - } - - @Override - public void clear() { - backing.clear(); - } - - @Override - public IntIterator iterator() { - return new WrappingIntIterator(backing.iterator()); - } - - @Override - public boolean remove(int k) { - return backing.remove(k); - } - } - - public static class WrappingRefSet implements ReferenceSet { - private final Set backing; - - public WrappingRefSet(Set backing) { - this.backing = Objects.requireNonNull(backing); - } - - @Override - public boolean add(V key) { - return backing.add(key); - } - - @Override - public boolean remove(final Object o) { - return backing.remove(o); - } - - @Override - public boolean containsAll(@NotNull final Collection c) { - return backing.containsAll(c); - } - - @Override - public boolean addAll(@NotNull final Collection c) { - return backing.addAll(c); - } - - @Override - public boolean removeAll(@NotNull final Collection c) { - return backing.removeAll(c); - } - - @Override - public boolean retainAll(@NotNull final Collection c) { - return backing.retainAll(c); - } - - @Override - public void clear() { - this.backing.clear(); - } - - @Override - public int size() { - return backing.size(); - } - - @Override - public boolean isEmpty() { - return backing.isEmpty(); - } - - @Override - public boolean contains(final Object o) { - return backing.contains(o); - } - - @Override - public ObjectIterator iterator() { - return null; - } - - @Override - public @NotNull Object[] toArray() { - return this.backing.toArray(); - } - - @Override - public @NotNull T[] toArray(@NotNull final T[] a) { - return this.backing.toArray(a); - } - } - - public static class WrappingLongListIterator implements LongListIterator { - private final ListIterator backing; - - WrappingLongListIterator(ListIterator backing) { - this.backing = Objects.requireNonNull(backing); - } - - @Override - public long previousLong() { - return backing.previous(); - } - - @Override - public long nextLong() { - return backing.next(); - } - - @Override - public boolean hasNext() { - return backing.hasNext(); - } - - @Override - public boolean hasPrevious() { - return backing.hasPrevious(); - } - - @Override - public int nextIndex() { - return backing.nextIndex(); - } - - @Override - public int previousIndex() { - return backing.previousIndex(); - } - - @Override - public void add(long k) { - backing.add(k); - } - - @Override - public void remove() { - backing.remove(); - } - - @Override - public void set(long k) { - backing.set(k); - } - } - - public static class SlimWrappingLongListIterator implements LongListIterator { - private final Iterator backing; - - SlimWrappingLongListIterator(Iterator backing) { - this.backing = Objects.requireNonNull(backing); - } - - @Override - public long previousLong() { - throw new UnsupportedOperationException(); - } - - @Override - public long nextLong() { - return backing.next(); - } - - @Override - public boolean hasNext() { - return backing.hasNext(); - } - - @Override - public boolean hasPrevious() { - throw new UnsupportedOperationException(); - } - - @Override - public int nextIndex() { - throw new UnsupportedOperationException(); - } - - @Override - public int previousIndex() { - throw new UnsupportedOperationException(); - } - - @Override - public void add(long k) { - throw new UnsupportedOperationException(); - } - - @Override - public void remove() { - backing.remove(); - } - - @Override - public void set(long k) { - throw new UnsupportedOperationException(); - } - } - - public static class WrappingObjectCollection implements ObjectCollection { - private final Collection backing; - - public WrappingObjectCollection(Collection backing) { - this.backing = Objects.requireNonNull(backing); - } - - @Override - public int size() { - return backing.size(); - } - - @Override - public boolean isEmpty() { - return backing.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return backing.contains(o); - } - - @Override - public Object[] toArray() { - return backing.toArray(); - } - - @Override - public T[] toArray(T[] a) { - return backing.toArray(a); - } - - @Override - public boolean add(V e) { - return backing.add(e); - } - - @Override - public boolean remove(Object o) { - return backing.remove(o); - } - - @Override - public boolean containsAll(Collection c) { - return backing.containsAll(c); - } - - @Override - public boolean addAll(Collection c) { - return backing.addAll(c); - } - - @Override - public boolean removeAll(Collection c) { - return backing.removeAll(c); - } - - @Override - public boolean retainAll(Collection c) { - return backing.retainAll(c); - } - - @Override - public void clear() { - backing.clear(); - } - - @Override - public ObjectIterator iterator() { - return itrWrap(backing); - } - } - - private record WrapperObjectIterator(Iterator parent) implements ObjectIterator { - private WrapperObjectIterator(Iterator parent) { - this.parent = Objects.requireNonNull(parent); - } - - @Override - public boolean hasNext() { - return parent.hasNext(); - } - - @Override - public T next() { - return parent.next(); - } - - @Override - public void remove() { - parent.remove(); - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java new file mode 100644 index 0000000..5f47188 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java @@ -0,0 +1,40 @@ +package org.bxteam.divinemc.util; + +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.levelgen.LegacyRandomSource; +import net.minecraft.world.level.levelgen.PositionalRandomFactory; +import net.minecraft.world.level.levelgen.SingleThreadedRandomSource; +import net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus; +import net.minecraft.world.level.levelgen.XoroshiroRandomSource; +import org.jetbrains.annotations.NotNull; + +public final class RandomUtil { + public static @NotNull RandomSource getRandom(PositionalRandomFactory deriver) { + if (deriver instanceof XoroshiroRandomSource.XoroshiroPositionalRandomFactory) { + return new XoroshiroRandomSource(0L, 0L); + } + if (deriver instanceof LegacyRandomSource.LegacyPositionalRandomFactory) { + return new SingleThreadedRandomSource(0L); + } + throw new IllegalArgumentException(); + } + + private static final ThreadLocal xoroshiro = ThreadLocal.withInitial(() -> new XoroshiroRandomSource(0L, 0L)); + private static final ThreadLocal simple = ThreadLocal.withInitial(() -> new SingleThreadedRandomSource(0L)); + + public static void derive(PositionalRandomFactory deriver, RandomSource random, int x, int y, int z) { + if (deriver instanceof final XoroshiroRandomSource.XoroshiroPositionalRandomFactory deriver1) { + final Xoroshiro128PlusPlus implementation = ((XoroshiroRandomSource) random).randomNumberGenerator; + implementation.seedLo = (Mth.getSeed(x, y, z) ^ deriver1.seedLo()); + implementation.seedHi = (deriver1.seedHi()); + return; + } + if (deriver instanceof LegacyRandomSource.LegacyPositionalRandomFactory(long seed)) { + final SingleThreadedRandomSource random1 = (SingleThreadedRandomSource) random; + random1.setSeed(Mth.getSeed(x, y, z) ^ seed); + return; + } + throw new IllegalArgumentException(); + } +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/map/Int2ObjectConcurrentHashMap.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/map/Int2ObjectConcurrentHashMap.java deleted file mode 100644 index cac8e64..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/map/Int2ObjectConcurrentHashMap.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.bxteam.divinemc.util.map; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.IntSet; -import it.unimi.dsi.fastutil.objects.ObjectCollection; -import it.unimi.dsi.fastutil.objects.ObjectSet; -import org.bxteam.divinemc.util.CollectionWrapperUtil; - -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -public final class Int2ObjectConcurrentHashMap implements Int2ObjectMap { - private final ConcurrentHashMap backing; - private V defaultReturnValue; - - public Int2ObjectConcurrentHashMap() { - this(16); - } - - public Int2ObjectConcurrentHashMap(int initialCapacity) { - if (initialCapacity < 0) { - throw new IllegalArgumentException("Initial capacity cannot be negative: " + initialCapacity); - } - - this.backing = new ConcurrentHashMap<>(initialCapacity); - } - - public Int2ObjectConcurrentHashMap(Map map) { - this(Math.max(16, map.size())); - putAll(Objects.requireNonNull(map, "Source map cannot be null")); - } - - @Override - public V get(int key) { - V value = backing.get(key); - return value != null ? value : defaultReturnValue; - } - - @Override - public V get(Object key) { - V value = backing.get(key); - return value != null ? value : defaultReturnValue; - } - - @Override - public boolean isEmpty() { - return backing.isEmpty(); - } - - @Override - public boolean containsValue(Object value) { - return backing.containsValue(value); - } - - @Override - public void putAll(Map m) { - Objects.requireNonNull(m, "Source map cannot be null"); - backing.putAll(m); - } - - @Override - public int size() { - return backing.size(); - } - - @Override - public void defaultReturnValue(V rv) { - this.defaultReturnValue = rv; - } - - @Override - public V defaultReturnValue() { - return defaultReturnValue; - } - - @Override - public ObjectSet> int2ObjectEntrySet() { - return CollectionWrapperUtil.entrySetIntWrap(backing); - } - - @Override - public IntSet keySet() { - return CollectionWrapperUtil.wrapIntSet(backing.keySet()); - } - - @Override - public ObjectCollection values() { - return CollectionWrapperUtil.wrap(backing.values()); - } - - @Override - public boolean containsKey(int key) { - return backing.containsKey(key); - } - - @Override - public V put(int key, V value) { - return backing.put(key, value); - } - - @Override - public V remove(int key) { - return backing.remove(key); - } - - @Override - public void clear() { - backing.clear(); - } - - public V compute(int key, java.util.function.BiFunction remappingFunction) { - Objects.requireNonNull(remappingFunction); - return backing.compute(key, remappingFunction); - } - - public ConcurrentHashMap concurrentView() { - return backing; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Int2ObjectMap that)) return false; - - if (size() != that.size()) return false; - return int2ObjectEntrySet().containsAll(that.int2ObjectEntrySet()); - } - - @Override - public int hashCode() { - return backing.hashCode(); - } - - @Override - public String toString() { - return backing.toString(); - } - - public V getOrDefault(int key, V defaultValue) { - V value = get(key); - return value != null ? value : defaultValue; - } - - public V putIfAbsent(int key, V value) { - return backing.putIfAbsent(key, value); - } - - public boolean remove(int key, Object value) { - return backing.remove(key, value); - } - - public boolean replace(int key, V oldValue, V newValue) { - return backing.replace(key, oldValue, newValue); - } - - public V replace(int key, V value) { - return backing.replace(key, value); - } -} From 08f2da878e22dec69839c995a61f58e914b9e102 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 04:33:33 +0300 Subject: [PATCH 20/67] add 1gt features --- ...-Disable-offline-warn-if-using-proxy.patch | 19 +++++++ .../features/0087-Copper-Bulb-1gt-delay.patch | 49 +++++++++++++++++++ .../features/0088-Crafter-1gt-delay.patch | 28 +++++++++++ .../bxteam/divinemc/config/DivineConfig.java | 12 +++++ 4 files changed, 108 insertions(+) create mode 100644 divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch create mode 100644 divinemc-server/minecraft-patches/features/0087-Copper-Bulb-1gt-delay.patch create mode 100644 divinemc-server/minecraft-patches/features/0088-Crafter-1gt-delay.patch diff --git a/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch b/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch new file mode 100644 index 0000000..51445a0 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 10 Jul 2025 04:21:08 +0300 +Subject: [PATCH] Disable offline warn if using proxy + + +diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java +index 13d85eb366a070bfd6723088412f51af07892362..bdb37afb8f30d19726c4775e1eaa8c1dabacd3a7 100644 +--- a/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/net/minecraft/server/dedicated/DedicatedServer.java +@@ -311,7 +311,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord"; + String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/"; + // Paper end - Add Velocity IP Forwarding Support +- if (!this.usesAuthentication()) { ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()) { // DivineMC - Disable offline warn if using proxy + LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); + LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); + // Spigot start diff --git a/divinemc-server/minecraft-patches/features/0087-Copper-Bulb-1gt-delay.patch b/divinemc-server/minecraft-patches/features/0087-Copper-Bulb-1gt-delay.patch new file mode 100644 index 0000000..194d085 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0087-Copper-Bulb-1gt-delay.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 10 Jul 2025 04:30:21 +0300 +Subject: [PATCH] Copper Bulb 1gt delay + + +diff --git a/net/minecraft/world/level/block/CopperBulbBlock.java b/net/minecraft/world/level/block/CopperBulbBlock.java +index 25caeb117d9a49fa00f46ec895a35dee8242aacd..3a2b751b150e7930817fd07d50a3baeecb44f7d1 100644 +--- a/net/minecraft/world/level/block/CopperBulbBlock.java ++++ b/net/minecraft/world/level/block/CopperBulbBlock.java +@@ -32,16 +32,36 @@ public class CopperBulbBlock extends Block { + @Override + protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + if (oldState.getBlock() != state.getBlock() && level instanceof ServerLevel serverLevel) { +- this.checkAndFlip(state, serverLevel, pos); ++ // DivineMC start - Copper Bulb 1gt delay ++ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt) { ++ this.checkAndFlip(state, serverLevel, pos); ++ } else { ++ level.scheduleTick(pos, this, 1); ++ } ++ // DivineMC end - Copper Bulb 1gt delay + } + } + + @Override + protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { + if (level instanceof ServerLevel serverLevel) { +- this.checkAndFlip(state, serverLevel, pos); ++ // DivineMC start - Copper Bulb 1gt delay ++ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt) { ++ this.checkAndFlip(state, serverLevel, pos); ++ } else { ++ level.scheduleTick(pos, this, 1); ++ } ++ } ++ } ++ ++ // DivineMC start - Copper Bulb 1gt delay ++ @Override ++ public void tick(BlockState state, ServerLevel level, BlockPos pos, net.minecraft.util.RandomSource random) { ++ if (org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt) { ++ checkAndFlip(state, level, pos); + } + } ++ // DivineMC end - Copper Bulb 1gt delay + + public void checkAndFlip(BlockState state, ServerLevel level, BlockPos pos) { + boolean hasNeighborSignal = level.hasNeighborSignal(pos); diff --git a/divinemc-server/minecraft-patches/features/0088-Crafter-1gt-delay.patch b/divinemc-server/minecraft-patches/features/0088-Crafter-1gt-delay.patch new file mode 100644 index 0000000..235cb7b --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0088-Crafter-1gt-delay.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 10 Jul 2025 04:31:46 +0300 +Subject: [PATCH] Crafter 1gt delay + + +diff --git a/net/minecraft/world/level/block/CrafterBlock.java b/net/minecraft/world/level/block/CrafterBlock.java +index 38b03c7b02bdfc579e5e126c12de3d878e26d188..c3e68a63f6f7d669dca8a08625a04bd7c8ef0327 100644 +--- a/net/minecraft/world/level/block/CrafterBlock.java ++++ b/net/minecraft/world/level/block/CrafterBlock.java +@@ -75,7 +75,7 @@ public class CrafterBlock extends BaseEntityBlock { + boolean triggeredValue = state.getValue(TRIGGERED); + BlockEntity blockEntity = level.getBlockEntity(pos); + if (hasNeighborSignal && !triggeredValue) { +- level.scheduleTick(pos, this, 4); ++ level.scheduleTick(pos, this, !org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt ? 4 : 1); // DivineMC - Crafter 1gt delay + level.setBlock(pos, state.setValue(TRIGGERED, true), 2); + this.setBlockEntityTriggered(blockEntity, true); + } else if (!hasNeighborSignal && triggeredValue) { +@@ -125,7 +125,7 @@ public class CrafterBlock extends BaseEntityBlock { + @Override + public void setPlacedBy(Level level, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { + if (state.getValue(TRIGGERED)) { +- level.scheduleTick(pos, this, 4); ++ level.scheduleTick(pos, this, !org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt ? 4 : 1); // DivineMC - Crafter 1gt delay + } + } + diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 933eb96..36bfc85 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -571,10 +571,15 @@ public class DivineConfig { public static String logLevel = "WARN"; public static boolean onlyLogThrown = true; + // Old features + public static boolean copperBulb1gt = false; + public static boolean crafter1gt = false; + public static void load() { secureSeed(); lagCompensation(); sentrySettings(); + oldFeatures(); } private static void secureSeed() { @@ -609,6 +614,13 @@ public class DivineConfig { if (sentryDsn != null && !sentryDsn.isBlank()) gg.pufferfish.pufferfish.sentry.SentryManager.init(Level.getLevel(logLevel)); } + + private static void oldFeatures() { + copperBulb1gt = getBoolean(ConfigCategory.MISC.key("old-features.copper-bulb-1gt"), copperBulb1gt, + "Whether to delay the copper lamp by 1 tick when the redstone signal changes."); + crafter1gt = getBoolean(ConfigCategory.MISC.key("old-features.crafter-1gt"), crafter1gt, + "Whether to reduce the frequency of the crafter outputting items to 1 tick."); + } } public static class NetworkCategory { From df17c196524e8abf3a8ea2fd13b18dbd3490120a Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 04:54:16 +0300 Subject: [PATCH 21/67] [Experimental] Raytrace Entity Tracker --- .../0089-Raytrace-Entity-Tracker.patch | 169 ++++++ .../occlusionculling/DataProvider.java | 30 + .../OcclusionCullingInstance.java | 513 ++++++++++++++++++ .../cache/ArrayOcclusionCache.java | 55 ++ .../cache/OcclusionCache.java | 15 + .../occlusionculling/util/MathUtilities.java | 19 + .../occlusionculling/util/Vec3d.java | 85 +++ .../dev/tr7zw/entityculling/CullTask.java | 146 +++++ .../DefaultChunkDataProvider.java | 41 ++ .../versionless/access/Cullable.java | 15 + .../bxteam/divinemc/config/DivineConfig.java | 21 + 11 files changed, 1109 insertions(+) create mode 100644 divinemc-server/minecraft-patches/features/0089-Raytrace-Entity-Tracker.patch create mode 100644 divinemc-server/src/main/java/com/logisticscraft/occlusionculling/DataProvider.java create mode 100644 divinemc-server/src/main/java/com/logisticscraft/occlusionculling/OcclusionCullingInstance.java create mode 100644 divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/ArrayOcclusionCache.java create mode 100644 divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/OcclusionCache.java create mode 100644 divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/MathUtilities.java create mode 100644 divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/Vec3d.java create mode 100644 divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java create mode 100644 divinemc-server/src/main/java/dev/tr7zw/entityculling/DefaultChunkDataProvider.java create mode 100644 divinemc-server/src/main/java/dev/tr7zw/entityculling/versionless/access/Cullable.java diff --git a/divinemc-server/minecraft-patches/features/0089-Raytrace-Entity-Tracker.patch b/divinemc-server/minecraft-patches/features/0089-Raytrace-Entity-Tracker.patch new file mode 100644 index 0000000..cee2bed --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0089-Raytrace-Entity-Tracker.patch @@ -0,0 +1,169 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 10 Jul 2025 04:51:08 +0300 +Subject: [PATCH] Raytrace Entity Tracker + +Original project: https://github.com/tr7zw/EntityCulling +Original license: Custom License + +Original project: https://github.com/LogisticsCraft/OcclusionCulling +Original license: MIT + +diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java +index a3290eb416ecb377d240bf334aef4e2b5e3bbefc..269c3312c1633faf48c1b471583ca71adfc8d2c6 100644 +--- a/net/minecraft/server/level/ChunkMap.java ++++ b/net/minecraft/server/level/ChunkMap.java +@@ -1421,7 +1421,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + double d1 = vec3_dx * vec3_dx + vec3_dz * vec3_dz; // Paper + double d2 = d * d; + // Paper start - Configurable entity tracking range by Y +- boolean flag = d1 <= d2; ++ boolean flag = d1 <= d2 && !entity.isCulled(); // DivineMC - Raytrace Entity Tracker + if (flag && level.paperConfig().entities.trackingRangeY.enabled) { + double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1); + if (rangeY != -1) { +diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java +index 44cd33cec38b1a2af304ec819b14124187011df1..ae8f7a1fdf85b9468d310123c77097df8c7054a4 100644 +--- a/net/minecraft/world/entity/Entity.java ++++ b/net/minecraft/world/entity/Entity.java +@@ -145,7 +145,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter; + import org.jetbrains.annotations.Contract; + import org.slf4j.Logger; + +-public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, DataComponentGetter, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker ++public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, DataComponentGetter, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity, dev.tr7zw.entityculling.versionless.access.Cullable { // Paper - rewrite chunk system // Paper - optimise entity tracker // DivineMC - Raytrace Entity Tracker + public static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur - Configurable entity base attributes + // CraftBukkit start + private static final int CURRENT_LEVEL = 2; +@@ -5475,4 +5475,47 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return false; + } + // Purpur end - Ridables ++ ++ // DivineMC start - Raytrace Entity Tracker ++ private long lasttime = 0; ++ private boolean culled = false; ++ private boolean outOfCamera = false; ++ ++ @Override ++ public void setTimeout() { ++ this.lasttime = System.currentTimeMillis() + 1000; ++ } ++ ++ @Override ++ public boolean isForcedVisible() { ++ return this.lasttime > System.currentTimeMillis(); ++ } ++ ++ @Override ++ public void setCulled(boolean value) { ++ this.culled = value; ++ if (!value) { ++ setTimeout(); ++ } ++ } ++ ++ @Override ++ public boolean isCulled() { ++ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.retEnabled) return false; ++ ++ return this.culled; ++ } ++ ++ @Override ++ public void setOutOfCamera(boolean value) { ++ this.outOfCamera = value; ++ } ++ ++ @Override ++ public boolean isOutOfCamera() { ++ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.retEnabled) return false; ++ ++ return this.outOfCamera; ++ } ++ // DivineMC end - Raytrace Entity Tracker + } +diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java +index 0159627e2c9a540d062073faf9018f5215e10866..26f6941dfbe0453ed5b091e408d8422901f4ca32 100644 +--- a/net/minecraft/world/entity/EntityType.java ++++ b/net/minecraft/world/entity/EntityType.java +@@ -1093,6 +1093,7 @@ public class EntityType implements FeatureElement, EntityTypeT + public EntityDimensions dimensions; + private final float spawnDimensionsScale; + private final FeatureFlagSet requiredFeatures; ++ public boolean skipRaytracingCheck = false; // DivineMC - Raytrace Entity Tracker + + private static EntityType register(ResourceKey> key, EntityType.Builder builder) { + return Registry.register(BuiltInRegistries.ENTITY_TYPE, key, builder.build(key)); +diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java +index 18b670a1e6e62c3b79281e529c89f35b16427c69..5ed70f2f427f8cccaeab494b2f5c62442c288e53 100644 +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -122,7 +122,6 @@ import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; + import net.minecraft.world.scores.PlayerTeam; + import net.minecraft.world.scores.Scoreboard; +-import net.minecraft.world.scores.Team; + import org.slf4j.Logger; + + public abstract class Player extends LivingEntity { +@@ -222,6 +221,25 @@ public abstract class Player extends LivingEntity { + public int burpDelay = 0; // Purpur - Burp delay + public boolean canPortalInstant = false; // Purpur - Add portal permission bypass + public int sixRowEnderchestSlotCount = -1; // Purpur - Barrels and enderchests 6 rows ++ // DivineMC start - Raytrace Entity Tracker ++ public dev.tr7zw.entityculling.CullTask cullTask; ++ { ++ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.retEnabled) { ++ this.cullTask = null; ++ } else { ++ final com.logisticscraft.occlusionculling.OcclusionCullingInstance culling = new com.logisticscraft.occlusionculling.OcclusionCullingInstance( ++ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retTracingDistance, ++ new dev.tr7zw.entityculling.DefaultChunkDataProvider(this.level()) ++ ); ++ ++ this.cullTask = new dev.tr7zw.entityculling.CullTask( ++ culling, this, ++ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retHitboxLimit, ++ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retCheckIntervalMs ++ ); ++ } ++ } ++ // DivineMC end - Raytrace Entity Tracker + + // CraftBukkit start + public boolean fauxSleeping; +@@ -310,6 +328,25 @@ public abstract class Player extends LivingEntity { + + @Override + public void tick() { ++ // DivineMC start - Raytrace Entity Tracker ++ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.retEnabled) { ++ if (this.cullTask != null) this.cullTask.signalStop(); ++ this.cullTask = null; ++ } else { ++ final com.logisticscraft.occlusionculling.OcclusionCullingInstance culling = new com.logisticscraft.occlusionculling.OcclusionCullingInstance( ++ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retTracingDistance, ++ new dev.tr7zw.entityculling.DefaultChunkDataProvider(this.level()) ++ ); ++ ++ this.cullTask = new dev.tr7zw.entityculling.CullTask( ++ culling, this, ++ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retHitboxLimit, ++ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retCheckIntervalMs ++ ); ++ } ++ if (this.cullTask != null) this.cullTask.setup(); ++ if (this.cullTask != null) this.cullTask.requestCullSignal(); ++ // DivineMC end - Raytrace Entity Tracker + // Purpur start - Burp delay + if (this.burpDelay > 0 && --this.burpDelay == 0) { + this.level().playSound(null, getX(), getY(), getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 1.0F, this.level().random.nextFloat() * 0.1F + 0.9F); +@@ -1467,6 +1504,7 @@ public abstract class Player extends LivingEntity { + if (this.containerMenu != null && this.hasContainerOpen()) { + this.doCloseContainer(); + } ++ if (this.cullTask != null) this.cullTask.signalStop(); // DivineMC - Raytrace Entity Tracker + } + + @Override diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/DataProvider.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/DataProvider.java new file mode 100644 index 0000000..8c3044f --- /dev/null +++ b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/DataProvider.java @@ -0,0 +1,30 @@ +package com.logisticscraft.occlusionculling; + +import com.logisticscraft.occlusionculling.util.Vec3d; + +public interface DataProvider { + /** + * Prepares the requested chunk. Returns true if the chunk is ready, false when + * not loaded. Should not reload the chunk when the x and y are the same as the + * last request! + * + * @param chunkX + * @param chunkZ + * @return + */ + boolean prepareChunk(int chunkX, int chunkZ); + + /** + * Location is inside the chunk. + * + * @param x + * @param y + * @param z + * @return + */ + boolean isOpaqueFullCube(int x, int y, int z); + + default void cleanup() { } + + default void checkingPosition(Vec3d[] targetPoints, int size, Vec3d viewerPosition) { } +} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/OcclusionCullingInstance.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/OcclusionCullingInstance.java new file mode 100644 index 0000000..f5bdb2d --- /dev/null +++ b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/OcclusionCullingInstance.java @@ -0,0 +1,513 @@ +package com.logisticscraft.occlusionculling; + +import com.logisticscraft.occlusionculling.cache.ArrayOcclusionCache; +import com.logisticscraft.occlusionculling.cache.OcclusionCache; +import com.logisticscraft.occlusionculling.util.MathUtilities; +import com.logisticscraft.occlusionculling.util.Vec3d; + +import java.util.Arrays; +import java.util.BitSet; + +public class OcclusionCullingInstance { + private static final int ON_MIN_X = 0x01; + private static final int ON_MAX_X = 0x02; + private static final int ON_MIN_Y = 0x04; + private static final int ON_MAX_Y = 0x08; + private static final int ON_MIN_Z = 0x10; + private static final int ON_MAX_Z = 0x20; + + private final int reach; + private final double aabbExpansion; + private final DataProvider provider; + private final OcclusionCache cache; + + // Reused allocated data structures + private final BitSet skipList = new BitSet(); // Grows bigger in case some mod introduces giant hitboxes + private final Vec3d[] targetPoints = new Vec3d[15]; + private final Vec3d targetPos = new Vec3d(0, 0, 0); + private final int[] cameraPos = new int[3]; + private final boolean[] dotselectors = new boolean[14]; + private boolean allowRayChecks = false; + private final int[] lastHitBlock = new int[3]; + private boolean allowWallClipping = false; + + + public OcclusionCullingInstance(int maxDistance, DataProvider provider) { + this(maxDistance, provider, new ArrayOcclusionCache(maxDistance), 0.5); + } + + public OcclusionCullingInstance(int maxDistance, DataProvider provider, OcclusionCache cache, double aabbExpansion) { + this.reach = maxDistance; + this.provider = provider; + this.cache = cache; + this.aabbExpansion = aabbExpansion; + for(int i = 0; i < targetPoints.length; i++) { + targetPoints[i] = new Vec3d(0, 0, 0); + } + } + + public boolean isAABBVisible(Vec3d aabbMin, Vec3d aabbMax, Vec3d viewerPosition) { + try { + int maxX = MathUtilities.floor(aabbMax.x + + aabbExpansion); + int maxY = MathUtilities.floor(aabbMax.y + + aabbExpansion); + int maxZ = MathUtilities.floor(aabbMax.z + + aabbExpansion); + int minX = MathUtilities.floor(aabbMin.x + - aabbExpansion); + int minY = MathUtilities.floor(aabbMin.y + - aabbExpansion); + int minZ = MathUtilities.floor(aabbMin.z + - aabbExpansion); + + cameraPos[0] = MathUtilities.floor(viewerPosition.x); + cameraPos[1] = MathUtilities.floor(viewerPosition.y); + cameraPos[2] = MathUtilities.floor(viewerPosition.z); + + Relative relX = Relative.from(minX, maxX, cameraPos[0]); + Relative relY = Relative.from(minY, maxY, cameraPos[1]); + Relative relZ = Relative.from(minZ, maxZ, cameraPos[2]); + + if(relX == Relative.INSIDE && relY == Relative.INSIDE && relZ == Relative.INSIDE) { + return true; // We are inside of the AABB, don't cull + } + + skipList.clear(); + + // Just check the cache first + int id = 0; + for (int x = minX; x <= maxX; x++) { + for (int y = minY; y <= maxY; y++) { + for (int z = minZ; z <= maxZ; z++) { + int cachedValue = getCacheValue(x, y, z); + + if (cachedValue == 1) { + // non-occluding + return true; + } + + if (cachedValue != 0) { + // was checked and it wasn't visible + skipList.set(id); + } + id++; + } + } + } + + // only after the first hit wall the cache becomes valid. + allowRayChecks = false; + + // since the cache wasn't helpfull + id = 0; + for (int x = minX; x <= maxX; x++) { + byte visibleOnFaceX = 0; + byte faceEdgeDataX = 0; + faceEdgeDataX |= (x == minX) ? ON_MIN_X : 0; + faceEdgeDataX |= (x == maxX) ? ON_MAX_X : 0; + visibleOnFaceX |= (x == minX && relX == Relative.POSITIVE) ? ON_MIN_X : 0; + visibleOnFaceX |= (x == maxX && relX == Relative.NEGATIVE) ? ON_MAX_X : 0; + for (int y = minY; y <= maxY; y++) { + byte faceEdgeDataY = faceEdgeDataX; + byte visibleOnFaceY = visibleOnFaceX; + faceEdgeDataY |= (y == minY) ? ON_MIN_Y : 0; + faceEdgeDataY |= (y == maxY) ? ON_MAX_Y : 0; + visibleOnFaceY |= (y == minY && relY == Relative.POSITIVE) ? ON_MIN_Y : 0; + visibleOnFaceY |= (y == maxY && relY == Relative.NEGATIVE) ? ON_MAX_Y : 0; + for (int z = minZ; z <= maxZ; z++) { + byte faceEdgeData = faceEdgeDataY; + byte visibleOnFace = visibleOnFaceY; + faceEdgeData |= (z == minZ) ? ON_MIN_Z : 0; + faceEdgeData |= (z == maxZ) ? ON_MAX_Z : 0; + visibleOnFace |= (z == minZ && relZ == Relative.POSITIVE) ? ON_MIN_Z : 0; + visibleOnFace |= (z == maxZ && relZ == Relative.NEGATIVE) ? ON_MAX_Z : 0; + if(skipList.get(id)) { // was checked and it wasn't visible + id++; + continue; + } + + if (visibleOnFace != 0) { + targetPos.set(x, y, z); + if (isVoxelVisible(viewerPosition, targetPos, faceEdgeData, visibleOnFace)) { + return true; + } + } + id++; + } + } + } + + return false; + } catch (Throwable t) { + // Failsafe + t.printStackTrace(); + } + return true; + } + + /** + * @param viewerPosition + * @param position + * @param faceData contains rather this Block is on the outside for a given face + * @param visibleOnFace contains rather a face should be concidered + * @return + */ + private boolean isVoxelVisible(Vec3d viewerPosition, Vec3d position, byte faceData, byte visibleOnFace) { + int targetSize = 0; + Arrays.fill(dotselectors, false); + if((visibleOnFace & ON_MIN_X) == ON_MIN_X){ + dotselectors[0] = true; + if((faceData & ~ON_MIN_X) != 0) { + dotselectors[1] = true; + dotselectors[4] = true; + dotselectors[5] = true; + } + dotselectors[8] = true; + } + if((visibleOnFace & ON_MIN_Y) == ON_MIN_Y){ + dotselectors[0] = true; + if((faceData & ~ON_MIN_Y) != 0) { + dotselectors[3] = true; + dotselectors[4] = true; + dotselectors[7] = true; + } + dotselectors[9] = true; + } + if((visibleOnFace & ON_MIN_Z) == ON_MIN_Z){ + dotselectors[0] = true; + if((faceData & ~ON_MIN_Z) != 0) { + dotselectors[1] = true; + dotselectors[4] = true; + dotselectors[5] = true; + } + dotselectors[10] = true; + } + if((visibleOnFace & ON_MAX_X) == ON_MAX_X){ + dotselectors[4] = true; + if((faceData & ~ON_MAX_X) != 0) { + dotselectors[5] = true; + dotselectors[6] = true; + dotselectors[7] = true; + } + dotselectors[11] = true; + } + if((visibleOnFace & ON_MAX_Y) == ON_MAX_Y){ + dotselectors[1] = true; + if((faceData & ~ON_MAX_Y) != 0) { + dotselectors[2] = true; + dotselectors[5] = true; + dotselectors[6] = true; + } + dotselectors[12] = true; + } + if((visibleOnFace & ON_MAX_Z) == ON_MAX_Z){ + dotselectors[2] = true; + if((faceData & ~ON_MAX_Z) != 0) { + dotselectors[3] = true; + dotselectors[6] = true; + dotselectors[7] = true; + } + dotselectors[13] = true; + } + + if (dotselectors[0])targetPoints[targetSize++].setAdd(position, 0.05, 0.05, 0.05); + if (dotselectors[1])targetPoints[targetSize++].setAdd(position, 0.05, 0.95, 0.05); + if (dotselectors[2])targetPoints[targetSize++].setAdd(position, 0.05, 0.95, 0.95); + if (dotselectors[3])targetPoints[targetSize++].setAdd(position, 0.05, 0.05, 0.95); + if (dotselectors[4])targetPoints[targetSize++].setAdd(position, 0.95, 0.05, 0.05); + if (dotselectors[5])targetPoints[targetSize++].setAdd(position, 0.95, 0.95, 0.05); + if (dotselectors[6])targetPoints[targetSize++].setAdd(position, 0.95, 0.95, 0.95); + if (dotselectors[7])targetPoints[targetSize++].setAdd(position, 0.95, 0.05, 0.95); + // middle points + if (dotselectors[8])targetPoints[targetSize++].setAdd(position, 0.05, 0.5, 0.5); + if (dotselectors[9])targetPoints[targetSize++].setAdd(position, 0.5, 0.05, 0.5); + if (dotselectors[10])targetPoints[targetSize++].setAdd(position, 0.5, 0.5, 0.05); + if (dotselectors[11])targetPoints[targetSize++].setAdd(position, 0.95, 0.5, 0.5); + if (dotselectors[12])targetPoints[targetSize++].setAdd(position, 0.5, 0.95, 0.5); + if (dotselectors[13])targetPoints[targetSize++].setAdd(position, 0.5, 0.5, 0.95); + + return isVisible(viewerPosition, targetPoints, targetSize); + } + + private boolean rayIntersection(int[] b, Vec3d rayOrigin, Vec3d rayDir) { + Vec3d rInv = new Vec3d(1, 1, 1).div(rayDir); + + double t1 = (b[0] - rayOrigin.x) * rInv.x; + double t2 = (b[0] + 1 - rayOrigin.x) * rInv.x; + double t3 = (b[1] - rayOrigin.y) * rInv.y; + double t4 = (b[1] + 1 - rayOrigin.y) * rInv.y; + double t5 = (b[2] - rayOrigin.z) * rInv.z; + double t6 = (b[2] + 1 - rayOrigin.z) * rInv.z; + + double tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6)); + double tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6)); + + // if tmax > 0, ray (line) is intersecting AABB, but the whole AABB is behind us + if (tmax > 0) { + return false; + } + + // if tmin > tmax, ray doesn't intersect AABB + if (tmin > tmax) { + return false; + } + + return true; + } + + /** + * returns the grid cells that intersect with this Vec3d
+ *
http://playtechs.blogspot.de/2007/03/raytracing-on-grid.html + *

+ * Caching assumes that all Vec3d's are inside the same block + */ + private boolean isVisible(Vec3d start, Vec3d[] targets, int size) { + // start cell coordinate + int x = cameraPos[0]; + int y = cameraPos[1]; + int z = cameraPos[2]; + + for (int v = 0; v < size; v++) { + // ray-casting target + Vec3d target = targets[v]; + + double relativeX = start.x - target.getX(); + double relativeY = start.y - target.getY(); + double relativeZ = start.z - target.getZ(); + + if(allowRayChecks && rayIntersection(lastHitBlock, start, new Vec3d(relativeX, relativeY, relativeZ).normalize())) { + continue; + } + + // horizontal and vertical cell amount spanned + double dimensionX = Math.abs(relativeX); + double dimensionY = Math.abs(relativeY); + double dimensionZ = Math.abs(relativeZ); + + // distance between horizontal intersection points with cell border as a + // fraction of the total Vec3d length + double dimFracX = 1f / dimensionX; + // distance between vertical intersection points with cell border as a fraction + // of the total Vec3d length + double dimFracY = 1f / dimensionY; + double dimFracZ = 1f / dimensionZ; + + // total amount of intersected cells + int intersectCount = 1; + + // 1, 0 or -1 + // determines the direction of the next cell (horizontally / vertically) + int x_inc, y_inc, z_inc; + + // the distance to the next horizontal / vertical intersection point with a cell + // border as a fraction of the total Vec3d length + double t_next_y, t_next_x, t_next_z; + + if (dimensionX == 0f) { + x_inc = 0; + t_next_x = dimFracX; // don't increment horizontally because the Vec3d is perfectly vertical + } else if (target.x > start.x) { + x_inc = 1; // target point is horizontally greater than starting point so increment every + // step by 1 + intersectCount += MathUtilities.floor(target.x) - x; // increment total amount of intersecting cells + t_next_x = (float) ((x + 1 - start.x) * dimFracX); // calculate the next horizontal + // intersection + // point based on the position inside + // the first cell + } else { + x_inc = -1; // target point is horizontally smaller than starting point so reduce every step + // by 1 + intersectCount += x - MathUtilities.floor(target.x); // increment total amount of intersecting cells + t_next_x = (float) ((start.x - x) + * dimFracX); // calculate the next horizontal + // intersection point + // based on the position inside + // the first cell + } + + if (dimensionY == 0f) { + y_inc = 0; + t_next_y = dimFracY; // don't increment vertically because the Vec3d is perfectly horizontal + } else if (target.y > start.y) { + y_inc = 1; // target point is vertically greater than starting point so increment every + // step by 1 + intersectCount += MathUtilities.floor(target.y) - y; // increment total amount of intersecting cells + t_next_y = (float) ((y + 1 - start.y) + * dimFracY); // calculate the next vertical + // intersection + // point based on the position inside + // the first cell + } else { + y_inc = -1; // target point is vertically smaller than starting point so reduce every step + // by 1 + intersectCount += y - MathUtilities.floor(target.y); // increment total amount of intersecting cells + t_next_y = (float) ((start.y - y) + * dimFracY); // calculate the next vertical intersection + // point + // based on the position inside + // the first cell + } + + if (dimensionZ == 0f) { + z_inc = 0; + t_next_z = dimFracZ; // don't increment vertically because the Vec3d is perfectly horizontal + } else if (target.z > start.z) { + z_inc = 1; // target point is vertically greater than starting point so increment every + // step by 1 + intersectCount += MathUtilities.floor(target.z) - z; // increment total amount of intersecting cells + t_next_z = (float) ((z + 1 - start.z) + * dimFracZ); // calculate the next vertical + // intersection + // point based on the position inside + // the first cell + } else { + z_inc = -1; // target point is vertically smaller than starting point so reduce every step + // by 1 + intersectCount += z - MathUtilities.floor(target.z); // increment total amount of intersecting cells + t_next_z = (float) ((start.z - z) + * dimFracZ); // calculate the next vertical intersection + // point + // based on the position inside + // the first cell + } + + boolean finished = stepRay(start, x, y, z, + dimFracX, dimFracY, dimFracZ, intersectCount, x_inc, y_inc, + z_inc, t_next_y, t_next_x, t_next_z); + provider.cleanup(); + if (finished) { + cacheResult(targets[0], true); + return true; + } else { + allowRayChecks = true; + } + } + cacheResult(targets[0], false); + return false; + } + + private boolean stepRay(Vec3d start, int currentX, int currentY, + int currentZ, double distInX, double distInY, + double distInZ, int n, int x_inc, int y_inc, + int z_inc, double t_next_y, double t_next_x, + double t_next_z) { + allowWallClipping = true; // initially allow rays to go through walls till they are on the outside + // iterate through all intersecting cells (n times) + for (; n > 1; n--) { // n-1 times because we don't want to check the last block + // towards - where from + + + // get cached value, 0 means uncached (default) + int cVal = getCacheValue(currentX, currentY, currentZ); + + if (cVal == 2 && !allowWallClipping) { + // block cached as occluding, stop ray + lastHitBlock[0] = currentX; + lastHitBlock[1] = currentY; + lastHitBlock[2] = currentZ; + return false; + } + + if (cVal == 0) { + // save current cell + int chunkX = currentX >> 4; + int chunkZ = currentZ >> 4; + + if (!provider.prepareChunk(chunkX, chunkZ)) { // Chunk not ready + return false; + } + + if (provider.isOpaqueFullCube(currentX, currentY, currentZ)) { + if (!allowWallClipping) { + cache.setLastHidden(); + lastHitBlock[0] = currentX; + lastHitBlock[1] = currentY; + lastHitBlock[2] = currentZ; + return false; + } + } else { + // outside of wall, now clipping is not allowed + allowWallClipping = false; + cache.setLastVisible(); + } + } + + if(cVal == 1) { + // outside of wall, now clipping is not allowed + allowWallClipping = false; + } + + + if (t_next_y < t_next_x && t_next_y < t_next_z) { // next cell is upwards/downwards because the distance to + // the next vertical + // intersection point is smaller than to the next horizontal intersection point + currentY += y_inc; // move up/down + t_next_y += distInY; // update next vertical intersection point + } else if (t_next_x < t_next_y && t_next_x < t_next_z) { // next cell is right/left + currentX += x_inc; // move right/left + t_next_x += distInX; // update next horizontal intersection point + } else { + currentZ += z_inc; // move right/left + t_next_z += distInZ; // update next horizontal intersection point + } + + } + return true; + } + + // -1 = invalid location, 0 = not checked yet, 1 = visible, 2 = occluding + private int getCacheValue(int x, int y, int z) { + x -= cameraPos[0]; + y -= cameraPos[1]; + z -= cameraPos[2]; + if (Math.abs(x) > reach - 2 || Math.abs(y) > reach - 2 + || Math.abs(z) > reach - 2) { + return -1; + } + + // check if target is already known + return cache.getState(x + reach, y + reach, z + reach); + } + + + private void cacheResult(int x, int y, int z, boolean result) { + int cx = x - cameraPos[0] + reach; + int cy = y - cameraPos[1] + reach; + int cz = z - cameraPos[2] + reach; + if (result) { + cache.setVisible(cx, cy, cz); + } else { + cache.setHidden(cx, cy, cz); + } + } + + private void cacheResult(Vec3d vector, boolean result) { + int cx = MathUtilities.floor(vector.x) - cameraPos[0] + reach; + int cy = MathUtilities.floor(vector.y) - cameraPos[1] + reach; + int cz = MathUtilities.floor(vector.z) - cameraPos[2] + reach; + if (result) { + cache.setVisible(cx, cy, cz); + } else { + cache.setHidden(cx, cy, cz); + } + } + + public void resetCache() { + this.cache.resetCache(); + } + + private enum Relative { + INSIDE, POSITIVE, NEGATIVE; + + public static Relative from(int min, int max, int pos) { + if (max > pos && min > pos) { + return POSITIVE; + } else if (min < pos && max < pos) { + return NEGATIVE; + } + return INSIDE; + } + } +} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/ArrayOcclusionCache.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/ArrayOcclusionCache.java new file mode 100644 index 0000000..1b7d1c9 --- /dev/null +++ b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/ArrayOcclusionCache.java @@ -0,0 +1,55 @@ +package com.logisticscraft.occlusionculling.cache; + +import java.util.Arrays; + +public class ArrayOcclusionCache implements OcclusionCache { + private final int reachX2; + private final byte[] cache; + private int positionKey; + private int entry; + private int offset; + + public ArrayOcclusionCache(int reach) { + this.reachX2 = reach * 2; + this.cache = new byte[(reachX2 * reachX2 * reachX2) / 4]; + } + + @Override + public void resetCache() { + Arrays.fill(cache, (byte) 0); + } + + @Override + public void setVisible(int x, int y, int z) { + positionKey = x + y * reachX2 + z * reachX2 * reachX2; + entry = positionKey / 4; + offset = (positionKey % 4) * 2; + cache[entry] |= 1 << offset; + } + + @Override + public void setHidden(int x, int y, int z) { + positionKey = x + y * reachX2 + z * reachX2 * reachX2; + entry = positionKey / 4; + offset = (positionKey % 4) * 2; + cache[entry] |= 1 << offset + 1; + } + + @Override + public int getState(int x, int y, int z) { + positionKey = x + y * reachX2 + z * reachX2 * reachX2; + entry = positionKey / 4; + offset = (positionKey % 4) * 2; + return cache[entry] >> offset & 3; + } + + @Override + public void setLastVisible() { + cache[entry] |= 1 << offset; + } + + @Override + public void setLastHidden() { + cache[entry] |= 1 << offset + 1; + } +} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/OcclusionCache.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/OcclusionCache.java new file mode 100644 index 0000000..d939357 --- /dev/null +++ b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/OcclusionCache.java @@ -0,0 +1,15 @@ +package com.logisticscraft.occlusionculling.cache; + +public interface OcclusionCache { + void resetCache(); + + void setVisible(int x, int y, int z); + + void setHidden(int x, int y, int z); + + int getState(int x, int y, int z); + + void setLastHidden(); + + void setLastVisible(); +} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/MathUtilities.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/MathUtilities.java new file mode 100644 index 0000000..57572ac --- /dev/null +++ b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/MathUtilities.java @@ -0,0 +1,19 @@ +package com.logisticscraft.occlusionculling.util; + +public final class MathUtilities { + private MathUtilities() { } + + public static int floor(double d) { + int i = (int) d; + return d < (double) i ? i - 1 : i; + } + + public static int fastFloor(double d) { + return (int) (d + 1024.0) - 1024; + } + + public static int ceil(double d) { + int i = (int) d; + return d > (double) i ? i + 1 : i; + } +} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/Vec3d.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/Vec3d.java new file mode 100644 index 0000000..28e7ba4 --- /dev/null +++ b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/Vec3d.java @@ -0,0 +1,85 @@ +package com.logisticscraft.occlusionculling.util; + +public class Vec3d { + public double x; + public double y; + public double z; + + public Vec3d(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + public double getX() { + return x; + } + + public double getY() { + return y; + } + + public double getZ() { + return z; + } + + public void set(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + public void setAdd(Vec3d vec, double x, double y, double z) { + this.x = vec.x + x; + this.y = vec.y + y; + this.z = vec.z + z; + } + + public Vec3d div(Vec3d rayDir) { + this.x /= rayDir.x; + this.z /= rayDir.z; + this.y /= rayDir.y; + return this; + } + + public Vec3d normalize() { + double mag = Math.sqrt(x*x+y*y+z*z); + this.x /= mag; + this.y /= mag; + this.z /= mag; + return this; + } + + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof Vec3d)) { + return false; + } + Vec3d vec3d = (Vec3d) other; + if (Double.compare(vec3d.x, x) != 0) { + return false; + } + if (Double.compare(vec3d.y, y) != 0) { + return false; + } + return Double.compare(vec3d.z, z) == 0; + } + + @Override + public int hashCode() { + long l = Double.doubleToLongBits(x); + int i = (int) (l ^ l >>> 32); + l = Double.doubleToLongBits(y); + i = 31 * i + (int) (l ^ l >>> 32); + l = Double.doubleToLongBits(z); + i = 31 * i + (int) (l ^ l >>> 32); + return i; + } + + @Override + public String toString() { + return "(" + x + ", " + y + ", " + z + ")"; + } +} diff --git a/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java b/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java new file mode 100644 index 0000000..7129673 --- /dev/null +++ b/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java @@ -0,0 +1,146 @@ +package dev.tr7zw.entityculling; + +import ca.spottedleaf.moonrise.common.util.TickThread; +import com.logisticscraft.occlusionculling.OcclusionCullingInstance; +import com.logisticscraft.occlusionculling.util.Vec3d; +import dev.tr7zw.entityculling.versionless.access.Cullable; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.bxteam.divinemc.config.DivineConfig; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class CullTask implements Runnable { + private volatile boolean requestCull = false; + private volatile boolean scheduleNext = true; + private volatile boolean inited = false; + + private final OcclusionCullingInstance culling; + private final Player checkTarget; + + private final int hitboxLimit; + + public long lastCheckedTime = 0; + + private final Vec3d lastPos = new Vec3d(0, 0, 0); + private final Vec3d aabbMin = new Vec3d(0, 0, 0); + private final Vec3d aabbMax = new Vec3d(0, 0, 0); + + private static final Executor backgroundWorker = Executors.newCachedThreadPool(task -> { + final TickThread worker = new TickThread("EntityCulling") { + @Override + public void run() { + task.run(); + } + }; + + worker.setDaemon(true); + + return worker; + }); + + private final Executor worker; + + public CullTask( + OcclusionCullingInstance culling, + Player checkTarget, + int hitboxLimit, + long checkIntervalMs + ) { + this.culling = culling; + this.checkTarget = checkTarget; + this.hitboxLimit = hitboxLimit; + this.worker = CompletableFuture.delayedExecutor(checkIntervalMs, TimeUnit.MILLISECONDS, backgroundWorker); + } + + public void requestCullSignal() { + this.requestCull = true; + } + + public void signalStop() { + this.scheduleNext = false; + } + + public void setup() { + if (!this.inited) + this.inited = true; + else + return; + this.worker.execute(this); + } + + @Override + public void run() { + try { + if (this.checkTarget.tickCount > 10) { + Vec3 cameraMC = this.checkTarget.getEyePosition(0); + if (requestCull || !(cameraMC.x == lastPos.x && cameraMC.y == lastPos.y && cameraMC.z == lastPos.z)) { + long start = System.currentTimeMillis(); + + requestCull = false; + + lastPos.set(cameraMC.x, cameraMC.y, cameraMC.z); + culling.resetCache(); + + cullEntities(cameraMC, lastPos); + + lastCheckedTime = (System.currentTimeMillis() - start); + } + } + } finally { + if (this.scheduleNext) { + this.worker.execute(this); + } + } + } + + private void cullEntities(Vec3 cameraMC, Vec3d camera) { + for (Entity entity : this.checkTarget.level().getEntities().getAll()) { + if (!(entity instanceof Cullable cullable)) { + continue; + } + + if (entity.getType().skipRaytracingCheck) { + continue; + } + + if (!cullable.isForcedVisible()) { + if (entity.isCurrentlyGlowing() || isSkippableArmorstand(entity)) { + cullable.setCulled(false); + continue; + } + + if (!entity.position().closerThan(cameraMC, DivineConfig.MiscCategory.retTracingDistance)) { + cullable.setCulled(false); + continue; + } + + AABB boundingBox = entity.getBoundingBox(); + if (boundingBox.getXsize() > hitboxLimit || boundingBox.getYsize() > hitboxLimit + || boundingBox.getZsize() > hitboxLimit) { + cullable.setCulled(false); + continue; + } + + aabbMin.set(boundingBox.minX, boundingBox.minY, boundingBox.minZ); + aabbMax.set(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ); + + boolean visible = culling.isAABBVisible(aabbMin, aabbMax, camera); + + cullable.setCulled(!visible); + } + } + } + + private boolean isSkippableArmorstand(Entity entity) { + if (!DivineConfig.MiscCategory.retSkipMarkerArmorStands) return false; + + return entity instanceof ArmorStand && entity.isInvisible(); + } +} diff --git a/divinemc-server/src/main/java/dev/tr7zw/entityculling/DefaultChunkDataProvider.java b/divinemc-server/src/main/java/dev/tr7zw/entityculling/DefaultChunkDataProvider.java new file mode 100644 index 0000000..fe8b71a --- /dev/null +++ b/divinemc-server/src/main/java/dev/tr7zw/entityculling/DefaultChunkDataProvider.java @@ -0,0 +1,41 @@ +package dev.tr7zw.entityculling; + +import com.logisticscraft.occlusionculling.DataProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.chunk.ChunkAccess; + +public class DefaultChunkDataProvider implements DataProvider { + private final Level level; + + public DefaultChunkDataProvider(Level level) { + this.level = level; + } + + @Override + public boolean prepareChunk(int chunkX, int chunkZ) { + return this.level.getChunkIfLoaded(chunkX, chunkZ) != null; + } + + @Override + public boolean isOpaqueFullCube(int x, int y, int z) { + BlockPos pos = new BlockPos(x, y, z); + + final ChunkAccess access = this.level.getChunkIfLoaded(pos); + if (access == null) { + return false; + } + + if (this.level.isOutsideBuildHeight(pos)) { + return Blocks.VOID_AIR.defaultBlockState().isSolidRender(); + } else { + return access.getBlockState(pos).isSolidRender(); + } + } + + @Override + public void cleanup() { + DataProvider.super.cleanup(); + } +} diff --git a/divinemc-server/src/main/java/dev/tr7zw/entityculling/versionless/access/Cullable.java b/divinemc-server/src/main/java/dev/tr7zw/entityculling/versionless/access/Cullable.java new file mode 100644 index 0000000..2d7f312 --- /dev/null +++ b/divinemc-server/src/main/java/dev/tr7zw/entityculling/versionless/access/Cullable.java @@ -0,0 +1,15 @@ +package dev.tr7zw.entityculling.versionless.access; + +public interface Cullable { + public void setTimeout(); + + public boolean isForcedVisible(); + + public void setCulled(boolean value); + + public boolean isCulled(); + + public void setOutOfCamera(boolean value); + + public boolean isOutOfCamera(); +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 36bfc85..a220012 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -571,6 +571,13 @@ public class DivineConfig { public static String logLevel = "WARN"; public static boolean onlyLogThrown = true; + // Raytrace Entity Tracker + public static boolean retEnabled = false; + public static boolean retSkipMarkerArmorStands = true; + public static int retCheckIntervalMs = 10; + public static int retTracingDistance = 48; + public static int retHitboxLimit = 50; + // Old features public static boolean copperBulb1gt = false; public static boolean crafter1gt = false; @@ -579,6 +586,7 @@ public class DivineConfig { secureSeed(); lagCompensation(); sentrySettings(); + ret(); oldFeatures(); } @@ -615,6 +623,19 @@ public class DivineConfig { if (sentryDsn != null && !sentryDsn.isBlank()) gg.pufferfish.pufferfish.sentry.SentryManager.init(Level.getLevel(logLevel)); } + private static void ret() { + retEnabled = getBoolean(ConfigCategory.MISC.key("raytrace-entity-tracker.enabled"), retEnabled, + "Raytrace Entity Tracker uses async ray-tracing to untrack entities players cannot see. Implementation of EntityCulling mod by tr7zw."); + retSkipMarkerArmorStands = getBoolean(ConfigCategory.MISC.key("raytrace-entity-tracker.skip-marker-armor-stands"), retSkipMarkerArmorStands, + "Whether to skip tracing entities with marker armor stand"); + retCheckIntervalMs = getInt(ConfigCategory.MISC.key("raytrace-entity-tracker.check-interval-ms"), retCheckIntervalMs, + "The interval in milliseconds between each trace."); + retTracingDistance = getInt(ConfigCategory.MISC.key("raytrace-entity-tracker.tracing-distance"), retTracingDistance, + "The distance in blocks to track entities in the raytrace entity tracker."); + retHitboxLimit = getInt(ConfigCategory.MISC.key("raytrace-entity-tracker.hitbox-limit"), retHitboxLimit, + "The maximum size of bounding box to trace."); + } + private static void oldFeatures() { copperBulb1gt = getBoolean(ConfigCategory.MISC.key("old-features.copper-bulb-1gt"), copperBulb1gt, "Whether to delay the copper lamp by 1 tick when the redstone signal changes."); From 626958c7dd6c1f5be65f22f7b64a4648aebf69c0 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 05:23:35 +0300 Subject: [PATCH 22/67] new Experimental annotation for config --- .../bxteam/divinemc/config/DivineConfig.java | 41 ++++++++++++++++++- .../config/annotations/Experimental.java | 12 ++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/config/annotations/Experimental.java diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index a220012..5c19909 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -9,6 +9,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; +import org.bxteam.divinemc.config.annotations.Experimental; import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy; import org.jetbrains.annotations.Nullable; import org.simpleyaml.configuration.comments.CommentType; @@ -17,6 +18,7 @@ import org.simpleyaml.exceptions.InvalidConfigurationException; import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -71,6 +73,7 @@ public class DivineConfig { config.options().header(HEADER); readConfig(DivineConfig.class, null); + checkExperimentalFeatures(); } static void readConfig(Class clazz, Object instance) throws IOException { @@ -188,6 +191,7 @@ public class DivineConfig { public static class AsyncCategory { // Parallel world ticking settings + @Experimental("Parallel World Ticking") public static boolean enableParallelWorldTicking = false; public static int parallelThreadCount = 4; public static boolean logContainerCreationStacktraces = false; @@ -196,6 +200,7 @@ public class DivineConfig { public static boolean usePerWorldTpsBar = true; // Regionized chunk ticking + @Experimental("Regionized Chunk Ticking") public static boolean enableRegionizedChunkTicking = false; public static int regionizedChunkTickingExecutorThreadCount = 4; public static boolean regionizedChunkTickingUseVirtualThreads = false; @@ -262,8 +267,6 @@ public class DivineConfig { LOGGER.warn("Invalid regionized chunk ticking thread count: {}, resetting to default (5)", regionizedChunkTickingExecutorThreadCount); regionizedChunkTickingExecutorThreadCount = 5; } - - if (enableRegionizedChunkTicking) LOGGER.warn("You have enabled Regionized Chunk Ticking. This feature is an experimental, and may not work as expected. Please report any issues you encounter to the BX Team Discord server"); } private static void asyncPathfinding() { @@ -572,6 +575,7 @@ public class DivineConfig { public static boolean onlyLogThrown = true; // Raytrace Entity Tracker + @Experimental("Raytrace Entity Tracker") public static boolean retEnabled = false; public static boolean retSkipMarkerArmorStands = true; public static int retCheckIntervalMs = 10; @@ -690,4 +694,37 @@ public class DivineConfig { "Message to send to the client when they are disconnected for not having No Chat Reports"); } } + + private static void checkExperimentalFeatures() { + List enabledExperimentalFeatures = new ArrayList<>(); + + Class[] innerClasses = DivineConfig.class.getDeclaredClasses(); + for (Class innerClass : innerClasses) { + if (Modifier.isStatic(innerClass.getModifiers())) { + Field[] fields = innerClass.getDeclaredFields(); + for (Field field : fields) { + if (field.isAnnotationPresent(Experimental.class) && + field.getType() == boolean.class && + Modifier.isStatic(field.getModifiers()) && + Modifier.isPublic(field.getModifiers())) { + try { + field.setAccessible(true); + boolean value = field.getBoolean(null); + if (value) { + Experimental annotation = field.getAnnotation(Experimental.class); + String featureName = annotation.value(); + enabledExperimentalFeatures.add(featureName); + } + } catch (IllegalAccessException e) { + LOGGER.debug("Failed to access field {}", field.getName(), e); + } + } + } + } + } + + if (!enabledExperimentalFeatures.isEmpty()) { + LOGGER.warn("You have the following experimental features enabled: [{}]. Please proceed with caution!", String.join(", ", enabledExperimentalFeatures)); + } + } } diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/annotations/Experimental.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/annotations/Experimental.java new file mode 100644 index 0000000..d0ffc91 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/annotations/Experimental.java @@ -0,0 +1,12 @@ +package org.bxteam.divinemc.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Experimental { + String value(); +} From f84d8cc1de47c22edc4d9fbdbe66cc05fed4f373 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 05:26:19 +0300 Subject: [PATCH 23/67] remove resendchunks for now --- .../divinemc/command/DivineCommand.java | 2 - .../subcommands/ResendChunksCommand.java | 51 ------------------- 2 files changed, 53 deletions(-) delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/command/subcommands/ResendChunksCommand.java diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/command/DivineCommand.java b/divinemc-server/src/main/java/org/bxteam/divinemc/command/DivineCommand.java index a2ca513..2a16973 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/command/DivineCommand.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/command/DivineCommand.java @@ -28,14 +28,12 @@ public final class DivineCommand extends Command { private static final DivineSubCommand MSPT_SUBCOMMAND = new MSPTCommand(); private static final DivineSubCommand RELOAD_SUBCOMMAND = new ReloadCommand(); - private static final DivineSubCommand RESEND_CHUNKS_SUBCOMMAND = new ResendChunksCommand(); private static final DivineSubCommand VERSION_SUBCOMMAND = new VersionCommand(); private static final Map SUBCOMMANDS = Util.make(() -> { final Map, DivineSubCommand> commands = new HashMap<>(); commands.put(Set.of(MSPTCommand.LITERAL_ARGUMENT), MSPT_SUBCOMMAND); commands.put(Set.of(ReloadCommand.LITERAL_ARGUMENT), RELOAD_SUBCOMMAND); - commands.put(Set.of(ResendChunksCommand.LITERAL_ARGUMENT), RESEND_CHUNKS_SUBCOMMAND); commands.put(Set.of(VersionCommand.LITERAL_ARGUMENT), VERSION_SUBCOMMAND); return commands.entrySet().stream() diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/command/subcommands/ResendChunksCommand.java b/divinemc-server/src/main/java/org/bxteam/divinemc/command/subcommands/ResendChunksCommand.java deleted file mode 100644 index 71e89a1..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/command/subcommands/ResendChunksCommand.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bxteam.divinemc.command.subcommands; - -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.network.PlayerChunkSender; -import net.minecraft.world.level.ChunkPos; -import org.bukkit.Chunk; -import org.bukkit.command.CommandSender; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.permissions.PermissionDefault; -import org.bxteam.divinemc.command.DivineCommand; -import org.bxteam.divinemc.command.DivineSubCommandPermission; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.framework.qual.DefaultQualifier; -import org.jetbrains.annotations.NotNull; -import java.util.stream.Collectors; - -@DefaultQualifier(NonNull.class) -public final class ResendChunksCommand extends DivineSubCommandPermission { - public static final String LITERAL_ARGUMENT = "resendchunks"; - public static final String PERM = DivineCommand.BASE_PERM + "." + LITERAL_ARGUMENT; - - public ResendChunksCommand() { - super(PERM, PermissionDefault.TRUE); - } - - @Override - public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { - if (sender instanceof Player player) { - final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - PlayerChunkSender chunkSender = serverPlayer.connection.chunkSender; - int resent = 0; - - for (ChunkPos chunkPos : serverPlayer.getBukkitEntity().getSentChunks().stream().map(ResendChunksCommand::bukkitChunk2ChunkPos).collect(Collectors.toSet())) { - chunkSender.dropChunk(serverPlayer, chunkPos); - PlayerChunkSender.sendChunk(serverPlayer.connection, serverPlayer.level(), serverPlayer.level().getChunk(chunkPos.x, chunkPos.z)); - resent++; - } - serverPlayer.sendSystemMessage(Component.literal("Resent " + resent + " chunks to client")); - } else { - sender.sendMessage("Only a player can execute this command."); - } - - return true; - } - - public static @NotNull ChunkPos bukkitChunk2ChunkPos(@NotNull Chunk chunk) { - return new ChunkPos(chunk.getX(), chunk.getZ()); - } -} From 19490233ab4e207d608e9d93d4038e481bd5f633 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 16:20:21 +0300 Subject: [PATCH 24/67] some config updates --- .../features/0002-Configuration.patch | 11 ++---- ...03-Completely-remove-Mojang-profiler.patch | 8 ++--- .../0010-Pufferfish-SIMD-support.patch | 4 +-- .../0064-Implement-NoChatReports.patch | 4 +-- ...-SparklyPaper-Parallel-world-ticking.patch | 6 ++-- ...-Disable-offline-warn-if-using-proxy.patch | 4 +-- .../features/0002-Configuration.patch | 14 +++----- .../features/0016-Implement-Secure-Seed.patch | 4 +-- .../command/subcommands/ReloadCommand.java | 6 +--- .../bxteam/divinemc/config/DivineConfig.java | 35 ++++++++++++------- 10 files changed, 45 insertions(+), 51 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0002-Configuration.patch b/divinemc-server/minecraft-patches/features/0002-Configuration.patch index 8ce8048..298d176 100644 --- a/divinemc-server/minecraft-patches/features/0002-Configuration.patch +++ b/divinemc-server/minecraft-patches/features/0002-Configuration.patch @@ -5,20 +5,15 @@ Subject: [PATCH] Configuration diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 670553243d26e2faab8a21f099a846d4d1df7927..9a36ad8112cc4a4d5c4fefcd3b4bf3c48d9d40ee 100644 +index 670553243d26e2faab8a21f099a846d4d1df7927..329aeeafd51aee4da289b70ff68cdfe5401cc91a 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -193,6 +193,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -193,6 +193,10 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface } org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur end - Purpur config files + // DivineMC start - Configuration -+ try { -+ org.bxteam.divinemc.config.DivineConfig.init((java.io.File) options.valueOf("divinemc-settings")); -+ } catch (Exception e) { -+ DedicatedServer.LOGGER.error("Unable to load DivineMC configuration", e); -+ return false; -+ } ++ org.bxteam.divinemc.config.DivineConfig.init((java.io.File) options.valueOf("divinemc-settings")); + org.bxteam.divinemc.command.DivineCommands.registerCommands(this); + // DivineMC end - Configuration com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now diff --git a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch index ca48538..160c8d5 100644 --- a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch +++ b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch @@ -1067,10 +1067,10 @@ index b10cb4a73df58a5fe64e88868733ba41616f59e4..9f9cbe6056f8a4eeca64c40872d7403b + // DivineMC end - Completely remove Mojang profiler } diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 9a36ad8112cc4a4d5c4fefcd3b4bf3c48d9d40ee..7aefb6a81d5f7f5431f3d67a096a93b036bbbd1d 100644 +index 329aeeafd51aee4da289b70ff68cdfe5401cc91a..653988aed936761385f245c520cc9521351664bf 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -795,12 +795,6 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -790,12 +790,6 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface return this.settings.getProperties().serverResourcePackInfo; } @@ -5015,7 +5015,7 @@ index fa06ecacc27f619853c8db76d909ab4ba75dc529..345d4b80bd4383e0fb66d744d87bc8ef // Paper start - Add mobcaps commands diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 1d3b16d3f60a394fe69e10ef1bb6052bb937070a..d0c4d63320fb5f58c43b38ebc333e9a7be487a5d 100644 +index b80924fbe054b00fe5117df896358e330f41e993..1669c21534a453c9cf16b992df7a6bf276dea887 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java @@ -13,8 +13,6 @@ import net.minecraft.Util; @@ -5039,7 +5039,7 @@ index 1d3b16d3f60a394fe69e10ef1bb6052bb937070a..d0c4d63320fb5f58c43b38ebc333e9a7 if (this.fire) { diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index 7425e8d6b352718f80e1e741329e28c5da80fcce..d11373d6a88f7b3baaf0e04d4f6e0d3837e2ba3b 100644 +index 75578e6ed7233a03d9b6cd3c6d3997f1c6148392..b88254fb3c12b99684c6ede1ae8a6671ffbe9ad6 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -24,8 +24,6 @@ import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; diff --git a/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch b/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch index a849a7e..ef6ab18 100644 --- a/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch +++ b/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch @@ -7,10 +7,10 @@ Original license: GPL v3 Original project: https://github.com/pufferfish-gg/Pufferfish diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 7aefb6a81d5f7f5431f3d67a096a93b036bbbd1d..7ac82a49e3c64d1a41a2870c5cf9900812329a57 100644 +index 653988aed936761385f245c520cc9521351664bf..f963be0d96a54a9077d2d66e9abe73ba8484d653 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -204,6 +204,26 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -199,6 +199,26 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface // DivineMC end - Configuration com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now diff --git a/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch b/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch index 8b8f786..f5a2a51 100644 --- a/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch +++ b/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch @@ -206,10 +206,10 @@ index a491be4250de3199c3e1aa9e5482b568692bd2f5..c88826db76c28c536e6c36c5592d69c1 private static final String PREFIX = "data:image/png;base64,"; public static final Codec CODEC = Codec.STRING.comapFlatMap(string -> { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 7ac82a49e3c64d1a41a2870c5cf9900812329a57..978934f81ba023d7565d2e66c51f6ca249510702 100644 +index f963be0d96a54a9077d2d66e9abe73ba8484d653..efe1e50af314c4b8f6b30c7eb0a8dd14aec327a9 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -629,6 +629,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -624,6 +624,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @Override public boolean enforceSecureProfile() { diff --git a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch index ae69f2c..d40fc8e 100644 --- a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch @@ -333,10 +333,10 @@ index 10e5469df1800bcdfb3f8cb4045ee25a4bafc58c..8efed0ffdc906b6c1ba054831e481f53 } } else if (this.visible.remove(advancementHolder)) { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 978934f81ba023d7565d2e66c51f6ca249510702..13d85eb366a070bfd6723088412f51af07892362 100644 +index efe1e50af314c4b8f6b30c7eb0a8dd14aec327a9..41900b602d763fdd1f393e29ef6c54ae2694d7bd 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -224,6 +224,13 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -219,6 +219,13 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface } // DivineMC end - Pufferfish SIMD @@ -1343,7 +1343,7 @@ index d23f255de9208f42125fa358a9e8194c984fe4d3..92e9bc9ba577474ca1108b8d06157395 // CraftBukkit end } diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index cf2ff202103fde0607e4dacef1a976c36b7840ef..8ea69a995c8572ed14cacaef0f53596c748dace6 100644 +index 6f25be39103cd0bb26bc365d9599b9846c6fe133..24f13e2b0b694ff4dd01aeea876ef874f1828304 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -365,6 +365,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p diff --git a/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch b/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch index 51445a0..f603014 100644 --- a/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch +++ b/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Disable offline warn if using proxy diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 13d85eb366a070bfd6723088412f51af07892362..bdb37afb8f30d19726c4775e1eaa8c1dabacd3a7 100644 +index 41900b602d763fdd1f393e29ef6c54ae2694d7bd..0e66aa733dd9b0c23ef01bb38243a0cab13d9ecf 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -311,7 +311,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -306,7 +306,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord"; String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/"; // Paper end - Add Velocity IP Forwarding Support diff --git a/divinemc-server/paper-patches/features/0002-Configuration.patch b/divinemc-server/paper-patches/features/0002-Configuration.patch index f067d73..2060404 100644 --- a/divinemc-server/paper-patches/features/0002-Configuration.patch +++ b/divinemc-server/paper-patches/features/0002-Configuration.patch @@ -5,24 +5,18 @@ Subject: [PATCH] Configuration diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index d9d158ef36225345eec871fd6e6fb19db08d4c21..ade084fb8f6f9290104677d6fc10a72816715746 100644 +index 592e8a4c04ef5acda9fdfd1405d8ff4952396ada..c8c7fa0304e8eaf0d444fc0c9a36c00bb27ccc71 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1060,6 +1060,13 @@ public final class CraftServer implements Server { +@@ -1060,6 +1060,7 @@ public final class CraftServer implements Server { org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot this.console.paperConfigurations.reloadConfigs(this.console); org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur - Purpur config files -+ // DivineMC start - Configuration -+ try { -+ org.bxteam.divinemc.config.DivineConfig.init((File) console.options.valueOf("divinemc-settings")); -+ } catch (IOException e) { -+ this.logger.log(Level.WARNING, "Failed to load DivineMC configuration, " + e.getMessage()); -+ } -+ // DivineMC end - Configuration ++ org.bxteam.divinemc.config.DivineConfig.init((File) console.options.valueOf("divinemc-settings")); // DivineMC - Configuration for (ServerLevel world : this.console.getAllLevels()) { // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) -@@ -1076,6 +1083,13 @@ public final class CraftServer implements Server { +@@ -1076,6 +1077,13 @@ public final class CraftServer implements Server { } world.spigotConfig.init(); // Spigot world.purpurConfig.init(); // Purpur - Purpur config files diff --git a/divinemc-server/paper-patches/features/0016-Implement-Secure-Seed.patch b/divinemc-server/paper-patches/features/0016-Implement-Secure-Seed.patch index 88d4cbc..61ae37b 100644 --- a/divinemc-server/paper-patches/features/0016-Implement-Secure-Seed.patch +++ b/divinemc-server/paper-patches/features/0016-Implement-Secure-Seed.patch @@ -25,10 +25,10 @@ index 400e632208d133a3f49fc7f14bceb48a1026769b..a1c7ba0fdb505d09407cca94e890dedd @Override diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 414fdc6ca7a2979124a7fbf529bff60f993c005a..19430a22687e6bf2887222ecdda2fdda9539c0f8 100644 +index 172fd6f12793565fda9a240ef045775a80e264cb..bf549edfc876f1d831b550864b3f54278bcdd20c 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1352,7 +1352,11 @@ public final class CraftServer implements Server { +@@ -1346,7 +1346,11 @@ public final class CraftServer implements Server { registryAccess = levelDataAndDimensions.dimensions().dimensionsRegistryAccess(); } else { LevelSettings levelSettings; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/command/subcommands/ReloadCommand.java b/divinemc-server/src/main/java/org/bxteam/divinemc/command/subcommands/ReloadCommand.java index 2df61ad..711aa1a 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/command/subcommands/ReloadCommand.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/command/subcommands/ReloadCommand.java @@ -39,11 +39,7 @@ public final class ReloadCommand extends DivineSubCommandPermission { MinecraftServer server = ((CraftServer) sender.getServer()).getServer(); - try { - DivineConfig.init((File) server.options.valueOf("divinemc-settings")); - } catch (IOException e) { - MinecraftServer.LOGGER.error("Failed to reload DivineMC config", e); - } + DivineConfig.init((File) server.options.valueOf("divinemc-settings")); for (ServerLevel level : server.getAllLevels()) { try { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 5c19909..afb9d07 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -59,21 +59,30 @@ public class DivineConfig { return convertToBukkit(config); } - public static void init(File configFile) throws IOException { - DivineConfig.configFile = configFile; - if (configFile.exists()) { - try { - config.load(configFile); - } catch (InvalidConfigurationException e) { - throw new IOException(e); - } - } + public static void init(File configFile) { + try { + long begin = System.nanoTime(); + LOGGER.info("Loading config..."); - getInt("version", CONFIG_VERSION); - config.options().header(HEADER); + DivineConfig.configFile = configFile; + if (configFile.exists()) { + try { + config.load(configFile); + } catch (InvalidConfigurationException e) { + throw new IOException(e); + } + } - readConfig(DivineConfig.class, null); - checkExperimentalFeatures(); + getInt("version", CONFIG_VERSION); + config.options().header(HEADER); + + readConfig(DivineConfig.class, null); + checkExperimentalFeatures(); + + LOGGER.info("Config loaded in {}ms", (System.nanoTime() - begin) / 1_000_000); + } catch (Exception e) { + LOGGER.error("Failed to load config", e); + } } static void readConfig(Class clazz, Object instance) throws IOException { From b0886299648529d192ba36261028a73466db7d97 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 16:41:04 +0300 Subject: [PATCH 25/67] update spark thread names --- ...074-Pufferfish-Optimize-mob-spawning.patch | 26 +++++++++---------- ...-SparklyPaper-Parallel-world-ticking.patch | 6 ++--- .../0081-Regionized-Chunk-Ticking.patch | 13 +++++----- .../dev/tr7zw/entityculling/CullTask.java | 4 ++- .../ServerLevelTickExecutorThreadFactory.java | 4 +-- .../bxteam/divinemc/util/AsyncProcessor.java | 2 ++ 6 files changed, 30 insertions(+), 25 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0074-Pufferfish-Optimize-mob-spawning.patch b/divinemc-server/minecraft-patches/features/0074-Pufferfish-Optimize-mob-spawning.patch index 5f053df..127ffac 100644 --- a/divinemc-server/minecraft-patches/features/0074-Pufferfish-Optimize-mob-spawning.patch +++ b/divinemc-server/minecraft-patches/features/0074-Pufferfish-Optimize-mob-spawning.patch @@ -9,29 +9,29 @@ Original project: https://github.com/pufferfish-gg/Pufferfish This patch reduces the main-thread impact of mob spawning by moving spawning work to other threads diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 7dbefd83d164a7d97a56b02862fef3b2f17d5aab..2f4be37e1ef4ea550bd6acd2c4647e5a7ed77648 100644 +index 7dbefd83d164a7d97a56b02862fef3b2f17d5aab..985a5168f7f81fb934e791618362b7c6e71ff893 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -289,6 +289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function threadFunction) { ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 75c8ce32e68f92e20201e9c243f46f2be716eac8..a76f7ce474cc1d6ff918737e845666a7529bd4a3 100644 +index 75c8ce32e68f92e20201e9c243f46f2be716eac8..bf680624bc6c618dfa0eeeb74c103ff6716fd27e 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -182,6 +182,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } // Paper end - chunk tick iteration optimisations -+ // DivineMC start - Async mob spawning ++ // DivineMC start - Pufferfish: Optimize mob spawning + public boolean firstRunSpawnCounts = true; + public final java.util.concurrent.atomic.AtomicBoolean spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false); -+ // DivineMC end - Async mob spawning ++ // DivineMC end - Pufferfish: Optimize mob spawning public ServerChunkCache( ServerLevel level, @@ -40,7 +40,7 @@ index 75c8ce32e68f92e20201e9c243f46f2be716eac8..a76f7ce474cc1d6ff918737e845666a7 this.broadcastChangedChunks(); } + -+ // DivineMC start - Async mob spawning ++ // DivineMC start - Pufferfish: Optimize mob spawning + if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) { + for (ServerPlayer player : this.level.players) { + for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) { @@ -79,7 +79,7 @@ index 75c8ce32e68f92e20201e9c243f46f2be716eac8..a76f7ce474cc1d6ff918737e845666a7 + }); + } + } -+ // DivineMC end - Async mob spawning ++ // DivineMC end - Pufferfish: Optimize mob spawning } private void broadcastChangedChunks() { @@ -87,7 +87,7 @@ index 75c8ce32e68f92e20201e9c243f46f2be716eac8..a76f7ce474cc1d6ff918737e845666a7 int naturalSpawnChunkCount = this.distanceManager.getNaturalSpawnChunkCount(); // Paper start - Optional per player mob spawns NaturalSpawner.SpawnState spawnState; -+ // DivineMC start - Async mob spawning ++ // DivineMC start - Pufferfish: Optimize mob spawning if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled - // re-set mob counts - for (ServerPlayer player : this.level.players) { @@ -123,7 +123,7 @@ index 75c8ce32e68f92e20201e9c243f46f2be716eac8..a76f7ce474cc1d6ff918737e845666a7 + lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap), false); + spawnCountsReady.set(true); } -+ // DivineMC end - Async mob spawning ++ // DivineMC end - Pufferfish: Optimize mob spawning // Paper end - Optional per player mob spawns - this.lastSpawnState = spawnState; boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit @@ -134,7 +134,7 @@ index 75c8ce32e68f92e20201e9c243f46f2be716eac8..a76f7ce474cc1d6ff918737e845666a7 // Paper end - PlayerNaturallySpawnCreaturesEvent boolean flag = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit - filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(spawnState, this.spawnFriendlies, this.spawnEnemies, flag, this.level); // CraftBukkit -+ filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag, this.level); // CraftBukkit // DivineMC - Async mob spawning ++ filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag, this.level); // CraftBukkit // DivineMC - Pufferfish: Optimize mob spawning } else { filteredSpawningCategories = List.of(); } @@ -143,7 +143,7 @@ index 75c8ce32e68f92e20201e9c243f46f2be716eac8..a76f7ce474cc1d6ff918737e845666a7 for (LevelChunk levelChunk : list) { - this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, spawnState); -+ this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Async mob spawning ++ this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Pufferfish: Optimize mob spawning } } finally { list.clear(); @@ -155,11 +155,11 @@ index 75c8ce32e68f92e20201e9c243f46f2be716eac8..a76f7ce474cc1d6ff918737e845666a7 - if (this.level.getWorldBorder().isWithinBounds(pos)) { // Paper - rewrite chunk system - NaturalSpawner.spawnForChunk(this.level, chunk, spawnState, spawnCategories); - } -+ // DivineMC start - Async mob spawning ++ // DivineMC start - Pufferfish: Optimize mob spawning + if (!spawnCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning || spawnCountsReady.get())) { // Paper - rewrite chunk system + NaturalSpawner.spawnForChunk(this.level, chunk, spawnState, spawnCategories); } -+ // DivineMC end - Async mob spawning ++ // DivineMC end - Pufferfish: Optimize mob spawning } private void getFullChunk(long chunkPos, Consumer fullChunkGetter) { diff --git a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch index d40fc8e..5b270ce 100644 --- a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch @@ -82,13 +82,13 @@ index ac27ff24f018d8798921c5152e679ceed1e88d8d..ec7d1353b19e55b00c558df8981323ef List states = new java.util.ArrayList<>(level.capturedBlockStates.values()); level.capturedBlockStates.clear(); diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 2f4be37e1ef4ea550bd6acd2c4647e5a7ed77648..101dce7741f74dd79b333fd6cf38a97cb0c832f8 100644 +index 985a5168f7f81fb934e791618362b7c6e71ff893..acbae905cd22511be417600c68c6944b80acd2d7 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -290,6 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function threadFunction) { @@ -351,7 +351,7 @@ index efe1e50af314c4b8f6b30c7eb0a8dd14aec327a9..41900b602d763fdd1f393e29ef6c54ae this.setFlightAllowed(properties.allowFlight); this.setMotd(properties.motd); diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index a76f7ce474cc1d6ff918737e845666a7529bd4a3..4fe0f6ba751666e436053536f7607fb50c8471f6 100644 +index bf680624bc6c618dfa0eeeb74c103ff6716fd27e..654d03368f06ab9870c11745b0994ea6722fa7bf 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -175,7 +175,6 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon diff --git a/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch b/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch index 994a345..f78dc19 100644 --- a/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch +++ b/divinemc-server/minecraft-patches/features/0081-Regionized-Chunk-Ticking.patch @@ -21,7 +21,7 @@ index e72eda830644851656fae3118c513d7bd701be45..4ab30d291de7db5ad7d5684662f41348 if (var2 instanceof ClosedChannelException) { LOGGER.info("Connection closed during protocol change"); diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afad669ae9f 100644 +index 654d03368f06ab9870c11745b0994ea6722fa7bf..7fcf9761c3af761e6d3e402fce2f9cbcc219d3b0 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -57,6 +57,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -324,7 +324,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afa + this.broadcastChangedChunks(); + // DivineMC end - Regionized Chunk Ticking + - // DivineMC start - Async mob spawning + // DivineMC start - Pufferfish: Optimize mob spawning if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) { for (ServerPlayer player : this.level.players) { @@ -553,14 +778,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -352,7 +352,7 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afa } private void tickChunks(long timeInhabited) { -@@ -610,23 +839,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -610,23 +839,28 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon filteredSpawningCategories = List.of(); } @@ -369,16 +369,17 @@ index 4fe0f6ba751666e436053536f7607fb50c8471f6..a2be5bd7167b53ad7ce25f05fac46afa - // Paper end - chunk tick iteration optimisation - - for (LevelChunk levelChunk : list) { -- this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Async mob spawning +- this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Pufferfish: Optimize mob spawning + try { + this.chunkMap.collectSpawningChunks(list); + // Paper start - chunk tick iteration optimisation + this.shuffleRandom.setSeed(this.level.random.nextLong()); -+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled ++ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) ++ Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled + // Paper end - chunk tick iteration optimisation + + for (LevelChunk levelChunk : list) { -+ this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Async mob spawning ++ this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Pufferfish: Optimize mob spawning + } + } finally { + list.clear(); diff --git a/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java b/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java index 7129673..b1d5551 100644 --- a/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java +++ b/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java @@ -10,6 +10,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.bxteam.divinemc.config.DivineConfig; +import org.bxteam.divinemc.spark.ThreadDumperRegistry; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -33,7 +34,7 @@ public class CullTask implements Runnable { private final Vec3d aabbMax = new Vec3d(0, 0, 0); private static final Executor backgroundWorker = Executors.newCachedThreadPool(task -> { - final TickThread worker = new TickThread("EntityCulling") { + final TickThread worker = new TickThread("Raytrace Entity Tracker Thread") { @Override public void run() { task.run(); @@ -41,6 +42,7 @@ public class CullTask implements Runnable { }; worker.setDaemon(true); + ThreadDumperRegistry.REGISTRY.add(worker.getName()); return worker; }); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java b/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java index 5a0eeba..20e49f5 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java @@ -9,12 +9,12 @@ public class ServerLevelTickExecutorThreadFactory implements ThreadFactory { public ServerLevelTickExecutorThreadFactory(String worldName) { this.worldName = worldName; - ThreadDumperRegistry.REGISTRY.add("serverlevel-tick-worker [" + worldName + "]"); + ThreadDumperRegistry.REGISTRY.add(worldName + "ServerLevel Tick Worker"); } @Override public Thread newThread(Runnable runnable) { - TickThread.ServerLevelTickThread tickThread = new TickThread.ServerLevelTickThread(runnable, "serverlevel-tick-worker [" + worldName + "]"); + TickThread.ServerLevelTickThread tickThread = new TickThread.ServerLevelTickThread(runnable, this.worldName + "ServerLevel Tick Worker"); if (tickThread.isDaemon()) { tickThread.setDaemon(false); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java index 76ca616..fc19155 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java @@ -3,6 +3,7 @@ package org.bxteam.divinemc.util; import ca.spottedleaf.moonrise.common.util.TickThread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.bxteam.divinemc.spark.ThreadDumperRegistry; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -31,6 +32,7 @@ public class AsyncProcessor { } }, threadName); + ThreadDumperRegistry.REGISTRY.add(threadName); this.workerThread.start(); } From a97e6c6855cff0a939e35ea29dc5335f13644fe0 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 17:52:11 +0300 Subject: [PATCH 26/67] Async Join Thread and executors shutdown --- .../features/0090-Async-Join-Thread.patch | 78 ++++++++++++++ .../features/0091-Shutdown-executors.patch | 18 ++++ .../bxteam/divinemc/config/DivineConfig.java | 19 ++++ .../pathfinding/AsyncPathProcessor.java | 4 +- .../entity/tracking/MultithreadedTracker.java | 2 +- .../server/network/AsyncJoinHandler.java | 102 ++++++++++++++++++ .../bxteam/divinemc/util/AsyncProcessor.java | 89 +++++++-------- .../divinemc/util/ExecutorShutdown.java | 51 +++++++++ 8 files changed, 316 insertions(+), 47 deletions(-) create mode 100644 divinemc-server/minecraft-patches/features/0090-Async-Join-Thread.patch create mode 100644 divinemc-server/minecraft-patches/features/0091-Shutdown-executors.patch create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/server/network/AsyncJoinHandler.java create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java diff --git a/divinemc-server/minecraft-patches/features/0090-Async-Join-Thread.patch b/divinemc-server/minecraft-patches/features/0090-Async-Join-Thread.patch new file mode 100644 index 0000000..67fda9a --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0090-Async-Join-Thread.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 11 Jun 2025 20:15:37 +0300 +Subject: [PATCH] Async Join Thread + + +diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index 9285697a1da3f216e03b8ea824f07f7f7c716c53..de4d2bd780c98c8c06db5e9375d447dae4d4429e 100644 +--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +@@ -186,22 +186,25 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + return; + } + // Paper end - Add Velocity IP Forwarding Support +- // CraftBukkit start +- // Paper start - Cache authenticator threads +- authenticatorPool.execute(() -> { ++ // DivineMC start - Async Join Thread ++ org.bxteam.divinemc.server.network.AsyncJoinHandler.runAsync(() -> { + try { + GameProfile gameprofile = ServerLoginPacketListenerImpl.this.createOfflineProfile(ServerLoginPacketListenerImpl.this.requestedUsername); // Spigot + + gameprofile = ServerLoginPacketListenerImpl.this.callPlayerPreLoginEvents(gameprofile); // Paper - Add more fields to AsyncPlayerPreLoginEvent + ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId()); +- ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile); ++ return gameprofile; + } catch (Exception ex) { + ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!"); + ServerLoginPacketListenerImpl.this.server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.requestedUsername, ex); ++ return null; ++ } ++ }, (gameprofile) -> { ++ if (gameprofile != null) { ++ ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile); + } + }); +- // Paper end - Cache authenticator threads +- // CraftBukkit end ++ // DivineMC end - Async Join Thread + } + } + } +@@ -259,7 +262,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + } + + // Paper start - Cache authenticator threads +- authenticatorPool.execute(new Runnable() { ++ // DivineMC start - Async Join Thread ++ org.bxteam.divinemc.server.network.AsyncJoinHandler.runAsync(new Runnable() { + @Override + public void run() { + String string1 = Objects.requireNonNull(ServerLoginPacketListenerImpl.this.requestedUsername, "Player name not initialized"); +@@ -410,16 +414,23 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + //TODO Update handling for lazy sessions, might not even have to do anything? + + // Proceed with login +- authenticatorPool.execute(() -> { ++ // DivineMC start - Async Join Thread ++ org.bxteam.divinemc.server.network.AsyncJoinHandler.runAsync(() -> { + try { + final GameProfile gameprofile = this.callPlayerPreLoginEvents(this.authenticatedProfile); + ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId()); +- ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile); ++ return gameprofile; + } catch (Exception ex) { + disconnect("Failed to verify username!"); + server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + this.authenticatedProfile.getName(), ex); ++ return null; ++ } ++ }, (gameprofile) -> { ++ if (gameprofile != null) { ++ ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile); + } + }); ++ // DivineMC end - Async Join Thread + return; + } + // Paper end - Add Velocity IP Forwarding Support diff --git a/divinemc-server/minecraft-patches/features/0091-Shutdown-executors.patch b/divinemc-server/minecraft-patches/features/0091-Shutdown-executors.patch new file mode 100644 index 0000000..cd6e003 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0091-Shutdown-executors.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 10 Jul 2025 17:39:29 +0300 +Subject: [PATCH] Shutdown executors + + +diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java +index 6361d8abdeb045923e8ce64f02cbb7a9ed949d1e..b31a4edee0616a63026f7a4335205f2d99d2f641 100644 +--- a/net/minecraft/server/MinecraftServer.java ++++ b/net/minecraft/server/MinecraftServer.java +@@ -1081,6 +1081,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop queue(@NotNull AsyncPath path) { - return CompletableFuture.runAsync(path::process, pathProcessingExecutor) + return CompletableFuture.runAsync(path::process, PATH_PROCESSING_EXECUTOR) .orTimeout(60L, TimeUnit.SECONDS) .exceptionally(throwable -> { if (throwable instanceof TimeoutException e) { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/tracking/MultithreadedTracker.java b/divinemc-server/src/main/java/org/bxteam/divinemc/entity/tracking/MultithreadedTracker.java index 6428810..038ebdf 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/tracking/MultithreadedTracker.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/entity/tracking/MultithreadedTracker.java @@ -29,7 +29,7 @@ public class MultithreadedTracker { private static final Logger LOGGER = LogManager.getLogger(THREAD_PREFIX); private static long lastWarnMillis = System.currentTimeMillis(); - private static final ThreadPoolExecutor TRACKER_EXECUTOR = new ThreadPoolExecutor( + public static final ThreadPoolExecutor TRACKER_EXECUTOR = new ThreadPoolExecutor( getCorePoolSize(), getMaxPoolSize(), getKeepAliveTime(), TimeUnit.SECONDS, diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/server/network/AsyncJoinHandler.java b/divinemc-server/src/main/java/org/bxteam/divinemc/server/network/AsyncJoinHandler.java new file mode 100644 index 0000000..9f62666 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/server/network/AsyncJoinHandler.java @@ -0,0 +1,102 @@ +package org.bxteam.divinemc.server.network; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import net.minecraft.server.MinecraftServer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bxteam.divinemc.config.DivineConfig; +import org.bxteam.divinemc.spark.ThreadDumperRegistry; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Supplier; + +public class AsyncJoinHandler { + private static final String THREAD_PREFIX = "Async Join Thread"; + public static final Logger LOGGER = LogManager.getLogger(AsyncJoinHandler.class.getSimpleName()); + public static ExecutorService JOIN_EXECUTOR; + + private static boolean enabled = false; + private static int threadCount = 2; + + /** + * Initialize the AsyncJoinHandler with configuration settings + */ + public static void init(boolean enabled, int threadCount) { + AsyncJoinHandler.enabled = enabled; + AsyncJoinHandler.threadCount = Math.max(1, threadCount); + + if (enabled) { + if (JOIN_EXECUTOR != null) { + JOIN_EXECUTOR.shutdown(); + } + + JOIN_EXECUTOR = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && + DivineConfig.AsyncCategory.asyncJoinUseVirtualThreads + ? Executors.newVirtualThreadPerTaskExecutor() + : Executors.newFixedThreadPool( + threadCount, + new ThreadFactoryBuilder() + .setNameFormat(THREAD_PREFIX) + .setDaemon(true) + .build() + ); + + ThreadDumperRegistry.REGISTRY.add(THREAD_PREFIX); + + LOGGER.info("Initialized AsyncJoinHandler with {} threads", threadCount); + } + } + + /** + * Execute a potentially blocking task asynchronously + * + * @param task The task to run asynchronously + * @param callback The callback to execute on the main thread when the task completes + * @param The return type of the task + */ + public static void runAsync(Supplier task, java.util.function.Consumer callback) { + if (!enabled || JOIN_EXECUTOR == null) { + T result = task.get(); + callback.accept(result); + return; + } + + CompletableFuture.supplyAsync(task, JOIN_EXECUTOR) + .thenAccept(result -> { + MinecraftServer.getServer().execute(() -> callback.accept(result)); + }) + .exceptionally(ex -> { + LOGGER.error("Error during async join operation", ex); + return null; + }); + } + + /** + * Execute a potentially blocking task asynchronously without a result + * + * @param asyncTask The task to run asynchronously + */ + public static void runAsync(Runnable asyncTask) { + if (!enabled || JOIN_EXECUTOR == null) { + asyncTask.run(); + return; + } + + CompletableFuture.runAsync(asyncTask, JOIN_EXECUTOR) + .thenRun(() -> MinecraftServer.getServer().execute(asyncTask)) + .exceptionally(ex -> { + LOGGER.error("Error during async join operation", ex); + return null; + }); + } + + /** + * Get the executor service for async join operations + */ + public static Executor getExecutor() { + return enabled && JOIN_EXECUTOR != null ? JOIN_EXECUTOR : Runnable::run; + } +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java index fc19155..042ffcb 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java @@ -1,61 +1,62 @@ package org.bxteam.divinemc.util; -import ca.spottedleaf.moonrise.common.util.TickThread; +import it.unimi.dsi.fastutil.PriorityQueue; +import it.unimi.dsi.fastutil.PriorityQueues; +import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue; +import net.minecraft.Util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bxteam.divinemc.spark.ThreadDumperRegistry; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.NoSuchElementException; +import java.util.concurrent.locks.LockSupport; -public class AsyncProcessor { +public class AsyncProcessor implements Runnable { private static final Logger LOGGER = LogManager.getLogger(AsyncProcessor.class); - private final BlockingQueue taskQueue; - private final Thread workerThread; - private volatile boolean isRunning; + public final Thread thread; + private final PriorityQueue jobs = PriorityQueues.synchronize(new ObjectArrayFIFOQueue<>()); + private volatile boolean killswitch = false; public AsyncProcessor(String threadName) { - this.taskQueue = new LinkedBlockingQueue<>(); - this.isRunning = true; + this.thread = Thread.ofPlatform() + .name(threadName) + .priority(Thread.NORM_PRIORITY - 1) + .daemon(false) + .uncaughtExceptionHandler(Util::onThreadException) + .unstarted(this); + } - this.workerThread = new TickThread(() -> { - while (isRunning || !taskQueue.isEmpty()) { + public void start() { + thread.start(); + ThreadDumperRegistry.REGISTRY.add(thread.getName()); + } + + public void join(long millis) throws InterruptedException { + killswitch = true; + LockSupport.unpark(thread); + thread.join(millis); + } + + public void submit(Runnable runnable) { + jobs.enqueue(runnable); + LockSupport.unpark(thread); + } + + @Override + public void run() { + while (!killswitch) { + try { + Runnable runnable; try { - Runnable task = taskQueue.take(); - task.run(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - break; - } catch (Exception e) { - LOGGER.error("An unexpected error occurred when running async processor: {}", e.getMessage(), e); + runnable = jobs.dequeue(); + } catch (NoSuchElementException e) { + LockSupport.park(); + continue; } + runnable.run(); + } catch (Exception e) { + LOGGER.error("Failed to execute async job for thread {}", thread.getName(), e); } - }, threadName); - - ThreadDumperRegistry.REGISTRY.add(threadName); - this.workerThread.start(); - } - - public void submit(Runnable task) { - if (!isRunning) { - throw new IllegalStateException("AsyncExecutor is not running."); } - - taskQueue.offer(task); - } - - public void shutdown() { - isRunning = false; - workerThread.interrupt(); - } - - public void shutdownNow() { - isRunning = false; - workerThread.interrupt(); - taskQueue.clear(); - } - - public boolean isRunning() { - return isRunning; } } diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java new file mode 100644 index 0000000..c0296b8 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java @@ -0,0 +1,51 @@ +package org.bxteam.divinemc.util; + +import net.minecraft.server.MinecraftServer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bxteam.divinemc.entity.pathfinding.AsyncPathProcessor; +import org.bxteam.divinemc.entity.tracking.MultithreadedTracker; +import org.bxteam.divinemc.server.network.AsyncJoinHandler; +import java.util.concurrent.TimeUnit; + +@SuppressWarnings("ConstantValue") +public class ExecutorShutdown { + public static final Logger LOGGER = LogManager.getLogger(ExecutorShutdown.class.getSimpleName()); + + public static void shutdown(MinecraftServer server) { + if (server.mobSpawnExecutor != null && server.mobSpawnExecutor.thread.isAlive()) { + LOGGER.info("Shutting down mob spawn executor..."); + + try { + server.mobSpawnExecutor.join(3000L); + } catch (InterruptedException ignored) { } + } + + if (MultithreadedTracker.TRACKER_EXECUTOR != null) { + LOGGER.info("Shutting down mob tracker executor..."); + MultithreadedTracker.TRACKER_EXECUTOR.shutdown(); + + try { + MultithreadedTracker.TRACKER_EXECUTOR.awaitTermination(10L, TimeUnit.SECONDS); + } catch (InterruptedException ignored) { } + } + + if (AsyncPathProcessor.PATH_PROCESSING_EXECUTOR != null) { + LOGGER.info("Shutting down mob pathfinding processing executor..."); + AsyncPathProcessor.PATH_PROCESSING_EXECUTOR.shutdown(); + + try { + AsyncPathProcessor.PATH_PROCESSING_EXECUTOR.awaitTermination(10L, TimeUnit.SECONDS); + } catch (InterruptedException ignored) { } + } + + if (AsyncJoinHandler.JOIN_EXECUTOR != null) { + LOGGER.info("Shutting down async join executor..."); + AsyncJoinHandler.JOIN_EXECUTOR.shutdown(); + + try { + AsyncJoinHandler.JOIN_EXECUTOR.awaitTermination(10L, TimeUnit.SECONDS); + } catch (InterruptedException ignored) { } + } + } +} From bf7ac641679454b4f55ba031f62b24b43c256d73 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 17:58:26 +0300 Subject: [PATCH 27/67] disabled by default --- .../src/main/java/org/bxteam/divinemc/config/DivineConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index a52a2d7..23ade38 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -231,7 +231,7 @@ public class DivineConfig { public static int asyncEntityTrackerQueueSize = 0; // Async Join Thread settings - public static boolean asyncJoinEnabled = true; + public static boolean asyncJoinEnabled = false; public static int asyncJoinThreadCount = 1; public static boolean asyncJoinUseVirtualThreads = false; From 6dca0972a05fee5af58f34f8af0773605ee9bad6 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 10 Jul 2025 19:28:34 +0300 Subject: [PATCH 28/67] remove vt for authenticator pool --- .../features/0066-Virtual-Threads.patch | 17 ----------------- .../0069-Player-ProfileResult-caching.patch | 6 +++--- .../features/0090-Async-Join-Thread.patch | 16 ++++++++++++---- .../bxteam/divinemc/config/DivineConfig.java | 3 --- 4 files changed, 15 insertions(+), 27 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0066-Virtual-Threads.patch b/divinemc-server/minecraft-patches/features/0066-Virtual-Threads.patch index 16b60e1..7275e8c 100644 --- a/divinemc-server/minecraft-patches/features/0066-Virtual-Threads.patch +++ b/divinemc-server/minecraft-patches/features/0066-Virtual-Threads.patch @@ -71,23 +71,6 @@ index 3ba558634558b4524245a2b29786237f5e38ef42..b6f67c4359e718db8eb9240a22e71fd0 // Paper end - AsyncTabCompleteEvent @Override -diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 20ba45054c243fbb85e50cf0bdf75648730cb0bc..10aecbb88a9a3dae3ecdf28aa449f1a1475a1905 100644 ---- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -53,7 +53,11 @@ import org.bukkit.event.player.PlayerPreLoginEvent; - public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, TickablePacketListener { - private static final AtomicInteger UNIQUE_THREAD_ID = new AtomicInteger(0); - static final Logger LOGGER = LogUtils.getLogger(); -- private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("User Authenticator #%d").setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build()); // Paper - Cache authenticator threads -+ // DivineMC start - Virtual Threads -+ private static final java.util.concurrent.ExecutorService authenticatorPool = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualAuthenticatorScheduler -+ ? java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor() -+ : java.util.concurrent.Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("User Authenticator #%d").setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build()); // Paper - Cache authenticator threads -+ // DivineMC end - Virtual Threads - private static final int MAX_TICKS_BEFORE_LOGIN = 600; - private final byte[] challenge; - final MinecraftServer server; diff --git a/net/minecraft/server/network/ServerTextFilter.java b/net/minecraft/server/network/ServerTextFilter.java index b3d46e7687c572d9847124eb58e4a6011a78066c..9d2e2b1cff68383cd19b42e24559e3009ef1df54 100644 --- a/net/minecraft/server/network/ServerTextFilter.java diff --git a/divinemc-server/minecraft-patches/features/0069-Player-ProfileResult-caching.patch b/divinemc-server/minecraft-patches/features/0069-Player-ProfileResult-caching.patch index d172351..5d21587 100644 --- a/divinemc-server/minecraft-patches/features/0069-Player-ProfileResult-caching.patch +++ b/divinemc-server/minecraft-patches/features/0069-Player-ProfileResult-caching.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Player ProfileResult caching diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 10aecbb88a9a3dae3ecdf28aa449f1a1475a1905..9285697a1da3f216e03b8ea824f07f7f7c716c53 100644 +index 20ba45054c243fbb85e50cf0bdf75648730cb0bc..443aebb71b2a55ee9dcd2dd4bf9a30fbb8da9e49 100644 --- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -75,6 +75,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, +@@ -71,6 +71,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, public @Nullable java.util.UUID requestedUuid; // Paper private final io.papermc.paper.connection.PaperPlayerLoginConnection paperLoginConnection; // Paper - Config API private volatile boolean disconnecting = false; // Paper - Fix disconnect still ticking login @@ -20,7 +20,7 @@ index 10aecbb88a9a3dae3ecdf28aa449f1a1475a1905..9285697a1da3f216e03b8ea824f07f7f public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) { this.server = server; -@@ -260,9 +265,23 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, +@@ -256,9 +261,23 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, String string1 = Objects.requireNonNull(ServerLoginPacketListenerImpl.this.requestedUsername, "Player name not initialized"); try { diff --git a/divinemc-server/minecraft-patches/features/0090-Async-Join-Thread.patch b/divinemc-server/minecraft-patches/features/0090-Async-Join-Thread.patch index 67fda9a..dc501ee 100644 --- a/divinemc-server/minecraft-patches/features/0090-Async-Join-Thread.patch +++ b/divinemc-server/minecraft-patches/features/0090-Async-Join-Thread.patch @@ -5,10 +5,18 @@ Subject: [PATCH] Async Join Thread diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 9285697a1da3f216e03b8ea824f07f7f7c716c53..de4d2bd780c98c8c06db5e9375d447dae4d4429e 100644 +index 443aebb71b2a55ee9dcd2dd4bf9a30fbb8da9e49..cd926f0576d73bc3ef41c9a075a7ac9c54c9dd41 100644 --- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -186,22 +186,25 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, +@@ -53,7 +53,6 @@ import org.bukkit.event.player.PlayerPreLoginEvent; + public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, TickablePacketListener { + private static final AtomicInteger UNIQUE_THREAD_ID = new AtomicInteger(0); + static final Logger LOGGER = LogUtils.getLogger(); +- private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("User Authenticator #%d").setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build()); // Paper - Cache authenticator threads + private static final int MAX_TICKS_BEFORE_LOGIN = 600; + private final byte[] challenge; + final MinecraftServer server; +@@ -182,22 +181,25 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, return; } // Paper end - Add Velocity IP Forwarding Support @@ -40,7 +48,7 @@ index 9285697a1da3f216e03b8ea824f07f7f7c716c53..de4d2bd780c98c8c06db5e9375d447da } } } -@@ -259,7 +262,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, +@@ -255,7 +257,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, } // Paper start - Cache authenticator threads @@ -50,7 +58,7 @@ index 9285697a1da3f216e03b8ea824f07f7f7c716c53..de4d2bd780c98c8c06db5e9375d447da @Override public void run() { String string1 = Objects.requireNonNull(ServerLoginPacketListenerImpl.this.requestedUsername, "Player name not initialized"); -@@ -410,16 +414,23 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, +@@ -406,16 +409,23 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, //TODO Update handling for lazy sessions, might not even have to do anything? // Proceed with login diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 23ade38..881346b 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -399,7 +399,6 @@ public class DivineConfig { public static boolean virtualThreadsEnabled = false; public static boolean virtualBukkitScheduler = false; public static boolean virtualChatScheduler = false; - public static boolean virtualAuthenticatorScheduler = false; public static boolean virtualTabCompleteScheduler = false; public static boolean virtualAsyncExecutor = false; public static boolean virtualCommandBuilderScheduler = false; @@ -523,8 +522,6 @@ public class DivineConfig { "Uses virtual threads for the Bukkit scheduler."); virtualChatScheduler = getBoolean(ConfigCategory.PERFORMANCE.key("virtual-threads.chat-scheduler"), virtualChatScheduler, "Uses virtual threads for the Chat scheduler."); - virtualAuthenticatorScheduler = getBoolean(ConfigCategory.PERFORMANCE.key("virtual-threads.authenticator-scheduler"), virtualAuthenticatorScheduler, - "Uses virtual threads for the Authenticator scheduler."); virtualTabCompleteScheduler = getBoolean(ConfigCategory.PERFORMANCE.key("virtual-threads.tab-complete-scheduler"), virtualTabCompleteScheduler, "Uses virtual threads for the Tab Complete scheduler."); virtualAsyncExecutor = getBoolean(ConfigCategory.PERFORMANCE.key("virtual-threads.async-executor"), virtualAsyncExecutor, From 1d451b444178875ec124bbecd30fc1cb4a9553e6 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 11 Jul 2025 01:25:21 +0300 Subject: [PATCH 29/67] add leaves protocols, load config a little bit earlier --- build-data/divinemc.at | 8 + .../features/0002-Configuration.patch | 18 +- ...03-Completely-remove-Mojang-profiler.patch | 8 +- .../0010-Pufferfish-SIMD-support.patch | 6 +- .../0064-Implement-NoChatReports.patch | 4 +- ...-SparklyPaper-Parallel-world-ticking.patch | 4 +- ...-Disable-offline-warn-if-using-proxy.patch | 4 +- .../features/0092-Leaves-Protocol-Core.patch | 146 ++++++ .../0093-Leaves-Xaero-s-Map-Protocol.patch | 20 + .../0094-Leaves-Syncmatica-Protocol.patch | 28 ++ .../features/0023-Leaves-Protocol-Core.patch | 28 ++ .../bxteam/divinemc/config/DivineConfig.java | 38 ++ .../org/leavesmc/leaves/LeavesLogger.java | 24 + .../leaves/protocol/AppleSkinProtocol.java | 122 +++++ .../leaves/protocol/XaeroMapProtocol.java | 46 ++ .../protocol/core/LeavesCustomPayload.java | 29 ++ .../leaves/protocol/core/LeavesProtocol.java | 20 + .../protocol/core/LeavesProtocolManager.java | 455 ++++++++++++++++++ .../leaves/protocol/core/ProtocolHandler.java | 61 +++ .../leaves/protocol/core/ProtocolUtils.java | 43 ++ .../core/invoker/AbstractInvokerHolder.java | 69 +++ .../invoker/BytebufReceiverInvokerHolder.java | 18 + .../core/invoker/EmptyInvokerHolder.java | 15 + .../core/invoker/InitInvokerHolder.java | 16 + .../MinecraftRegisterInvokerHolder.java | 18 + .../invoker/PayloadReceiverInvokerHolder.java | 18 + .../core/invoker/PlayerInvokerHolder.java | 16 + .../leaves/protocol/jade/JadeProtocol.java | 290 +++++++++++ .../protocol/jade/accessor/Accessor.java | 22 + .../protocol/jade/accessor/AccessorImpl.java | 60 +++ .../protocol/jade/accessor/BlockAccessor.java | 44 ++ .../jade/accessor/BlockAccessorImpl.java | 143 ++++++ .../jade/accessor/EntityAccessor.java | 42 ++ .../jade/accessor/EntityAccessorImpl.java | 112 +++++ .../jade/payload/ClientHandshakePayload.java | 19 + .../jade/payload/ReceiveDataPayload.java | 20 + .../jade/payload/RequestBlockPayload.java | 35 ++ .../jade/payload/RequestEntityPayload.java | 36 ++ .../jade/payload/ServerHandshakePayload.java | 37 ++ .../protocol/jade/provider/IJadeProvider.java | 12 + .../jade/provider/IServerDataProvider.java | 8 + .../provider/IServerExtensionProvider.java | 10 + .../ItemStorageExtensionProvider.java | 142 ++++++ .../jade/provider/ItemStorageProvider.java | 87 ++++ .../provider/StreamServerDataProvider.java | 23 + .../jade/provider/block/BeehiveProvider.java | 34 ++ .../provider/block/BlockNameProvider.java | 60 +++ .../provider/block/BrewingStandProvider.java | 43 ++ .../jade/provider/block/CampfireProvider.java | 55 +++ .../block/ChiseledBookshelfProvider.java | 44 ++ .../provider/block/CommandBlockProvider.java | 40 ++ .../jade/provider/block/FurnaceProvider.java | 51 ++ .../provider/block/HopperLockProvider.java | 37 ++ .../jade/provider/block/JukeboxProvider.java | 32 ++ .../jade/provider/block/LecternProvider.java | 33 ++ .../block/MobSpawnerCooldownProvider.java | 42 ++ .../jade/provider/block/RedstoneProvider.java | 36 ++ .../provider/entity/AnimalOwnerProvider.java | 48 ++ .../provider/entity/MobBreedingProvider.java | 44 ++ .../provider/entity/MobGrowthProvider.java | 43 ++ .../entity/NextEntityDropProvider.java | 42 ++ .../provider/entity/PetArmorProvider.java | 35 ++ .../entity/StatusEffectsProvider.java | 45 ++ .../entity/ZombieVillagerProvider.java | 34 ++ .../protocol/jade/tool/ShearsToolHandler.java | 37 ++ .../leaves/protocol/jade/util/CommonUtil.java | 72 +++ .../protocol/jade/util/HierarchyLookup.java | 138 ++++++ .../protocol/jade/util/IHierarchyLookup.java | 71 +++ .../protocol/jade/util/ItemCollector.java | 121 +++++ .../protocol/jade/util/ItemIterator.java | 102 ++++ .../leaves/protocol/jade/util/JadeCodec.java | 59 +++ .../jade/util/LootTableMineableCollector.java | 109 +++++ .../jade/util/PairHierarchyLookup.java | 115 +++++ .../protocol/jade/util/PriorityStore.java | 40 ++ .../leaves/protocol/jade/util/ViewGroup.java | 58 +++ .../jade/util/WrappedHierarchyLookup.java | 107 ++++ .../syncmatica/CommunicationManager.java | 389 +++++++++++++++ .../leaves/protocol/syncmatica/Feature.java | 23 + .../protocol/syncmatica/FeatureSet.java | 68 +++ .../protocol/syncmatica/FileStorage.java | 80 +++ .../syncmatica/LocalLitematicState.java | 24 + .../protocol/syncmatica/MessageType.java | 8 + .../protocol/syncmatica/PacketType.java | 30 ++ .../protocol/syncmatica/PlayerIdentifier.java | 37 ++ .../syncmatica/PlayerIdentifierProvider.java | 46 ++ .../protocol/syncmatica/ServerPlacement.java | 166 +++++++ .../protocol/syncmatica/ServerPosition.java | 51 ++ .../protocol/syncmatica/SubRegionData.java | 90 ++++ .../SubRegionPlacementModification.java | 65 +++ .../protocol/syncmatica/SyncmaticManager.java | 108 +++++ .../syncmatica/SyncmaticaPayload.java | 18 + .../syncmatica/SyncmaticaProtocol.java | 127 +++++ .../syncmatica/exchange/AbstractExchange.java | 66 +++ .../syncmatica/exchange/DownloadExchange.java | 128 +++++ .../syncmatica/exchange/Exchange.java | 20 + .../syncmatica/exchange/ExchangeTarget.java | 39 ++ .../syncmatica/exchange/FeatureExchange.java | 48 ++ .../exchange/ModifyExchangeServer.java | 82 ++++ .../syncmatica/exchange/UploadExchange.java | 101 ++++ .../exchange/VersionHandshakeServer.java | 66 +++ .../org/leavesmc/leaves/util/NbtUtils.java | 75 +++ 101 files changed, 6187 insertions(+), 19 deletions(-) create mode 100644 divinemc-server/minecraft-patches/features/0092-Leaves-Protocol-Core.patch create mode 100644 divinemc-server/minecraft-patches/features/0093-Leaves-Xaero-s-Map-Protocol.patch create mode 100644 divinemc-server/minecraft-patches/features/0094-Leaves-Syncmatica-Protocol.patch create mode 100644 divinemc-server/paper-patches/features/0023-Leaves-Protocol-Core.patch create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/LeavesLogger.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/AppleSkinProtocol.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/XaeroMapProtocol.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesCustomPayload.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocol.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolHandler.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolUtils.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/AbstractInvokerHolder.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/BytebufReceiverInvokerHolder.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/EmptyInvokerHolder.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/InitInvokerHolder.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/MinecraftRegisterInvokerHolder.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/PayloadReceiverInvokerHolder.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/PlayerInvokerHolder.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessor.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessor.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ClientHandshakePayload.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ReceiveDataPayload.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestBlockPayload.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestEntityPayload.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ServerHandshakePayload.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IJadeProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerDataProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerExtensionProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/StreamServerDataProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BeehiveProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BlockNameProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BrewingStandProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ChiseledBookshelfProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CommandBlockProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/FurnaceProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/HopperLockProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/JukeboxProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/LecternProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/MobSpawnerCooldownProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/RedstoneProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/AnimalOwnerProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobBreedingProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobGrowthProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/NextEntityDropProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/PetArmorProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/StatusEffectsProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/ZombieVillagerProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ShearsToolHandler.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/CommonUtil.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/HierarchyLookup.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/IHierarchyLookup.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemIterator.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/JadeCodec.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/LootTableMineableCollector.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/PairHierarchyLookup.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/PriorityStore.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ViewGroup.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/WrappedHierarchyLookup.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/Feature.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/FeatureSet.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/FileStorage.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/LocalLitematicState.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/MessageType.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PacketType.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PlayerIdentifier.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PlayerIdentifierProvider.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/ServerPlacement.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/ServerPosition.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SubRegionData.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SubRegionPlacementModification.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticManager.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticaPayload.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticaProtocol.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/AbstractExchange.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/DownloadExchange.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/Exchange.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/ExchangeTarget.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/FeatureExchange.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/ModifyExchangeServer.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/UploadExchange.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/VersionHandshakeServer.java create mode 100644 divinemc-server/src/main/java/org/leavesmc/leaves/util/NbtUtils.java diff --git a/build-data/divinemc.at b/build-data/divinemc.at index 457eb6b..016f220 100644 --- a/build-data/divinemc.at +++ b/build-data/divinemc.at @@ -12,6 +12,8 @@ public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities lineOfS public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities nearbyEntities public net.minecraft.world.entity.ai.sensing.Sensor scanRate public net.minecraft.world.entity.ai.sensing.Sensor timeToTick +public net.minecraft.world.entity.animal.armadillo.Armadillo scuteTime +public net.minecraft.world.entity.animal.frog.Tadpole getTicksLeftUntilAdult()I public net.minecraft.world.level.chunk.PaletteResize public net.minecraft.world.level.entity.EntityTickList entities public net.minecraft.world.level.levelgen.DensityFunctions$BlendAlpha @@ -41,4 +43,10 @@ public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedLo public net.minecraft.world.level.levelgen.XoroshiroRandomSource randomNumberGenerator public net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool rawTemplates public net.minecraft.world.level.pathfinder.SwimNodeEvaluator allowBreaching +public net.minecraft.world.level.storage.loot.LootPool entries +public net.minecraft.world.level.storage.loot.LootTable pools +public net.minecraft.world.level.storage.loot.entries.CompositeEntryBase children +public net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer conditions +public net.minecraft.world.level.storage.loot.entries.NestedLootTable contents +public net.minecraft.world.level.storage.loot.predicates.CompositeLootItemCondition terms public-f ca.spottedleaf.moonrise.paper.PaperHooks diff --git a/divinemc-server/minecraft-patches/features/0002-Configuration.patch b/divinemc-server/minecraft-patches/features/0002-Configuration.patch index 298d176..192f9bb 100644 --- a/divinemc-server/minecraft-patches/features/0002-Configuration.patch +++ b/divinemc-server/minecraft-patches/features/0002-Configuration.patch @@ -5,17 +5,23 @@ Subject: [PATCH] Configuration diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 670553243d26e2faab8a21f099a846d4d1df7927..329aeeafd51aee4da289b70ff68cdfe5401cc91a 100644 +index 670553243d26e2faab8a21f099a846d4d1df7927..83bd88eb9944481642f912c2d4862dfecdec2246 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -193,6 +193,10 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -162,6 +162,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + this.setLocalIp(properties.serverIp); + } + ++ org.bxteam.divinemc.config.DivineConfig.init((java.io.File) options.valueOf("divinemc-settings")); // DivineMC - Configuration ++ + // Spigot start + this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); + org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings")); +@@ -193,6 +195,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface } org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur end - Purpur config files -+ // DivineMC start - Configuration -+ org.bxteam.divinemc.config.DivineConfig.init((java.io.File) options.valueOf("divinemc-settings")); -+ org.bxteam.divinemc.command.DivineCommands.registerCommands(this); -+ // DivineMC end - Configuration ++ org.bxteam.divinemc.command.DivineCommands.registerCommands(this); // DivineMC - Configuration com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now this.setPvpAllowed(properties.pvp); diff --git a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch index 160c8d5..c6c93b2 100644 --- a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch +++ b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch @@ -1067,10 +1067,10 @@ index b10cb4a73df58a5fe64e88868733ba41616f59e4..9f9cbe6056f8a4eeca64c40872d7403b + // DivineMC end - Completely remove Mojang profiler } diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 329aeeafd51aee4da289b70ff68cdfe5401cc91a..653988aed936761385f245c520cc9521351664bf 100644 +index 83bd88eb9944481642f912c2d4862dfecdec2246..06657a0fbf65dd095519d706dd5a8e1d8b6b381a 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -790,12 +790,6 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -789,12 +789,6 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface return this.settings.getProperties().serverResourcePackInfo; } @@ -4493,7 +4493,7 @@ index cf6ff7b7b4a007d7ff4b3c5a25d4f5a36422c683..c5275d6069a491c3c2b2de175b76fb87 } diff --git a/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/net/minecraft/world/entity/animal/armadillo/Armadillo.java -index 0da5c51c4830cf1826261f4d8877303b34c6cb87..6fbeaff7178a21338920d6738767033260b7a726 100644 +index e4578193f58417c7ef2776bb3d831ba55c553aec..2a7a078e05e16e73e43a24e108d207bce2e876bb 100644 --- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java +++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java @@ -23,8 +23,6 @@ import net.minecraft.util.ByIdMap; @@ -4604,7 +4604,7 @@ index 1d5079602e7ae1042e2bb92209dded4007f703da..c6e4966d3e4fdb7c91577fc1693fb669 } diff --git a/net/minecraft/world/entity/animal/frog/Tadpole.java b/net/minecraft/world/entity/animal/frog/Tadpole.java -index 6932e85b3db0205f9a69d9ef965a934f100e6bcf..c0e12a6e5dd2b7e12e4cc40f6795228de6b470cc 100644 +index 3bb197054f5197c0b8c4e2d4714d695255d5ecfa..f85626b690b02908fac3979d277b293ec48aa451 100644 --- a/net/minecraft/world/entity/animal/frog/Tadpole.java +++ b/net/minecraft/world/entity/animal/frog/Tadpole.java @@ -12,8 +12,6 @@ import net.minecraft.server.level.ServerLevel; diff --git a/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch b/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch index ef6ab18..b7094ad 100644 --- a/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch +++ b/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch @@ -7,11 +7,11 @@ Original license: GPL v3 Original project: https://github.com/pufferfish-gg/Pufferfish diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 653988aed936761385f245c520cc9521351664bf..f963be0d96a54a9077d2d66e9abe73ba8484d653 100644 +index 06657a0fbf65dd095519d706dd5a8e1d8b6b381a..a947fc31f6261531b6f28e5af577e74ca84f2132 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -199,6 +199,26 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - // DivineMC end - Configuration +@@ -198,6 +198,26 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + org.bxteam.divinemc.command.DivineCommands.registerCommands(this); // DivineMC - Configuration com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now + // DivineMC start - Pufferfish SIMD diff --git a/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch b/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch index f5a2a51..7c2fc7a 100644 --- a/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch +++ b/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch @@ -206,10 +206,10 @@ index a491be4250de3199c3e1aa9e5482b568692bd2f5..c88826db76c28c536e6c36c5592d69c1 private static final String PREFIX = "data:image/png;base64,"; public static final Codec CODEC = Codec.STRING.comapFlatMap(string -> { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index f963be0d96a54a9077d2d66e9abe73ba8484d653..efe1e50af314c4b8f6b30c7eb0a8dd14aec327a9 100644 +index a947fc31f6261531b6f28e5af577e74ca84f2132..021e1cb762d23ebe885a3f190ba2431e1db99bb8 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -624,6 +624,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -623,6 +623,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @Override public boolean enforceSecureProfile() { diff --git a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch index 5b270ce..ab00baa 100644 --- a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch @@ -333,10 +333,10 @@ index 10e5469df1800bcdfb3f8cb4045ee25a4bafc58c..8efed0ffdc906b6c1ba054831e481f53 } } else if (this.visible.remove(advancementHolder)) { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index efe1e50af314c4b8f6b30c7eb0a8dd14aec327a9..41900b602d763fdd1f393e29ef6c54ae2694d7bd 100644 +index 021e1cb762d23ebe885a3f190ba2431e1db99bb8..8820d1789192247c52b4d821abf2dd23c0bf1b62 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -219,6 +219,13 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -218,6 +218,13 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface } // DivineMC end - Pufferfish SIMD diff --git a/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch b/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch index f603014..d0b1ce8 100644 --- a/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch +++ b/divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Disable offline warn if using proxy diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 41900b602d763fdd1f393e29ef6c54ae2694d7bd..0e66aa733dd9b0c23ef01bb38243a0cab13d9ecf 100644 +index 8820d1789192247c52b4d821abf2dd23c0bf1b62..5a2b9632a1e46b512a1379923765c1b8a28250b9 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -306,7 +306,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -305,7 +305,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord"; String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/"; // Paper end - Add Velocity IP Forwarding Support diff --git a/divinemc-server/minecraft-patches/features/0092-Leaves-Protocol-Core.patch b/divinemc-server/minecraft-patches/features/0092-Leaves-Protocol-Core.patch new file mode 100644 index 0000000..642ff50 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0092-Leaves-Protocol-Core.patch @@ -0,0 +1,146 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 10 Jul 2025 22:11:47 +0300 +Subject: [PATCH] Leaves: Protocol Core + +Original project: https://github.com/LeavesMC/Leaves +Original license: GPLv3 + +diff --git a/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java b/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java +index fb263fa1f30a7dfcb7ec2656abfb38e5fe88eac9..c3be4c2fd4a544967322a45d3b8c0fe78a0684a5 100644 +--- a/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java ++++ b/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java +@@ -40,13 +40,22 @@ public interface CustomPacketPayload { + + @Override + public void encode(B buffer, CustomPacketPayload value) { ++ // DivineMC start - Leaves Protocol Core ++ if (value instanceof org.leavesmc.leaves.protocol.core.LeavesCustomPayload payload) { ++ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.encode(buffer, payload); ++ return; ++ } ++ // DivineMC end - Leaves Protocol Core + this.writeCap(buffer, value.type(), value); + } + + @Override + public CustomPacketPayload decode(B buffer) { + ResourceLocation resourceLocation = buffer.readResourceLocation(); +- return (CustomPacketPayload)this.findCodec(resourceLocation).decode(buffer); ++ // DivineMC start - Leaves Protocol Core ++ var payload = org.leavesmc.leaves.protocol.core.LeavesProtocolManager.decode(resourceLocation, buffer); ++ return java.util.Objects.requireNonNullElseGet(payload, () -> this.findCodec(resourceLocation).decode(buffer)); ++ // DivineMC end - Leaves Protocol Core + } + }; + } +diff --git a/net/minecraft/network/protocol/common/custom/DiscardedPayload.java b/net/minecraft/network/protocol/common/custom/DiscardedPayload.java +index 62b9d9486c15a1ec6527f786df4e9fc483390bcb..36d8b93182cc44e3bea245800ea9e2719333ac65 100644 +--- a/net/minecraft/network/protocol/common/custom/DiscardedPayload.java ++++ b/net/minecraft/network/protocol/common/custom/DiscardedPayload.java +@@ -4,12 +4,12 @@ import net.minecraft.network.FriendlyByteBuf; + import net.minecraft.network.codec.StreamCodec; + import net.minecraft.resources.ResourceLocation; + +-public record DiscardedPayload(ResourceLocation id, byte[] data) implements CustomPacketPayload { // Paper - store data ++public record DiscardedPayload(ResourceLocation id, byte @org.jetbrains.annotations.Nullable [] data) implements CustomPacketPayload { // Paper - store data // DivineMC - Leaves Protocol Core + public static StreamCodec codec(ResourceLocation id, int maxSize) { + return CustomPacketPayload.codec((value, output) -> { + // Paper start + // Always write data +- output.writeBytes(value.data); ++ if (value.data != null) output.writeBytes(value.data); // DivineMC - Leaves Protocol Core + }, buffer -> { + int i = buffer.readableBytes(); + if (i >= 0 && i <= maxSize) { +diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java +index b31a4edee0616a63026f7a4335205f2d99d2f641..0072f3f07b1962adc1766930bb9a2f709cb76e6e 100644 +--- a/net/minecraft/server/MinecraftServer.java ++++ b/net/minecraft/server/MinecraftServer.java +@@ -1788,6 +1788,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Thu, 10 Jul 2025 22:15:39 +0300 +Subject: [PATCH] Leaves: Xaero's Map Protocol + +Original project: https://github.com/LeavesMC/Leaves +Original license: GPLv3 + +diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java +index f65599e41ca77756cc9bfb87c4a86606eed127cf..753f921042c8fcfc0eb6c2dca7f80751df4909e3 100644 +--- a/net/minecraft/server/players/PlayerList.java ++++ b/net/minecraft/server/players/PlayerList.java +@@ -1172,6 +1172,7 @@ public abstract class PlayerList { + player.connection.send(new ClientboundInitializeBorderPacket(worldBorder)); + player.connection.send(new ClientboundSetTimePacket(level.getGameTime(), level.getDayTime(), level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); + player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getSharedSpawnPos(), level.getSharedSpawnAngle())); ++ org.leavesmc.leaves.protocol.XaeroMapProtocol.onSendWorldInfo(player); // DivineMC - Leaves: Xaero's Map Protocol + if (level.isRaining()) { + // CraftBukkit start - handle player weather + // player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, 0.0F)); diff --git a/divinemc-server/minecraft-patches/features/0094-Leaves-Syncmatica-Protocol.patch b/divinemc-server/minecraft-patches/features/0094-Leaves-Syncmatica-Protocol.patch new file mode 100644 index 0000000..e211dd3 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0094-Leaves-Syncmatica-Protocol.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 10 Jul 2025 22:17:00 +0300 +Subject: [PATCH] Leaves: Syncmatica Protocol + +Original project: https://github.com/LeavesMC/Leaves +Original license: GPLv3 + +diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 9d771e7fba94c09df602a249f58a9caf1d339bcf..db85f8f905425316f893d0adccdeef53517faba8 100644 +--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -313,6 +313,7 @@ public class ServerGamePacketListenerImpl + private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper - Limit client sign length + private final io.papermc.paper.event.packet.ClientTickEndEvent tickEndEvent; // Paper - add client tick end event + public final io.papermc.paper.connection.PaperPlayerGameConnection playerGameConnection; // Paper ++ public final org.leavesmc.leaves.protocol.syncmatica.exchange.ExchangeTarget exchangeTarget; // DivineMC - Leaves: Syncmatica Protocol + + public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie cookie) { + super(server, connection, cookie); +@@ -324,6 +325,7 @@ public class ServerGamePacketListenerImpl + this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat + this.tickEndEvent = new io.papermc.paper.event.packet.ClientTickEndEvent(player.getBukkitEntity()); // Paper - add client tick end event + this.playerGameConnection = new io.papermc.paper.connection.PaperPlayerGameConnection(this); // Paper ++ this.exchangeTarget = new org.leavesmc.leaves.protocol.syncmatica.exchange.ExchangeTarget(this); // DivineMC - Leaves: Syncmatica Protocol + } + + // Paper start - configuration phase API diff --git a/divinemc-server/paper-patches/features/0023-Leaves-Protocol-Core.patch b/divinemc-server/paper-patches/features/0023-Leaves-Protocol-Core.patch new file mode 100644 index 0000000..f005be4 --- /dev/null +++ b/divinemc-server/paper-patches/features/0023-Leaves-Protocol-Core.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 10 Jul 2025 22:12:19 +0300 +Subject: [PATCH] Leaves: Protocol Core + +Original project: https://github.com/LeavesMC/Leaves +Original license: GPLv3 + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index bf549edfc876f1d831b550864b3f54278bcdd20c..bf53f7343f5c8dd6f3bd995cfcebe7b88472659b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -510,6 +510,7 @@ public final class CraftServer implements Server { + this.potionBrewer = new io.papermc.paper.potion.PaperPotionBrewer(console); // Paper - custom potion mixes + datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper + this.spark = new io.papermc.paper.SparksFly(this); // Paper - spark ++ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.init(); // DivineMC - Leaves Protocol Core + } + + public boolean getCommandBlockOverride(String command) { +@@ -1099,6 +1100,7 @@ public final class CraftServer implements Server { + org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur - Purpur config files + this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); + this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); ++ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleServerReload(); // DivineMC - Leaves Protocol Core + + int pollCount = 0; + diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 881346b..72b96ee 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -26,6 +26,7 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Random; @SuppressWarnings({"unused", "SameParameterValue"}) public class DivineConfig { @@ -688,9 +689,20 @@ public class DivineConfig { public static boolean noChatReportsDemandOnClient = false; public static String noChatReportsDisconnectDemandOnClientMessage = "You do not have No Chat Reports, and this server is configured to require it on client!"; + // Protocols + public static boolean protocolsAppleSkinEnabled = false; + public static int protocolsAppleSkinSyncTickInterval = 20; + public static boolean protocolsJadeEnabled = false; + public static boolean protocolsMapsXaeroMapEnabled = false; + public static int protocolsMapsXaeroMapServerId = new Random().nextInt(); + public static boolean protocolsSyncMaticaEnabled = false; + public static boolean protocolsSyncMaticaQuota = false; + public static int protocolsSyncMaticaQuotaLimit = 40000000; + public static void load() { networkSettings(); noChatReports(); + protocols(); } private static void networkSettings() { @@ -718,6 +730,32 @@ public class DivineConfig { noChatReportsDisconnectDemandOnClientMessage = getString(ConfigCategory.NETWORK.key("no-chat-reports.disconnect-demand-on-client-message"), noChatReportsDisconnectDemandOnClientMessage, "Message to send to the client when they are disconnected for not having No Chat Reports"); } + + private static void protocols() { + // AppleSkin + protocolsAppleSkinEnabled = getBoolean(ConfigCategory.NETWORK.key("protocols.appleskin.appleskin-enable"), protocolsAppleSkinEnabled, + "Enables AppleSkin protocol support"); + protocolsAppleSkinSyncTickInterval = getInt(ConfigCategory.NETWORK.key("protocols.appleskin.sync-tick-interval"), protocolsAppleSkinSyncTickInterval, + "Sync tick interval for AppleSkin protocol"); + + // Jade + protocolsJadeEnabled = getBoolean(ConfigCategory.NETWORK.key("protocols.jade.jade-enable"), protocolsJadeEnabled, + "Enables Jade protocol support"); + + // Xaero's Map + protocolsMapsXaeroMapEnabled = getBoolean(ConfigCategory.NETWORK.key("protocols.xaeromap.xaeromap-enable"), protocolsMapsXaeroMapEnabled, + "Enables Xaero's Map protocol support"); + protocolsMapsXaeroMapServerId = getInt(ConfigCategory.NETWORK.key("protocols.xaeromap.xaero-map-server-id"), protocolsMapsXaeroMapServerId, + "Server ID for Xaero's Map protocol"); + + // Syncmatica + protocolsSyncMaticaEnabled = getBoolean(ConfigCategory.NETWORK.key("protocols.syncmatica.syncmatica-enable"), protocolsSyncMaticaEnabled, + "Enables SyncMatica protocol support"); + protocolsSyncMaticaQuota = getBoolean(ConfigCategory.NETWORK.key("protocols.syncmatica.quota"), protocolsSyncMaticaQuota, + "Enables quota system for SyncMatica"); + protocolsSyncMaticaQuotaLimit = getInt(ConfigCategory.NETWORK.key("protocols.syncmatica.quota-limit"), protocolsSyncMaticaQuotaLimit, + "Quota limit for SyncMatica protocol"); + } } private static void checkExperimentalFeatures() { diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/LeavesLogger.java b/divinemc-server/src/main/java/org/leavesmc/leaves/LeavesLogger.java new file mode 100644 index 0000000..bc45935 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/LeavesLogger.java @@ -0,0 +1,24 @@ +package org.leavesmc.leaves; + +import org.bukkit.Bukkit; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class LeavesLogger extends Logger { + public static final LeavesLogger LOGGER = new LeavesLogger(); + + private LeavesLogger() { + super("Leaves", null); + setParent(Bukkit.getLogger()); + setLevel(Level.ALL); + } + + public void severe(String msg, Exception exception) { + this.log(Level.SEVERE, msg, exception); + } + + public void warning(String msg, Exception exception) { + this.log(Level.WARNING, msg, exception); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/AppleSkinProtocol.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/AppleSkinProtocol.java new file mode 100644 index 0000000..2e551b1 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/AppleSkinProtocol.java @@ -0,0 +1,122 @@ +package org.leavesmc.leaves.protocol; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.food.FoodData; +import net.minecraft.world.level.GameRules; +import org.bxteam.divinemc.config.DivineConfig; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.core.LeavesProtocol; +import org.leavesmc.leaves.protocol.core.ProtocolHandler; +import org.leavesmc.leaves.protocol.core.ProtocolUtils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +@LeavesProtocol.Register(namespace = "appleskin") +public class AppleSkinProtocol implements LeavesProtocol { + public static final String PROTOCOL_ID = "appleskin"; + + private static final ResourceLocation SATURATION_KEY = id("saturation"); + private static final ResourceLocation EXHAUSTION_KEY = id("exhaustion"); + private static final ResourceLocation NATURAL_REGENERATION_KEY = id("natural_regeneration"); + + private static final float MINIMUM_EXHAUSTION_CHANGE_THRESHOLD = 0.01F; + + private static final Map previousSaturationLevels = new HashMap<>(); + private static final Map previousExhaustionLevels = new HashMap<>(); + private static final Map previousNaturalRegeneration = new HashMap<>(); + + private static final Map> subscribedChannels = new HashMap<>(); + + @Contract("_ -> new") + public static ResourceLocation id(String path) { + return ResourceLocation.tryBuild(PROTOCOL_ID, path); + } + + @ProtocolHandler.PlayerJoin + public static void onPlayerLoggedIn(@NotNull ServerPlayer player) { + resetPlayerData(player); + } + + @ProtocolHandler.PlayerLeave + public static void onPlayerLoggedOut(@NotNull ServerPlayer player) { + subscribedChannels.remove(player); + resetPlayerData(player); + } + + @ProtocolHandler.MinecraftRegister(onlyNamespace = true) + public static void onPlayerSubscribed(@NotNull ServerPlayer player, ResourceLocation id) { + subscribedChannels.computeIfAbsent(player, k -> new HashSet<>()).add(id.getPath()); + } + + @ProtocolHandler.Ticker + public static void tick() { + for (Map.Entry> entry : subscribedChannels.entrySet()) { + ServerPlayer player = entry.getKey(); + FoodData data = player.getFoodData(); + + for (String channel : entry.getValue()) { + switch (channel) { + case "saturation" -> { + float saturation = data.getSaturationLevel(); + Float previousSaturation = previousSaturationLevels.get(player); + if (previousSaturation == null || saturation != previousSaturation) { + ProtocolUtils.sendBytebufPacket(player, SATURATION_KEY, buf -> buf.writeFloat(saturation)); + previousSaturationLevels.put(player, saturation); + } + } + + case "exhaustion" -> { + float exhaustion = data.exhaustionLevel; + Float previousExhaustion = previousExhaustionLevels.get(player); + if (previousExhaustion == null || Math.abs(exhaustion - previousExhaustion) >= MINIMUM_EXHAUSTION_CHANGE_THRESHOLD) { + ProtocolUtils.sendBytebufPacket(player, EXHAUSTION_KEY, buf -> buf.writeFloat(exhaustion)); + previousExhaustionLevels.put(player, exhaustion); + } + } + + case "natural_regeneration" -> { + boolean regeneration = player.level().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION); + Boolean previousRegeneration = previousNaturalRegeneration.get(player); + if (previousRegeneration == null || regeneration != previousRegeneration) { + ProtocolUtils.sendBytebufPacket(player, NATURAL_REGENERATION_KEY, buf -> buf.writeBoolean(regeneration)); + previousNaturalRegeneration.put(player, regeneration); + } + } + } + } + } + } + + @ProtocolHandler.ReloadServer + public static void onServerReload() { + disableAllPlayer(); + } + + public static void disableAllPlayer() { + for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().getPlayers()) { + onPlayerLoggedOut(player); + } + } + + private static void resetPlayerData(@NotNull ServerPlayer player) { + previousExhaustionLevels.remove(player); + previousSaturationLevels.remove(player); + previousNaturalRegeneration.remove(player); + } + + @Override + public int tickerInterval(String tickerID) { + return DivineConfig.NetworkCategory.protocolsAppleSkinSyncTickInterval; + } + + @Override + public boolean isActive() { + return DivineConfig.NetworkCategory.protocolsAppleSkinEnabled; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/XaeroMapProtocol.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/XaeroMapProtocol.java new file mode 100644 index 0000000..9731e97 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/XaeroMapProtocol.java @@ -0,0 +1,46 @@ +package org.leavesmc.leaves.protocol; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import org.bxteam.divinemc.config.DivineConfig; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.core.LeavesProtocol; +import org.leavesmc.leaves.protocol.core.ProtocolUtils; + +@LeavesProtocol.Register(namespace = "xaerominimap_or_xaeroworldmap_i_dont_care") +public class XaeroMapProtocol implements LeavesProtocol { + public static final String PROTOCOL_ID_MINI = "xaerominimap"; + public static final String PROTOCOL_ID_WORLD = "xaeroworldmap"; + + private static final ResourceLocation MINIMAP_KEY = idMini("main"); + private static final ResourceLocation WORLDMAP_KEY = idWorld("main"); + + @Contract("_ -> new") + public static ResourceLocation idMini(String path) { + return ResourceLocation.tryBuild(PROTOCOL_ID_MINI, path); + } + + @Contract("_ -> new") + public static ResourceLocation idWorld(String path) { + return ResourceLocation.tryBuild(PROTOCOL_ID_WORLD, path); + } + + public static void onSendWorldInfo(@NotNull ServerPlayer player) { + if (DivineConfig.NetworkCategory.protocolsMapsXaeroMapEnabled) { + ProtocolUtils.sendBytebufPacket(player, MINIMAP_KEY, buf -> { + buf.writeByte(0); + buf.writeInt(DivineConfig.NetworkCategory.protocolsMapsXaeroMapServerId); + }); + ProtocolUtils.sendBytebufPacket(player, WORLDMAP_KEY, buf -> { + buf.writeByte(0); + buf.writeInt(DivineConfig.NetworkCategory.protocolsMapsXaeroMapServerId); + }); + } + } + + @Override + public boolean isActive() { + return DivineConfig.NetworkCategory.protocolsMapsXaeroMapEnabled; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesCustomPayload.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesCustomPayload.java new file mode 100644 index 0000000..76cf606 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesCustomPayload.java @@ -0,0 +1,29 @@ +package org.leavesmc.leaves.protocol.core; + +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +public interface LeavesCustomPayload extends CustomPacketPayload { + Type LEAVES_TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("leaves", "custom_payload")); + + @Override + default @NotNull Type type() { + return LEAVES_TYPE; + } + + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + @interface ID { + } + + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + @interface Codec { + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocol.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocol.java new file mode 100644 index 0000000..a284840 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocol.java @@ -0,0 +1,20 @@ +package org.leavesmc.leaves.protocol.core; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +public interface LeavesProtocol { + boolean isActive(); + + default int tickerInterval(String tickerID) { + return 1; + } + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @interface Register { + String namespace(); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java new file mode 100644 index 0000000..ab74a47 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java @@ -0,0 +1,455 @@ +package org.leavesmc.leaves.protocol.core; + +import io.netty.buffer.ByteBuf; +import io.papermc.paper.connection.PluginMessageBridgeImpl; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import org.leavesmc.leaves.LeavesLogger; +import org.leavesmc.leaves.protocol.core.invoker.BytebufReceiverInvokerHolder; +import org.leavesmc.leaves.protocol.core.invoker.EmptyInvokerHolder; +import org.leavesmc.leaves.protocol.core.invoker.InitInvokerHolder; +import org.leavesmc.leaves.protocol.core.invoker.MinecraftRegisterInvokerHolder; +import org.leavesmc.leaves.protocol.core.invoker.PayloadReceiverInvokerHolder; +import org.leavesmc.leaves.protocol.core.invoker.PlayerInvokerHolder; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.entity.CraftPlayer; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.JarURLConnection; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class LeavesProtocolManager { + private static final LeavesLogger LOGGER = LeavesLogger.LOGGER; + + private static final Map, PayloadReceiverInvokerHolder> PAYLOAD_RECEIVERS = new HashMap<>(); + private static final Map, ResourceLocation> IDS = new HashMap<>(); + private static final Map, StreamCodec> CODECS = new HashMap<>(); + private static final Map> ID2CODEC = new HashMap<>(); + + private static final Map STRICT_BYTEBUF_RECEIVERS = new HashMap<>(); + private static final Map NAMESPACED_BYTEBUF_RECEIVERS = new HashMap<>(); + private static final List GENERIC_BYTEBUF_RECEIVERS = new ArrayList<>(); + + private static final Map STRICT_MINECRAFT_REGISTER = new HashMap<>(); + private static final Map NAMESPACED_MINECRAFT_REGISTER = new HashMap<>(); + private static final List WILD_MINECRAFT_REGISTER = new ArrayList<>(); + + private static final List> TICKERS = new ArrayList<>(); + + private static final List> PLAYER_JOIN = new ArrayList<>(); + private static final List> PLAYER_LEAVE = new ArrayList<>(); + private static final List> RELOAD_SERVER = new ArrayList<>(); + private static final List> RELOAD_DATAPACK = new ArrayList<>(); + + @SuppressWarnings("unchecked") + public static void init() { + for (Class clazz : getClasses("org.leavesmc.leaves.protocol")) { + if (LeavesCustomPayload.class.isAssignableFrom(clazz) && !clazz.equals(LeavesCustomPayload.class)) { + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + if (!Modifier.isStatic(field.getModifiers())) { + continue; + } + try { + final LeavesCustomPayload.ID id = field.getAnnotation(LeavesCustomPayload.ID.class); + if (id != null && field.getType().equals(ResourceLocation.class)) { + IDS.put((Class) clazz, (ResourceLocation) field.get(null)); + } + final LeavesCustomPayload.Codec codec = field.getAnnotation(LeavesCustomPayload.Codec.class); + if (codec != null && field.getType().equals(StreamCodec.class)) { + CODECS.put((Class) clazz, (StreamCodec) field.get(null)); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + continue; + } + + final LeavesProtocol.Register register = clazz.getAnnotation(LeavesProtocol.Register.class); + if (register == null) { + continue; + } + LeavesProtocol protocol; + try { + Constructor constructor = clazz.getDeclaredConstructor(); + constructor.setAccessible(true); + protocol = (LeavesProtocol) constructor.newInstance(); + } catch (Throwable throwable) { + LOGGER.severe("Failed to load class " + clazz.getName() + ". " + throwable); + return; + } + + boolean active = true; + try { + Method isActiveMethod = clazz.getDeclaredMethod("isActive"); + isActiveMethod.setAccessible(true); + active = (Boolean) isActiveMethod.invoke(protocol); + } catch (Throwable e) { + LOGGER.warning("Failed to check isActive for " + clazz.getName() + ": " + e); + continue; + } + + for (final Method method : clazz.getDeclaredMethods()) { + if (method.isBridge() || method.isSynthetic()) { + continue; + } + method.setAccessible(true); + + final ProtocolHandler.Init init = method.getAnnotation(ProtocolHandler.Init.class); + if (init != null) { + InitInvokerHolder holder = new InitInvokerHolder(protocol, method, init); + try { + holder.invoke(); + } catch (RuntimeException exception) { + LOGGER.severe("Failed to invoke init method " + method.getName() + " in " + clazz.getName() + ", " + exception.getCause() + ": " + exception.getMessage()); + } + continue; + } + + if (!active) continue; + + final ProtocolHandler.ReloadServer reloadServer = method.getAnnotation(ProtocolHandler.ReloadServer.class); + if (reloadServer != null) { + RELOAD_SERVER.add(new EmptyInvokerHolder<>(protocol, method, reloadServer)); + continue; + } + + final ProtocolHandler.ReloadDataPack reloadDataPack = method.getAnnotation(ProtocolHandler.ReloadDataPack.class); + if (reloadDataPack != null) { + RELOAD_DATAPACK.add(new EmptyInvokerHolder<>(protocol, method, reloadDataPack)); + continue; + } + + final ProtocolHandler.PayloadReceiver payloadReceiver = method.getAnnotation(ProtocolHandler.PayloadReceiver.class); + if (payloadReceiver != null) { + PAYLOAD_RECEIVERS.put(payloadReceiver.payload(), new PayloadReceiverInvokerHolder(protocol, method, payloadReceiver)); + continue; + } + + final ProtocolHandler.BytebufReceiver bytebufReceiver = method.getAnnotation(ProtocolHandler.BytebufReceiver.class); + if (bytebufReceiver != null) { + String key = bytebufReceiver.key(); + BytebufReceiverInvokerHolder holder = new BytebufReceiverInvokerHolder(protocol, method, bytebufReceiver); + if (bytebufReceiver.onlyNamespace()) { + NAMESPACED_BYTEBUF_RECEIVERS.put(key.isEmpty() ? register.namespace() : key, holder); + } else { + if (key.isEmpty()) { + GENERIC_BYTEBUF_RECEIVERS.add(holder); + } else { + if (key.contains(":")) { + STRICT_BYTEBUF_RECEIVERS.put(key, holder); + } else { + STRICT_BYTEBUF_RECEIVERS.put(register.namespace() + ":" + key, holder); + } + } + } + continue; + } + + final ProtocolHandler.Ticker ticker = method.getAnnotation(ProtocolHandler.Ticker.class); + if (ticker != null) { + TICKERS.add(new EmptyInvokerHolder<>(protocol, method, ticker)); + continue; + } + + final ProtocolHandler.PlayerJoin playerJoin = method.getAnnotation(ProtocolHandler.PlayerJoin.class); + if (playerJoin != null) { + PLAYER_JOIN.add(new PlayerInvokerHolder<>(protocol, method, playerJoin)); + continue; + } + + final ProtocolHandler.PlayerLeave playerLeave = method.getAnnotation(ProtocolHandler.PlayerLeave.class); + if (playerLeave != null) { + PLAYER_LEAVE.add(new PlayerInvokerHolder<>(protocol, method, playerLeave)); + continue; + } + + final ProtocolHandler.MinecraftRegister minecraftRegister = method.getAnnotation(ProtocolHandler.MinecraftRegister.class); + if (minecraftRegister != null) { + String key = minecraftRegister.key(); + MinecraftRegisterInvokerHolder holder = new MinecraftRegisterInvokerHolder(protocol, method, minecraftRegister); + if (minecraftRegister.onlyNamespace()) { + NAMESPACED_MINECRAFT_REGISTER.put(key.isEmpty() ? register.namespace() : key, holder); + } else { + if (key.isEmpty()) { + WILD_MINECRAFT_REGISTER.add(holder); + } else { + if (key.contains(":")) { + STRICT_MINECRAFT_REGISTER.put(key, holder); + } else { + STRICT_MINECRAFT_REGISTER.put(register.namespace() + ":" + key, holder); + } + } + } + } + } + } + for (var idInfo : IDS.entrySet()) { + var codec = CODECS.get(idInfo.getKey()); + if (codec == null) { + throw new IllegalArgumentException("Payload " + idInfo.getKey() + " is not configured correctly"); + } + ID2CODEC.put(idInfo.getValue(), codec); + } + // Log all found instances + LOGGER.info("Protocol initialization complete. Found instances:"); + LOGGER.info(" Payload receivers: " + PAYLOAD_RECEIVERS.size()); + PAYLOAD_RECEIVERS.forEach((clazz, holder) -> + LOGGER.info(" " + clazz.getSimpleName() + " -> " + holder.getClass().getSimpleName())); + + LOGGER.info(" IDs: " + IDS.size()); + IDS.forEach((clazz, id) -> + LOGGER.info(" " + clazz.getSimpleName() + " -> " + id)); + + LOGGER.info(" Codecs: " + CODECS.size()); + CODECS.forEach((clazz, codec) -> + LOGGER.info(" " + clazz.getSimpleName() + " -> " + codec.getClass().getSimpleName())); + + LOGGER.info(" Strict bytebuf receivers: " + STRICT_BYTEBUF_RECEIVERS.size()); + STRICT_BYTEBUF_RECEIVERS.forEach((key, holder) -> + LOGGER.info(" " + key + " -> " + holder.getClass().getSimpleName())); + + LOGGER.info(" Namespaced bytebuf receivers: " + NAMESPACED_BYTEBUF_RECEIVERS.size()); + NAMESPACED_BYTEBUF_RECEIVERS.forEach((key, holder) -> + LOGGER.info(" " + key + " -> " + holder.getClass().getSimpleName())); + + LOGGER.info(" Generic bytebuf receivers: " + GENERIC_BYTEBUF_RECEIVERS.size()); + GENERIC_BYTEBUF_RECEIVERS.forEach(holder -> + LOGGER.info(" " + holder.getClass().getSimpleName())); + + LOGGER.info(" Tickers: " + TICKERS.size()); + LOGGER.info(" Player join handlers: " + PLAYER_JOIN.size()); + LOGGER.info(" Player leave handlers: " + PLAYER_LEAVE.size()); + LOGGER.info(" Server reload handlers: " + RELOAD_SERVER.size()); + LOGGER.info(" DataPack reload handlers: " + RELOAD_DATAPACK.size()); + + LOGGER.info(" Strict minecraft register: " + STRICT_MINECRAFT_REGISTER.size()); + STRICT_MINECRAFT_REGISTER.forEach((key, holder) -> + LOGGER.info(" " + key + " -> " + holder.getClass().getSimpleName())); + + LOGGER.info(" Namespaced minecraft register: " + NAMESPACED_MINECRAFT_REGISTER.size()); + NAMESPACED_MINECRAFT_REGISTER.forEach((key, holder) -> + LOGGER.info(" " + key + " -> " + holder.getClass().getSimpleName())); + + LOGGER.info(" Wild minecraft register: " + WILD_MINECRAFT_REGISTER.size()); + WILD_MINECRAFT_REGISTER.forEach(holder -> + LOGGER.info(" " + holder.getClass().getSimpleName())); + } + + public static LeavesCustomPayload decode(ResourceLocation location, FriendlyByteBuf buf) { + var codec = ID2CODEC.get(location); + if (codec == null) { + return null; + } + return codec.decode(ProtocolUtils.decorate(buf)); + } + + public static void encode(FriendlyByteBuf buf, LeavesCustomPayload payload) { + var location = IDS.get(payload.getClass()); + var codec = CODECS.get(payload.getClass()); + if (location == null || codec == null) { + throw new IllegalArgumentException("Payload " + payload.getClass() + " is not configured correctly " + location + " " + codec); + } + buf.writeResourceLocation(location); + codec.encode(ProtocolUtils.decorate(buf), payload); + } + + public static void handlePayload(ServerPlayer player, LeavesCustomPayload payload) { + PayloadReceiverInvokerHolder holder; + if ((holder = PAYLOAD_RECEIVERS.get(payload.getClass())) != null) { + holder.invoke(player, payload); + } + } + + public static boolean handleBytebuf(ServerPlayer player, ResourceLocation location, ByteBuf buf) { + RegistryFriendlyByteBuf buf1 = ProtocolUtils.decorate(buf); + BytebufReceiverInvokerHolder holder; + if ((holder = STRICT_BYTEBUF_RECEIVERS.get(location.toString())) != null) { + holder.invoke(player, buf1); + return true; + } + if ((holder = NAMESPACED_BYTEBUF_RECEIVERS.get(location.getNamespace())) != null) { + if (holder.invoke(player, buf1)) { + return true; + } + } + for (var holder1 : GENERIC_BYTEBUF_RECEIVERS) { + if (holder1.invoke(player, buf1)) { + return true; + } + } + return false; + } + + public static void handleTick(long tickCount) { + for (var tickerInfo : TICKERS) { + if (tickCount % tickerInfo.owner().tickerInterval(tickerInfo.handler().tickerId()) == 0) { + tickerInfo.invoke(); + } + } + } + + public static void handlePlayerJoin(ServerPlayer player) { + sendKnownId(player); + for (var join : PLAYER_JOIN) { + join.invoke(player); + } + } + + public static void handlePlayerLeave(ServerPlayer player) { + for (var leave : PLAYER_LEAVE) { + leave.invoke(player); + } + } + + public static void handleServerReload() { + for (var reload : RELOAD_SERVER) { + reload.invoke(); + } + } + + public static void handleDataPackReload() { + for (var reload : RELOAD_DATAPACK) { + reload.invoke(); + } + } + + public static void handleMinecraftRegister(String channelId, PluginMessageBridgeImpl bridge) { + ServerPlayer player = null; + if (bridge instanceof CraftPlayer craftPlayer) { + player = craftPlayer.getHandle(); + } + + if (player == null) { + return; + } + + ResourceLocation location = ResourceLocation.tryParse(channelId); + if (location == null) { + return; + } + + for (var wildHolder : WILD_MINECRAFT_REGISTER) { + wildHolder.invoke(player, location); + } + + MinecraftRegisterInvokerHolder holder; + if ((holder = STRICT_MINECRAFT_REGISTER.get(location.toString())) != null) { + holder.invoke(player, location); + } + if ((holder = NAMESPACED_MINECRAFT_REGISTER.get(location.getNamespace())) != null) { + holder.invoke(player, location); + } + } + + private static void sendKnownId(ServerPlayer player) { + Set set = new HashSet<>(); + PAYLOAD_RECEIVERS.forEach((clazz, holder) -> set.add(IDS.get(clazz).toString())); + STRICT_BYTEBUF_RECEIVERS.forEach((key, holder) -> set.add(key)); + if (set.isEmpty()) return; + ProtocolUtils.sendBytebufPacket(player, ResourceLocation.fromNamespaceAndPath("minecraft", "register"), buf -> { + for (String channel : set) { + buf.writeBytes(channel.getBytes(StandardCharsets.US_ASCII)); + buf.writeByte(0); + } + buf.writerIndex(Math.max(buf.writerIndex() - 1, 0)); + }); + } + + public static Set> getClasses(String pack) { + Set> classes = new LinkedHashSet<>(); + String packageDirName = pack.replace('.', '/'); + Enumeration dirs; + try { + dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); + while (dirs.hasMoreElements()) { + URL url = dirs.nextElement(); + String protocol = url.getProtocol(); + if ("file".equals(protocol)) { + String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8); + findClassesInPackageByFile(pack, filePath, classes); + } else if ("jar".equals(protocol)) { + JarFile jar; + try { + jar = ((JarURLConnection) url.openConnection()).getJarFile(); + Enumeration entries = jar.entries(); + findClassesInPackageByJar(pack, entries, packageDirName, classes); + } catch (IOException exception) { + LOGGER.warning("Failed to load jar file, " + exception.getCause() + ": " + exception.getMessage()); + } + } + } + } catch (IOException exception) { + LOGGER.warning("Failed to load classes, " + exception.getCause() + ": " + exception.getMessage()); + } + return classes; + } + + private static void findClassesInPackageByFile(String packageName, String packagePath, Set> classes) { + File dir = new File(packagePath); + if (!dir.exists() || !dir.isDirectory()) { + return; + } + File[] dirfiles = dir.listFiles((file) -> file.isDirectory() || file.getName().endsWith(".class")); + if (dirfiles != null) { + for (File file : dirfiles) { + if (file.isDirectory()) { + findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), classes); + } else { + String className = file.getName().substring(0, file.getName().length() - 6); + try { + classes.add(Class.forName(packageName + '.' + className)); + } catch (ClassNotFoundException exception) { + LOGGER.warning("Failed to load class " + className + ", " + exception.getCause() + ": " + exception.getMessage()); + } + } + } + } + } + + private static void findClassesInPackageByJar(String packageName, Enumeration entries, String packageDirName, Set> classes) { + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String name = entry.getName(); + if (name.charAt(0) == '/') { + name = name.substring(1); + } + if (name.startsWith(packageDirName)) { + int idx = name.lastIndexOf('/'); + if (idx != -1) { + packageName = name.substring(0, idx).replace('/', '.'); + } + if (name.endsWith(".class") && !entry.isDirectory()) { + String className = name.substring(packageName.length() + 1, name.length() - 6); + try { + classes.add(Class.forName(packageName + '.' + className)); + } catch (ClassNotFoundException exception) { + LOGGER.warning("Failed to load class " + className + ", " + exception.getCause() + ": " + exception.getMessage()); + } + } + } + } + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolHandler.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolHandler.java new file mode 100644 index 0000000..8bf4a4c --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolHandler.java @@ -0,0 +1,61 @@ +package org.leavesmc.leaves.protocol.core; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +public class ProtocolHandler { + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface Init { + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface PayloadReceiver { + Class payload(); + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface BytebufReceiver { + String key() default ""; + + boolean onlyNamespace() default false; + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface Ticker { + String tickerId() default ""; + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface PlayerJoin { + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface PlayerLeave { + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface ReloadServer { + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface MinecraftRegister { + String key() default ""; + + boolean onlyNamespace() default false; + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface ReloadDataPack { + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolUtils.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolUtils.java new file mode 100644 index 0000000..82cb8ab --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/ProtocolUtils.java @@ -0,0 +1,43 @@ +package org.leavesmc.leaves.protocol.core; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.papermc.paper.ServerBuildInfo; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.network.protocol.common.custom.DiscardedPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; +import java.util.function.Function; + +public class ProtocolUtils { + private static final Function bufDecorator = buf -> buf instanceof RegistryFriendlyByteBuf registry ? registry : new RegistryFriendlyByteBuf(buf, MinecraftServer.getServer().registryAccess()); + + public static String buildProtocolVersion(String protocol) { + return protocol + "-leaves-" + ServerBuildInfo.buildInfo().asString(ServerBuildInfo.StringRepresentation.VERSION_SIMPLE); + } + + public static void sendEmptyPacket(ServerPlayer player, ResourceLocation id) { + player.internalConnection.send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, null))); + } + + public static void sendBytebufPacket(@NotNull ServerPlayer player, ResourceLocation id, Consumer consumer) { + RegistryFriendlyByteBuf buf = decorate(Unpooled.buffer()); + consumer.accept(buf); + player.internalConnection.send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, ByteBufUtil.getBytes(buf)))); + } + + public static void sendPayloadPacket(ServerPlayer player, CustomPacketPayload payload) { + player.internalConnection.send(new ClientboundCustomPayloadPacket(payload)); + } + + public static RegistryFriendlyByteBuf decorate(ByteBuf buf) { + return bufDecorator.apply(buf); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/AbstractInvokerHolder.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/AbstractInvokerHolder.java new file mode 100644 index 0000000..ebb2bee --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/AbstractInvokerHolder.java @@ -0,0 +1,69 @@ +package org.leavesmc.leaves.protocol.core.invoker; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.core.LeavesProtocol; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +public abstract class AbstractInvokerHolder { + protected final LeavesProtocol owner; + protected final Method invoker; + protected final T handler; + protected final Class returnType; + protected final Class[] parameterTypes; + + protected AbstractInvokerHolder(LeavesProtocol owner, Method invoker, T handler, @Nullable Class returnType, @NotNull Class... parameterTypes) { + this.owner = owner; + this.invoker = invoker; + this.handler = handler; + this.returnType = returnType; + this.parameterTypes = parameterTypes; + + validateMethodSignature(); + } + + protected void validateMethodSignature() { + if (returnType != null && !returnType.isAssignableFrom(invoker.getReturnType())) { + throw new IllegalArgumentException("Return type mismatch in " + owner.getClass().getName() + "#" + invoker.getName() + + ": expected " + returnType.getName() + " but found " + invoker.getReturnType().getName()); + } + + Class[] methodParamTypes = invoker.getParameterTypes(); + if (methodParamTypes.length != parameterTypes.length) { + throw new IllegalArgumentException("Parameter count mismatch in " + owner.getClass().getName() + "#" + invoker.getName() + + ": expected " + parameterTypes.length + " but found " + methodParamTypes.length); + } + + for (int i = 0; i < parameterTypes.length; i++) { + if (!parameterTypes[i].isAssignableFrom(methodParamTypes[i])) { + throw new IllegalArgumentException("Parameter type mismatch in " + owner.getClass().getName() + "#" + invoker.getName() + + " at index " + i + ": expected " + parameterTypes[i].getName() + " but found " + methodParamTypes[i].getName()); + } + } + } + + public LeavesProtocol owner() { + return owner; + } + + public T handler() { + return handler; + } + + protected Object invoke0(boolean force, Object... args) { + if (!force && !owner.isActive()) { + return null; + } + try { + if (Modifier.isStatic(invoker.getModifiers())) { + return invoker.invoke(null, args); + } else { + return invoker.invoke(owner, args); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/BytebufReceiverInvokerHolder.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/BytebufReceiverInvokerHolder.java new file mode 100644 index 0000000..e2c01b8 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/BytebufReceiverInvokerHolder.java @@ -0,0 +1,18 @@ +package org.leavesmc.leaves.protocol.core.invoker; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import org.leavesmc.leaves.protocol.core.LeavesProtocol; +import org.leavesmc.leaves.protocol.core.ProtocolHandler; + +import java.lang.reflect.Method; + +public class BytebufReceiverInvokerHolder extends AbstractInvokerHolder { + public BytebufReceiverInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.BytebufReceiver handler) { + super(owner, invoker, handler, null, ServerPlayer.class, FriendlyByteBuf.class); + } + + public boolean invoke(ServerPlayer player, FriendlyByteBuf buf) { + return invoke0(false, player, buf) instanceof Boolean b && b; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/EmptyInvokerHolder.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/EmptyInvokerHolder.java new file mode 100644 index 0000000..d6e18d3 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/EmptyInvokerHolder.java @@ -0,0 +1,15 @@ +package org.leavesmc.leaves.protocol.core.invoker; + +import org.leavesmc.leaves.protocol.core.LeavesProtocol; + +import java.lang.reflect.Method; + +public class EmptyInvokerHolder extends AbstractInvokerHolder { + public EmptyInvokerHolder(LeavesProtocol owner, Method invoker, T handler) { + super(owner, invoker, handler, null); + } + + public void invoke() { + invoke0(false); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/InitInvokerHolder.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/InitInvokerHolder.java new file mode 100644 index 0000000..128aaf8 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/InitInvokerHolder.java @@ -0,0 +1,16 @@ +package org.leavesmc.leaves.protocol.core.invoker; + +import org.leavesmc.leaves.protocol.core.LeavesProtocol; +import org.leavesmc.leaves.protocol.core.ProtocolHandler; + +import java.lang.reflect.Method; + +public class InitInvokerHolder extends AbstractInvokerHolder { + public InitInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.Init handler) { + super(owner, invoker, handler, null); + } + + public void invoke() { + invoke0(true); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/MinecraftRegisterInvokerHolder.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/MinecraftRegisterInvokerHolder.java new file mode 100644 index 0000000..c6766bc --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/MinecraftRegisterInvokerHolder.java @@ -0,0 +1,18 @@ +package org.leavesmc.leaves.protocol.core.invoker; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import org.leavesmc.leaves.protocol.core.LeavesProtocol; +import org.leavesmc.leaves.protocol.core.ProtocolHandler; + +import java.lang.reflect.Method; + +public class MinecraftRegisterInvokerHolder extends AbstractInvokerHolder { + public MinecraftRegisterInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.MinecraftRegister handler) { + super(owner, invoker, handler, null, ServerPlayer.class, ResourceLocation.class); + } + + public void invoke(ServerPlayer player, ResourceLocation id) { + invoke0(false, player, id); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/PayloadReceiverInvokerHolder.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/PayloadReceiverInvokerHolder.java new file mode 100644 index 0000000..bed868b --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/PayloadReceiverInvokerHolder.java @@ -0,0 +1,18 @@ +package org.leavesmc.leaves.protocol.core.invoker; + +import net.minecraft.server.level.ServerPlayer; +import org.leavesmc.leaves.protocol.core.LeavesCustomPayload; +import org.leavesmc.leaves.protocol.core.LeavesProtocol; +import org.leavesmc.leaves.protocol.core.ProtocolHandler; + +import java.lang.reflect.Method; + +public class PayloadReceiverInvokerHolder extends AbstractInvokerHolder { + public PayloadReceiverInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.PayloadReceiver handler) { + super(owner, invoker, handler, null, ServerPlayer.class, handler.payload()); + } + + public void invoke(ServerPlayer player, LeavesCustomPayload payload) { + invoke0(false, player, payload); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/PlayerInvokerHolder.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/PlayerInvokerHolder.java new file mode 100644 index 0000000..5ed2c2d --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/invoker/PlayerInvokerHolder.java @@ -0,0 +1,16 @@ +package org.leavesmc.leaves.protocol.core.invoker; + +import net.minecraft.server.level.ServerPlayer; +import org.leavesmc.leaves.protocol.core.LeavesProtocol; + +import java.lang.reflect.Method; + +public class PlayerInvokerHolder extends AbstractInvokerHolder { + public PlayerInvokerHolder(LeavesProtocol owner, Method invoker, T handler) { + super(owner, invoker, handler, null, ServerPlayer.class); + } + + public void invoke(ServerPlayer player) { + invoke0(false, player); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java new file mode 100644 index 0000000..d5727e8 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java @@ -0,0 +1,290 @@ +package org.leavesmc.leaves.protocol.jade; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.AgeableMob; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.animal.Animal; +import net.minecraft.world.entity.animal.Chicken; +import net.minecraft.world.entity.animal.allay.Allay; +import net.minecraft.world.entity.animal.armadillo.Armadillo; +import net.minecraft.world.entity.animal.frog.Tadpole; +import net.minecraft.world.entity.animal.sniffer.Sniffer; +import net.minecraft.world.entity.monster.ZombieVillager; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.CampfireBlock; +import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; +import net.minecraft.world.level.block.entity.BeehiveBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; +import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity; +import net.minecraft.world.level.block.entity.ChiseledBookShelfBlockEntity; +import net.minecraft.world.level.block.entity.CommandBlockEntity; +import net.minecraft.world.level.block.entity.ComparatorBlockEntity; +import net.minecraft.world.level.block.entity.HopperBlockEntity; +import net.minecraft.world.level.block.entity.JukeboxBlockEntity; +import net.minecraft.world.level.block.entity.LecternBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import org.bukkit.Bukkit; +import org.bxteam.divinemc.config.DivineConfig; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.LeavesLogger; +import org.leavesmc.leaves.protocol.core.LeavesProtocol; +import org.leavesmc.leaves.protocol.core.ProtocolHandler; +import org.leavesmc.leaves.protocol.core.ProtocolUtils; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.payload.ClientHandshakePayload; +import org.leavesmc.leaves.protocol.jade.payload.ReceiveDataPayload; +import org.leavesmc.leaves.protocol.jade.payload.RequestBlockPayload; +import org.leavesmc.leaves.protocol.jade.payload.RequestEntityPayload; +import org.leavesmc.leaves.protocol.jade.payload.ServerHandshakePayload; +import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider; +import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider; +import org.leavesmc.leaves.protocol.jade.provider.IServerExtensionProvider; +import org.leavesmc.leaves.protocol.jade.provider.ItemStorageExtensionProvider; +import org.leavesmc.leaves.protocol.jade.provider.ItemStorageProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.BeehiveProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.BlockNameProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.BrewingStandProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.CampfireProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.ChiseledBookshelfProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.CommandBlockProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.FurnaceProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.HopperLockProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.JukeboxProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.LecternProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.MobSpawnerCooldownProvider; +import org.leavesmc.leaves.protocol.jade.provider.block.RedstoneProvider; +import org.leavesmc.leaves.protocol.jade.provider.entity.AnimalOwnerProvider; +import org.leavesmc.leaves.protocol.jade.provider.entity.MobBreedingProvider; +import org.leavesmc.leaves.protocol.jade.provider.entity.MobGrowthProvider; +import org.leavesmc.leaves.protocol.jade.provider.entity.NextEntityDropProvider; +import org.leavesmc.leaves.protocol.jade.provider.entity.PetArmorProvider; +import org.leavesmc.leaves.protocol.jade.provider.entity.StatusEffectsProvider; +import org.leavesmc.leaves.protocol.jade.provider.entity.ZombieVillagerProvider; +import org.leavesmc.leaves.protocol.jade.util.HierarchyLookup; +import org.leavesmc.leaves.protocol.jade.util.LootTableMineableCollector; +import org.leavesmc.leaves.protocol.jade.util.PairHierarchyLookup; +import org.leavesmc.leaves.protocol.jade.util.PriorityStore; +import org.leavesmc.leaves.protocol.jade.util.WrappedHierarchyLookup; +import org.leavesmc.leaves.util.NbtUtils; +import org.purpurmc.purpur.util.MinecraftInternalPlugin; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@LeavesProtocol.Register(namespace = "jade") +public class JadeProtocol implements LeavesProtocol { + + public static final String PROTOCOL_ID = "jade"; + public static final String PROTOCOL_VERSION = "7"; + public static final HierarchyLookup> entityDataProviders = new HierarchyLookup<>(Entity.class); + public static final PairHierarchyLookup> blockDataProviders = new PairHierarchyLookup<>(new HierarchyLookup<>(Block.class), new HierarchyLookup<>(BlockEntity.class)); + public static final WrappedHierarchyLookup> itemStorageProviders = WrappedHierarchyLookup.forAccessor(); + private static final Set enabledPlayers = new HashSet<>(); + private static final org.purpurmc.purpur.util.MinecraftInternalPlugin minecraftInternalPlugin = new org.purpurmc.purpur.util.MinecraftInternalPlugin(); + + public static PriorityStore priorities; + private static List shearableBlocks = null; + + @Contract("_ -> new") + public static ResourceLocation id(String path) { + return ResourceLocation.tryBuild(PROTOCOL_ID, path); + } + + @Contract("_ -> new") + public static @NotNull ResourceLocation mc_id(String path) { + return ResourceLocation.withDefaultNamespace(path); + } + + @ProtocolHandler.Init + public static void init() { + priorities = new PriorityStore<>(IJadeProvider::getDefaultPriority, IJadeProvider::getUid); + + // core plugin + blockDataProviders.register(BlockEntity.class, BlockNameProvider.INSTANCE); + + // universal plugin + entityDataProviders.register(Entity.class, ItemStorageProvider.getEntity()); + blockDataProviders.register(Block.class, ItemStorageProvider.getBlock()); + + itemStorageProviders.register(Object.class, ItemStorageExtensionProvider.INSTANCE); + itemStorageProviders.register(Block.class, ItemStorageExtensionProvider.INSTANCE); + + // vanilla plugin + entityDataProviders.register(Entity.class, AnimalOwnerProvider.INSTANCE); + entityDataProviders.register(LivingEntity.class, StatusEffectsProvider.INSTANCE); + entityDataProviders.register(AgeableMob.class, MobGrowthProvider.INSTANCE); + entityDataProviders.register(Tadpole.class, MobGrowthProvider.INSTANCE); + entityDataProviders.register(Animal.class, MobBreedingProvider.INSTANCE); + entityDataProviders.register(Allay.class, MobBreedingProvider.INSTANCE); + entityDataProviders.register(Mob.class, PetArmorProvider.INSTANCE); + + entityDataProviders.register(Chicken.class, NextEntityDropProvider.INSTANCE); + entityDataProviders.register(Armadillo.class, NextEntityDropProvider.INSTANCE); + entityDataProviders.register(Sniffer.class, NextEntityDropProvider.INSTANCE); + + entityDataProviders.register(ZombieVillager.class, ZombieVillagerProvider.INSTANCE); + + blockDataProviders.register(BrewingStandBlockEntity.class, BrewingStandProvider.INSTANCE); + blockDataProviders.register(BeehiveBlockEntity.class, BeehiveProvider.INSTANCE); + blockDataProviders.register(CommandBlockEntity.class, CommandBlockProvider.INSTANCE); + blockDataProviders.register(JukeboxBlockEntity.class, JukeboxProvider.INSTANCE); + blockDataProviders.register(LecternBlockEntity.class, LecternProvider.INSTANCE); + + blockDataProviders.register(ComparatorBlockEntity.class, RedstoneProvider.INSTANCE); + blockDataProviders.register(HopperBlockEntity.class, HopperLockProvider.INSTANCE); + blockDataProviders.register(CalibratedSculkSensorBlockEntity.class, RedstoneProvider.INSTANCE); + + blockDataProviders.register(AbstractFurnaceBlockEntity.class, FurnaceProvider.INSTANCE); + blockDataProviders.register(ChiseledBookShelfBlockEntity.class, ChiseledBookshelfProvider.INSTANCE); + blockDataProviders.register(TrialSpawnerBlockEntity.class, MobSpawnerCooldownProvider.INSTANCE); + + itemStorageProviders.register(CampfireBlock.class, CampfireProvider.INSTANCE); + + blockDataProviders.idMapped(); + entityDataProviders.idMapped(); + + blockDataProviders.loadComplete(priorities); + entityDataProviders.loadComplete(priorities); + itemStorageProviders.loadComplete(priorities); + + rebuildShearableBlocks(); + } + + @ProtocolHandler.PayloadReceiver(payload = ClientHandshakePayload.class) + public static void clientHandshake(ServerPlayer player, ClientHandshakePayload payload) { + if (!payload.protocolVersion().equals(PROTOCOL_VERSION)) { + player.sendSystemMessage(Component.literal("You are using a different version of Jade than the server. Please update Jade or report to the server operator").withColor(0xff0000)); + return; + } + ProtocolUtils.sendPayloadPacket(player, new ServerHandshakePayload(Collections.emptyMap(), shearableBlocks, blockDataProviders.mappedIds(), entityDataProviders.mappedIds())); + enabledPlayers.add(player); + } + + @ProtocolHandler.PlayerLeave + public static void onPlayerLeave(ServerPlayer player) { + enabledPlayers.remove(player); + } + + @ProtocolHandler.PayloadReceiver(payload = RequestEntityPayload.class) + public static void requestEntityData(ServerPlayer player, RequestEntityPayload payload) { + Bukkit.getGlobalRegionScheduler().run(minecraftInternalPlugin, (task) -> { + EntityAccessor accessor = payload.data().unpack(player); + if (accessor == null) { + return; + } + + Entity entity = accessor.getEntity(); + double maxDistance = Mth.square(player.entityInteractionRange() + 21); + if (entity == null || player.distanceToSqr(entity) > maxDistance) { + return; + } + + List> providers = entityDataProviders.get(entity); + if (providers.isEmpty()) { + return; + } + + CompoundTag tag = new CompoundTag(); + for (IServerDataProvider provider : providers) { + if (!payload.dataProviders().contains(provider)) { + continue; + } + try { + provider.appendServerData(tag, accessor); + } catch (Exception e) { + LeavesLogger.LOGGER.warning("Error while saving data for entity " + entity); + } + } + tag.putInt("EntityId", entity.getId()); + + ProtocolUtils.sendPayloadPacket(player, new ReceiveDataPayload(tag)); + }); + } + + @ProtocolHandler.PayloadReceiver(payload = RequestBlockPayload.class) + public static void requestBlockData(ServerPlayer player, RequestBlockPayload payload) { + Bukkit.getGlobalRegionScheduler().run(minecraftInternalPlugin, (task) -> { + BlockAccessor accessor = payload.data().unpack(player); + if (accessor == null) { + return; + } + + BlockPos pos = accessor.getPosition(); + Block block = accessor.getBlock(); + BlockEntity blockEntity = accessor.getBlockEntity(); + double maxDistance = Mth.square(player.blockInteractionRange() + 21); + if (pos.distSqr(player.blockPosition()) > maxDistance || !accessor.getLevel().isLoaded(pos)) { + return; + } + + List> providers; + if (blockEntity != null) { + providers = blockDataProviders.getMerged(block, blockEntity); + } else { + providers = blockDataProviders.first.get(block); + } + + if (providers.isEmpty()) { + return; + } + + CompoundTag tag = new CompoundTag(); + for (IServerDataProvider provider : providers) { + if (!payload.dataProviders().contains(provider)) { + continue; + } + try { + provider.appendServerData(tag, accessor); + } catch (Exception e) { + LeavesLogger.LOGGER.warning("Error while saving data for block " + accessor.getBlockState()); + } + } + NbtUtils.writeBlockPosToTag(pos, tag); + tag.putString("BlockId", BuiltInRegistries.BLOCK.getKey(block).toString()); + + ProtocolUtils.sendPayloadPacket(player, new ReceiveDataPayload(tag)); + }); + } + + @ProtocolHandler.ReloadServer + public static void onServerReload() { + rebuildShearableBlocks(); + for (ServerPlayer player : enabledPlayers) { + ProtocolUtils.sendPayloadPacket(player, new ServerHandshakePayload(Collections.emptyMap(), shearableBlocks, blockDataProviders.mappedIds(), entityDataProviders.mappedIds())); + } + } + + private static void rebuildShearableBlocks() { + try { + shearableBlocks = Collections.unmodifiableList(LootTableMineableCollector.execute( + MinecraftServer.getServer().reloadableRegistries().lookup().lookupOrThrow(Registries.LOOT_TABLE), + Items.SHEARS.getDefaultInstance() + )); + } catch (Throwable ignore) { + shearableBlocks = List.of(); + LeavesLogger.LOGGER.severe("Failed to collect shearable blocks"); + } + } + + @Override + public boolean isActive() { + return DivineConfig.NetworkCategory.protocolsJadeEnabled; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java new file mode 100644 index 0000000..6bc2253 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java @@ -0,0 +1,22 @@ +package org.leavesmc.leaves.protocol.jade.accessor; + +import net.minecraft.nbt.Tag; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamEncoder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.Nullable; + +public interface Accessor { + Level getLevel(); + + Player getPlayer(); + + Tag encodeAsNbt(StreamEncoder codec, D value); + + T getHitResult(); + + @Nullable + Object getTarget(); +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java new file mode 100644 index 0000000..a6d91d9 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java @@ -0,0 +1,60 @@ +package org.leavesmc.leaves.protocol.jade.accessor; + +import io.netty.buffer.Unpooled; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamEncoder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.HitResult; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.function.Supplier; + +public abstract class AccessorImpl implements Accessor { + + private final Level level; + private final Player player; + private final Supplier hit; + protected boolean verify; + private RegistryFriendlyByteBuf buffer; + + public AccessorImpl(Level level, Player player, Supplier hit) { + this.level = level; + this.player = player; + this.hit = hit; + } + + @Override + public Level getLevel() { + return level; + } + + @Override + public Player getPlayer() { + return player; + } + + private RegistryFriendlyByteBuf buffer() { + if (buffer == null) { + buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), level.registryAccess()); + } + buffer.clear(); + return buffer; + } + + @Override + public Tag encodeAsNbt(StreamEncoder streamCodec, D value) { + RegistryFriendlyByteBuf buffer = buffer(); + streamCodec.encode(buffer, value); + ByteArrayTag tag = new ByteArrayTag(ArrayUtils.subarray(buffer.array(), 0, buffer.readableBytes())); + buffer.clear(); + return tag; + } + + @Override + public T getHitResult() { + return hit.get(); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessor.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessor.java new file mode 100644 index 0000000..133415a --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessor.java @@ -0,0 +1,44 @@ +package org.leavesmc.leaves.protocol.jade.accessor; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.ApiStatus; + +import java.util.function.Supplier; + +public interface BlockAccessor extends Accessor { + + Block getBlock(); + + BlockState getBlockState(); + + BlockEntity getBlockEntity(); + + BlockPos getPosition(); + + @ApiStatus.NonExtendable + interface Builder { + Builder level(Level level); + + Builder player(Player player); + + Builder hit(BlockHitResult hit); + + Builder blockState(BlockState state); + + default Builder blockEntity(BlockEntity blockEntity) { + return blockEntity(() -> blockEntity); + } + + Builder blockEntity(Supplier blockEntity); + + Builder from(BlockAccessor accessor); + + BlockAccessor build(); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java new file mode 100644 index 0000000..a94bb9e --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java @@ -0,0 +1,143 @@ +package org.leavesmc.leaves.protocol.jade.accessor; + +import com.google.common.base.Suppliers; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +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.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +/** + * Class to get information of block target and context. + */ +public class BlockAccessorImpl extends AccessorImpl implements BlockAccessor { + + private final BlockState blockState; + @Nullable + private final Supplier blockEntity; + + private BlockAccessorImpl(Builder builder) { + super(builder.level, builder.player, Suppliers.ofInstance(builder.hit)); + blockState = builder.blockState; + blockEntity = builder.blockEntity; + } + + @Override + public Block getBlock() { + return getBlockState().getBlock(); + } + + @Override + public BlockState getBlockState() { + return blockState; + } + + @Override + public BlockEntity getBlockEntity() { + return blockEntity == null ? null : blockEntity.get(); + } + + @Override + public BlockPos getPosition() { + return getHitResult().getBlockPos(); + } + + @Nullable + @Override + public Object getTarget() { + return getBlockEntity(); + } + + public static class Builder implements BlockAccessor.Builder { + private Level level; + private Player player; + private BlockHitResult hit; + private BlockState blockState = Blocks.AIR.defaultBlockState(); + private Supplier blockEntity; + + @Override + public Builder level(Level level) { + this.level = level; + return this; + } + + @Override + public Builder player(Player player) { + this.player = player; + return this; + } + + @Override + public Builder hit(BlockHitResult hit) { + this.hit = hit; + return this; + } + + @Override + public Builder blockState(BlockState blockState) { + this.blockState = blockState; + return this; + } + + @Override + public Builder blockEntity(Supplier blockEntity) { + this.blockEntity = blockEntity; + return this; + } + + @Override + public Builder from(BlockAccessor accessor) { + level = accessor.getLevel(); + player = accessor.getPlayer(); + hit = accessor.getHitResult(); + blockEntity = accessor::getBlockEntity; + blockState = accessor.getBlockState(); + return this; + } + + @Override + public BlockAccessor build() { + return new BlockAccessorImpl(this); + } + } + + public record SyncData(boolean showDetails, BlockHitResult hit, BlockState blockState, ItemStack fakeBlock) { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.BOOL, + SyncData::showDetails, + StreamCodec.of(FriendlyByteBuf::writeBlockHitResult, FriendlyByteBuf::readBlockHitResult), + SyncData::hit, + ByteBufCodecs.idMapper(Block.BLOCK_STATE_REGISTRY), + SyncData::blockState, + ItemStack.OPTIONAL_STREAM_CODEC, + SyncData::fakeBlock, + SyncData::new + ); + + public BlockAccessor unpack(ServerPlayer player) { + Supplier blockEntity = null; + if (blockState.hasBlockEntity()) { + blockEntity = Suppliers.memoize(() -> player.level().getBlockEntity(hit.getBlockPos())); + } + return new Builder() + .level(player.level()) + .player(player) + .hit(hit) + .blockState(blockState) + .blockEntity(blockEntity) + .build(); + } + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessor.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessor.java new file mode 100644 index 0000000..00fd87b --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessor.java @@ -0,0 +1,42 @@ +package org.leavesmc.leaves.protocol.jade.accessor; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.EntityHitResult; +import org.jetbrains.annotations.ApiStatus; + +import java.util.function.Supplier; + +public interface EntityAccessor extends Accessor { + + Entity getEntity(); + + /** + * For part entity like ender dragon's, getEntity() will return the parent entity. + */ + Entity getRawEntity(); + + @ApiStatus.NonExtendable + interface Builder { + Builder level(Level level); + + Builder player(Player player); + + default Builder hit(EntityHitResult hit) { + return hit(() -> hit); + } + + Builder hit(Supplier hit); + + default Builder entity(Entity entity) { + return entity(() -> entity); + } + + Builder entity(Supplier entity); + + Builder from(EntityAccessor accessor); + + EntityAccessor build(); + } +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java new file mode 100644 index 0000000..56166c6 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java @@ -0,0 +1,112 @@ +package org.leavesmc.leaves.protocol.jade.accessor; + +import com.google.common.base.Suppliers; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.util.CommonUtil; + +import java.util.function.Supplier; + +public class EntityAccessorImpl extends AccessorImpl implements EntityAccessor { + + private final Supplier entity; + + public EntityAccessorImpl(Builder builder) { + super(builder.level, builder.player, builder.hit); + entity = builder.entity; + } + + @Override + public Entity getEntity() { + return CommonUtil.wrapPartEntityParent(getRawEntity()); + } + + @Override + public Entity getRawEntity() { + return entity.get(); + } + + @NotNull + @Override + public Object getTarget() { + return getEntity(); + } + + public static class Builder implements EntityAccessor.Builder { + private Level level; + private Player player; + private Supplier hit; + private Supplier entity; + + @Override + public Builder level(Level level) { + this.level = level; + return this; + } + + @Override + public Builder player(Player player) { + this.player = player; + return this; + } + + + @Override + public Builder hit(Supplier hit) { + this.hit = hit; + return this; + } + + @Override + public Builder entity(Supplier entity) { + this.entity = entity; + return this; + } + + @Override + public Builder from(EntityAccessor accessor) { + level = accessor.getLevel(); + player = accessor.getPlayer(); + hit = accessor::getHitResult; + entity = accessor::getEntity; + return this; + } + + @Override + public EntityAccessor build() { + return new EntityAccessorImpl(this); + } + } + + public record SyncData(boolean showDetails, int id, int partIndex, Vec3 hitVec) { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.BOOL, + SyncData::showDetails, + ByteBufCodecs.VAR_INT, + SyncData::id, + ByteBufCodecs.VAR_INT, + SyncData::partIndex, + ByteBufCodecs.VECTOR3F.map(Vec3::new, Vec3::toVector3f), + SyncData::hitVec, + SyncData::new + ); + + public EntityAccessor unpack(ServerPlayer player) { + Supplier entity = Suppliers.memoize(() -> CommonUtil.getPartEntity(player.level().getEntity(id), partIndex)); + return new EntityAccessorImpl.Builder() + .level(player.level()) + .player(player) + .entity(entity) + .hit(Suppliers.memoize(() -> new EntityHitResult(entity.get(), hitVec))) + .build(); + } + } +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ClientHandshakePayload.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ClientHandshakePayload.java new file mode 100644 index 0000000..1620d68 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ClientHandshakePayload.java @@ -0,0 +1,19 @@ +package org.leavesmc.leaves.protocol.jade.payload; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import org.leavesmc.leaves.protocol.core.LeavesCustomPayload; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; + +public record ClientHandshakePayload(String protocolVersion) implements LeavesCustomPayload { + + @ID + private static final ResourceLocation PACKET_CLIENT_HANDSHAKE = JadeProtocol.id("client_handshake"); + + @Codec + private static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, ClientHandshakePayload::protocolVersion, ClientHandshakePayload::new + ); +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ReceiveDataPayload.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ReceiveDataPayload.java new file mode 100644 index 0000000..b2630fc --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ReceiveDataPayload.java @@ -0,0 +1,20 @@ +package org.leavesmc.leaves.protocol.jade.payload; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import org.leavesmc.leaves.protocol.core.LeavesCustomPayload; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; + +public record ReceiveDataPayload(CompoundTag tag) implements LeavesCustomPayload { + + @ID + private static final ResourceLocation PACKET_RECEIVE_DATA = JadeProtocol.id("receive_data"); + + @Codec + private static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.COMPOUND_TAG, ReceiveDataPayload::tag, ReceiveDataPayload::new + ); +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestBlockPayload.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestBlockPayload.java new file mode 100644 index 0000000..9d32bf2 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestBlockPayload.java @@ -0,0 +1,35 @@ +package org.leavesmc.leaves.protocol.jade.payload; + +import io.netty.buffer.ByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.core.LeavesCustomPayload; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessorImpl; +import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider; + +import java.util.List; +import java.util.Objects; + +import static org.leavesmc.leaves.protocol.jade.JadeProtocol.blockDataProviders; + +public record RequestBlockPayload(BlockAccessorImpl.SyncData data, List<@Nullable IServerDataProvider> dataProviders) implements LeavesCustomPayload { + + @ID + private static final ResourceLocation PACKET_REQUEST_BLOCK = JadeProtocol.id("request_block"); + + @Codec + private static final StreamCodec CODEC = StreamCodec.composite( + BlockAccessorImpl.SyncData.STREAM_CODEC, + RequestBlockPayload::data, + ByteBufCodecs.>list() + .apply(ByteBufCodecs.idMapper( + $ -> Objects.requireNonNull(blockDataProviders.idMapper()).byId($), + $ -> Objects.requireNonNull(blockDataProviders.idMapper()).getIdOrThrow($))), + RequestBlockPayload::dataProviders, + RequestBlockPayload::new); +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestEntityPayload.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestEntityPayload.java new file mode 100644 index 0000000..70dd289 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestEntityPayload.java @@ -0,0 +1,36 @@ +package org.leavesmc.leaves.protocol.jade.payload; + +import io.netty.buffer.ByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.core.LeavesCustomPayload; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessorImpl; +import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider; + +import java.util.List; +import java.util.Objects; + +import static org.leavesmc.leaves.protocol.jade.JadeProtocol.entityDataProviders; + +public record RequestEntityPayload(EntityAccessorImpl.SyncData data, List<@Nullable IServerDataProvider> dataProviders) implements LeavesCustomPayload { + + @ID + private static final ResourceLocation PACKET_REQUEST_ENTITY = JadeProtocol.id("request_entity"); + + @Codec + private static final StreamCodec CODEC = StreamCodec.composite( + EntityAccessorImpl.SyncData.STREAM_CODEC, + RequestEntityPayload::data, + ByteBufCodecs.>list() + .apply(ByteBufCodecs.idMapper( + $ -> Objects.requireNonNull(entityDataProviders.idMapper()).byId($), + $ -> Objects.requireNonNull(entityDataProviders.idMapper()).getIdOrThrow($) + )), + RequestEntityPayload::dataProviders, + RequestEntityPayload::new); +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ServerHandshakePayload.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ServerHandshakePayload.java new file mode 100644 index 0000000..4955e0e --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ServerHandshakePayload.java @@ -0,0 +1,37 @@ +package org.leavesmc.leaves.protocol.jade.payload; + + +import com.google.common.collect.Maps; +import io.netty.buffer.ByteBuf; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import org.leavesmc.leaves.protocol.core.LeavesCustomPayload; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; + +import java.util.List; +import java.util.Map; + +import static org.leavesmc.leaves.protocol.jade.util.JadeCodec.PRIMITIVE_STREAM_CODEC; + +public record ServerHandshakePayload(Map serverConfig, List shearableBlocks, List blockProviderIds, List entityProviderIds) implements LeavesCustomPayload { + + @ID + private static final ResourceLocation PACKET_SERVER_HANDSHAKE = JadeProtocol.id("server_handshake"); + + @Codec + private static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.map(Maps::newHashMapWithExpectedSize, ResourceLocation.STREAM_CODEC, PRIMITIVE_STREAM_CODEC), + ServerHandshakePayload::serverConfig, + ByteBufCodecs.registry(Registries.BLOCK).apply(ByteBufCodecs.list()), + ServerHandshakePayload::shearableBlocks, + ByteBufCodecs.list().apply(ResourceLocation.STREAM_CODEC), + ServerHandshakePayload::blockProviderIds, + ByteBufCodecs.list().apply(ResourceLocation.STREAM_CODEC), + ServerHandshakePayload::entityProviderIds, + ServerHandshakePayload::new + ); +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IJadeProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IJadeProvider.java new file mode 100644 index 0000000..d62fc8f --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IJadeProvider.java @@ -0,0 +1,12 @@ +package org.leavesmc.leaves.protocol.jade.provider; + +import net.minecraft.resources.ResourceLocation; + +public interface IJadeProvider { + + ResourceLocation getUid(); + + default int getDefaultPriority() { + return 0; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerDataProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerDataProvider.java new file mode 100644 index 0000000..7d839f1 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerDataProvider.java @@ -0,0 +1,8 @@ +package org.leavesmc.leaves.protocol.jade.provider; + +import net.minecraft.nbt.CompoundTag; +import org.leavesmc.leaves.protocol.jade.accessor.Accessor; + +public interface IServerDataProvider> extends IJadeProvider { + void appendServerData(CompoundTag data, T accessor); +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerExtensionProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerExtensionProvider.java new file mode 100644 index 0000000..6e32eed --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerExtensionProvider.java @@ -0,0 +1,10 @@ +package org.leavesmc.leaves.protocol.jade.provider; + +import org.leavesmc.leaves.protocol.jade.accessor.Accessor; +import org.leavesmc.leaves.protocol.jade.util.ViewGroup; + +import java.util.List; + +public interface IServerExtensionProvider extends IJadeProvider { + List> getGroups(Accessor request); +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java new file mode 100644 index 0000000..2999e79 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java @@ -0,0 +1,142 @@ +package org.leavesmc.leaves.protocol.jade.provider; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.Container; +import net.minecraft.world.LockCode; +import net.minecraft.world.RandomizableContainer; +import net.minecraft.world.WorldlyContainerHolder; +import net.minecraft.world.entity.animal.horse.AbstractHorse; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.vehicle.ContainerEntity; +import net.minecraft.world.inventory.PlayerEnderChestContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.EnderChestBlock; +import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.entity.EnderChestBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.LeavesLogger; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.Accessor; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.util.ItemCollector; +import org.leavesmc.leaves.protocol.jade.util.ItemIterator; +import org.leavesmc.leaves.protocol.jade.util.ViewGroup; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +public enum ItemStorageExtensionProvider implements IServerExtensionProvider { + INSTANCE; + + public static final Cache> targetCache = CacheBuilder.newBuilder().weakKeys().expireAfterAccess(60, TimeUnit.SECONDS).build(); + + private static final ResourceLocation UNIVERSAL_ITEM_STORAGE = JadeProtocol.mc_id("item_storage.default"); + + public static ItemCollector createItemCollector(Accessor request) { + if (request.getTarget() instanceof AbstractHorse) { + return new ItemCollector<>(new ItemIterator.ContainerItemIterator(o -> { + if (o instanceof AbstractHorse horse) { + return horse.inventory; + } + return null; + }, 2)); + } + + // TODO BlockEntity like fabric's ItemStorage + + final Container container = findContainer(request); + if (container != null) { + if (container instanceof ChestBlockEntity) { + return new ItemCollector<>(new ItemIterator.ContainerItemIterator(o -> { + if (o instanceof ChestBlockEntity blockEntity) { + if (blockEntity.getBlockState().getBlock() instanceof ChestBlock chestBlock) { + Container compound = null; + if (blockEntity.getLevel() != null) { + compound = ChestBlock.getContainer(chestBlock, blockEntity.getBlockState(), blockEntity.getLevel(), blockEntity.getBlockPos(), false); + } + if (compound != null) { + return compound; + } + } + return blockEntity; + } + return null; + }, 0)); + } + return new ItemCollector<>(new ItemIterator.ContainerItemIterator(0)); + } + + return ItemCollector.EMPTY; + } + + public static @Nullable Container findContainer(@NotNull Accessor accessor) { + Object target = accessor.getTarget(); + if (target == null && accessor instanceof BlockAccessor blockAccessor && + blockAccessor.getBlock() instanceof WorldlyContainerHolder holder) { + return holder.getContainer(blockAccessor.getBlockState(), accessor.getLevel(), blockAccessor.getPosition()); + } else if (target instanceof Container container) { + return container; + } + return null; + } + + @Override + public List> getGroups(Accessor request) { + Object target = request.getTarget(); + + switch (target) { + case null -> { + return createItemCollector(request).update(request); + } + case RandomizableContainer te when te.getLootTable() != null -> { + return List.of(); + } + case ContainerEntity containerEntity when containerEntity.getContainerLootTable() != null -> { + return List.of(); + } + case EnderChestBlockEntity enderChest when request.getPlayer().getEnderChestInventory().isEmpty() -> { + return List.of(); + } + default -> { + } + } + + Player player = request.getPlayer(); + if (!player.isCreative() && !player.isSpectator() && target instanceof BaseContainerBlockEntity te) { + if (te.lockKey != LockCode.NO_LOCK) { + return List.of(); + } + } + + if (target instanceof EnderChestBlockEntity) { + PlayerEnderChestContainer inventory = player.getEnderChestInventory(); + return new ItemCollector<>(new ItemIterator.ContainerItemIterator(x -> inventory, 0)).update(request); + } + + ItemCollector itemCollector; + try { + itemCollector = targetCache.get(target, () -> createItemCollector(request)); + } catch (ExecutionException e) { + LeavesLogger.LOGGER.severe("Failed to get item collector for " + target); + return null; + } + + return itemCollector.update(request); + } + + @Override + public ResourceLocation getUid() { + return UNIVERSAL_ITEM_STORAGE; + } + + @Override + public int getDefaultPriority() { + return 9999; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java new file mode 100644 index 0000000..7d6cd6d --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java @@ -0,0 +1,87 @@ +package org.leavesmc.leaves.protocol.jade.provider; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.LockCode; +import net.minecraft.world.RandomizableContainer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; +import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.Accessor; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.util.CommonUtil; +import org.leavesmc.leaves.protocol.jade.util.ItemCollector; +import org.leavesmc.leaves.protocol.jade.util.ViewGroup; + +import java.util.List; +import java.util.Map; + +public abstract class ItemStorageProvider> implements IServerDataProvider { + + private static final StreamCodec>>> STREAM_CODEC = ViewGroup.listCodec(ItemStack.OPTIONAL_STREAM_CODEC); + + private static final ResourceLocation UNIVERSAL_ITEM_STORAGE = JadeProtocol.mc_id("item_storage"); + + public static ForBlock getBlock() { + return ForBlock.INSTANCE; + } + + public static ForEntity getEntity() { + return ForEntity.INSTANCE; + } + + public static void putData(CompoundTag tag, @NotNull Accessor accessor) { + Object target = accessor.getTarget(); + Player player = accessor.getPlayer(); + Map.Entry>> entry = CommonUtil.getServerExtensionData(accessor, JadeProtocol.itemStorageProviders); + if (entry != null) { + List> groups = entry.getValue(); + for (ViewGroup group : groups) { + if (group.views.size() > ItemCollector.MAX_SIZE) { + group.views = group.views.subList(0, ItemCollector.MAX_SIZE); + } + } + tag.put(UNIVERSAL_ITEM_STORAGE.toString(), accessor.encodeAsNbt(STREAM_CODEC, entry)); + return; + } + if (target instanceof RandomizableContainer containerEntity && containerEntity.getLootTable() != null) { + tag.putBoolean("Loot", true); + } else if (!player.isCreative() && !player.isSpectator() && target instanceof BaseContainerBlockEntity te) { + if (te.lockKey != LockCode.NO_LOCK) { + tag.putBoolean("Locked", true); + } + } + } + + @Override + public ResourceLocation getUid() { + return UNIVERSAL_ITEM_STORAGE; + } + + @Override + public void appendServerData(CompoundTag tag, @NotNull T accessor) { + if (accessor.getTarget() instanceof AbstractFurnaceBlockEntity) { + return; + } + putData(tag, accessor); + } + + @Override + public int getDefaultPriority() { + return 1000; + } + + public static class ForBlock extends ItemStorageProvider { + private static final ForBlock INSTANCE = new ForBlock(); + } + + public static class ForEntity extends ItemStorageProvider { + private static final ForEntity INSTANCE = new ForEntity(); + } +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/StreamServerDataProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/StreamServerDataProvider.java new file mode 100644 index 0000000..fde7c8e --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/StreamServerDataProvider.java @@ -0,0 +1,23 @@ +package org.leavesmc.leaves.protocol.jade.provider; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.accessor.Accessor; + +public interface StreamServerDataProvider, D> extends IServerDataProvider { + + @Override + default void appendServerData(CompoundTag data, T accessor) { + D value = streamData(accessor); + if (value != null) { + data.put(getUid().toString(), accessor.encodeAsNbt(streamCodec(), value)); + } + } + + @Nullable + D streamData(T accessor); + + StreamCodec streamCodec(); +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BeehiveProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BeehiveProvider.java new file mode 100644 index 0000000..ee92d79 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BeehiveProvider.java @@ -0,0 +1,34 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BeehiveBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum BeehiveProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_BEEHIVE = JadeProtocol.mc_id("beehive"); + + @Override + public @NotNull StreamCodec streamCodec() { + return ByteBufCodecs.BYTE.cast(); + } + + @Override + public Byte streamData(@NotNull BlockAccessor accessor) { + BeehiveBlockEntity beehive = (BeehiveBlockEntity) accessor.getBlockEntity(); + int bees = beehive.getOccupantCount(); + return (byte) (beehive.isFull() ? bees : -bees); + } + + @Override + public ResourceLocation getUid() { + return MC_BEEHIVE; + } +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BlockNameProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BlockNameProvider.java new file mode 100644 index 0000000..4904ef0 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BlockNameProvider.java @@ -0,0 +1,60 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.Nameable; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.state.properties.ChestType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum BlockNameProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation CORE_OBJECT_NAME = JadeProtocol.id("object_name"); + + @Override + @Nullable + public Component streamData(@NotNull BlockAccessor accessor) { + if (!(accessor.getBlockEntity() instanceof Nameable nameable)) { + return null; + } + if (nameable instanceof ChestBlockEntity && accessor.getBlock() instanceof ChestBlock && accessor.getBlockState().getValue(ChestBlock.TYPE) != ChestType.SINGLE) { + MenuProvider menuProvider = accessor.getBlockState().getMenuProvider(accessor.getLevel(), accessor.getPosition()); + if (menuProvider != null) { + Component name = menuProvider.getDisplayName(); + if (!(name.getContents() instanceof TranslatableContents contents) || !"container.chestDouble".equals(contents.getKey())) { + return name; + } + } + } else if (nameable.hasCustomName()) { + return nameable.getDisplayName(); + } + return accessor.getBlockEntity().components().get(DataComponents.ITEM_NAME); + } + + @Override + public StreamCodec streamCodec() { + return ComponentSerialization.STREAM_CODEC; + } + + @Override + public ResourceLocation getUid() { + return CORE_OBJECT_NAME; + } + + @Override + public int getDefaultPriority() { + return -10100; + } +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BrewingStandProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BrewingStandProvider.java new file mode 100644 index 0000000..4266550 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BrewingStandProvider.java @@ -0,0 +1,43 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import io.netty.buffer.ByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum BrewingStandProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_BREWING_STAND = JadeProtocol.mc_id("brewing_stand"); + + @Override + public @NotNull Data streamData(@NotNull BlockAccessor accessor) { + BrewingStandBlockEntity brewingStand = (BrewingStandBlockEntity) accessor.getBlockEntity(); + return new Data(brewingStand.fuel, brewingStand.brewTime); + } + + @Override + public @NotNull StreamCodec streamCodec() { + return Data.STREAM_CODEC.cast(); + } + + @Override + public ResourceLocation getUid() { + return MC_BREWING_STAND; + } + + public record Data(int fuel, int time) { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, + Data::fuel, + ByteBufCodecs.VAR_INT, + Data::time, + Data::new); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java new file mode 100644 index 0000000..2deb377 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java @@ -0,0 +1,55 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import com.google.common.collect.Lists; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.NbtOps; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.block.entity.CampfireBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.Accessor; +import org.leavesmc.leaves.protocol.jade.provider.IServerExtensionProvider; +import org.leavesmc.leaves.protocol.jade.util.ViewGroup; + +import java.util.List; + +public enum CampfireProvider implements IServerExtensionProvider { + INSTANCE; + + private static final MapCodec COOKING_TIME_CODEC = Codec.INT.fieldOf("jade:cooking"); + private static final ResourceLocation MC_CAMPFIRE = JadeProtocol.mc_id("campfire"); + + @Override + public @Nullable @Unmodifiable List> getGroups(@NotNull Accessor request) { + if (request.getTarget() instanceof CampfireBlockEntity campfire) { + List list = Lists.newArrayList(); + for (int i = 0; i < campfire.cookingTime.length; i++) { + ItemStack stack = campfire.getItems().get(i); + if (stack.isEmpty()) { + continue; + } + stack = stack.copy(); + + CustomData customData = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY) + .update(NbtOps.INSTANCE, COOKING_TIME_CODEC, campfire.cookingTime[i] - campfire.cookingProgress[i]) + .getOrThrow(); + stack.set(DataComponents.CUSTOM_DATA, customData); + + list.add(stack); + } + return List.of(new ViewGroup<>(list)); + } + return null; + } + + @Override + public ResourceLocation getUid() { + return MC_CAMPFIRE; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ChiseledBookshelfProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ChiseledBookshelfProvider.java new file mode 100644 index 0000000..12fdbc3 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ChiseledBookshelfProvider.java @@ -0,0 +1,44 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.ChiseledBookShelfBlock; +import net.minecraft.world.level.block.entity.ChiseledBookShelfBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.ItemStorageProvider; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum ChiseledBookshelfProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_CHISELED_BOOKSHELF = JadeProtocol.mc_id("chiseled_bookshelf"); + + @Override + public @Nullable ItemStack streamData(@NotNull BlockAccessor accessor) { + int slot = ((ChiseledBookShelfBlock) accessor.getBlock()).getHitSlot(accessor.getHitResult(), accessor.getBlockState()).orElse(-1); + if (slot == -1) { + return null; + } + return ((ChiseledBookShelfBlockEntity) accessor.getBlockEntity()).getItem(slot); + } + + @Override + public StreamCodec streamCodec() { + return ItemStack.OPTIONAL_STREAM_CODEC; + } + + @Override + public ResourceLocation getUid() { + return MC_CHISELED_BOOKSHELF; + } + + @Override + public int getDefaultPriority() { + return ItemStorageProvider.getBlock().getDefaultPriority() + 1; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CommandBlockProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CommandBlockProvider.java new file mode 100644 index 0000000..5f71fad --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CommandBlockProvider.java @@ -0,0 +1,40 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.CommandBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum CommandBlockProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_COMMAND_BLOCK = JadeProtocol.mc_id("command_block"); + + @Nullable + public String streamData(@NotNull BlockAccessor accessor) { + if (!accessor.getPlayer().canUseGameMasterBlocks()) { + return null; + } + String command = ((CommandBlockEntity) accessor.getBlockEntity()).getCommandBlock().getCommand(); + if (command.length() > 40) { + command = command.substring(0, 37) + "..."; + } + return command; + } + + @Override + public @NotNull StreamCodec streamCodec() { + return ByteBufCodecs.STRING_UTF8.cast(); + } + + @Override + public ResourceLocation getUid() { + return MC_COMMAND_BLOCK; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/FurnaceProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/FurnaceProvider.java new file mode 100644 index 0000000..5e5f2cc --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/FurnaceProvider.java @@ -0,0 +1,51 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +import java.util.List; + +public enum FurnaceProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_FURNACE = JadeProtocol.mc_id("furnace"); + + @Override + public @NotNull Data streamData(@NotNull BlockAccessor accessor) { + AbstractFurnaceBlockEntity furnace = (AbstractFurnaceBlockEntity) accessor.getBlockEntity(); + return new Data( + furnace.cookingTimer, + furnace.cookingTotalTime, + List.of(furnace.getItem(0), furnace.getItem(1), furnace.getItem(2)) + ); + } + + @Override + public StreamCodec streamCodec() { + return Data.STREAM_CODEC; + } + + @Override + public ResourceLocation getUid() { + return MC_FURNACE; + } + + public record Data(int progress, int total, List inventory) { + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, + Data::progress, + ByteBufCodecs.VAR_INT, + Data::total, + ItemStack.OPTIONAL_LIST_STREAM_CODEC, + Data::inventory, + Data::new); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/HopperLockProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/HopperLockProvider.java new file mode 100644 index 0000000..2459acd --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/HopperLockProvider.java @@ -0,0 +1,37 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum HopperLockProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_HOPPER_LOCK = JadeProtocol.mc_id("hopper_lock"); + + @Override + public Boolean streamData(@NotNull BlockAccessor accessor) { + return !accessor.getBlockState().getValue(BlockStateProperties.ENABLED); + } + + @Override + public @NotNull StreamCodec streamCodec() { + return ByteBufCodecs.BOOL.cast(); + } + + @Override + public ResourceLocation getUid() { + return MC_HOPPER_LOCK; + } + + @Override + public int getDefaultPriority() { + return BlockNameProvider.INSTANCE.getDefaultPriority() + 10; + } +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/JukeboxProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/JukeboxProvider.java new file mode 100644 index 0000000..0b6e224 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/JukeboxProvider.java @@ -0,0 +1,32 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.JukeboxBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum JukeboxProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_JUKEBOX = JadeProtocol.mc_id("jukebox"); + + @Override + public @NotNull ItemStack streamData(BlockAccessor accessor) { + return ((JukeboxBlockEntity) accessor.getBlockEntity()).getTheItem(); + } + + @Override + public StreamCodec streamCodec() { + return ItemStack.OPTIONAL_STREAM_CODEC; + } + + @Override + public ResourceLocation getUid() { + return MC_JUKEBOX; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/LecternProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/LecternProvider.java new file mode 100644 index 0000000..c363bd6 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/LecternProvider.java @@ -0,0 +1,33 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.LecternBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum LecternProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_LECTERN = JadeProtocol.mc_id("lectern"); + + @Override + public @NotNull ItemStack streamData(@NotNull BlockAccessor accessor) { + return ((LecternBlockEntity) accessor.getBlockEntity()).getBook(); + } + + @Override + public StreamCodec streamCodec() { + return ItemStack.OPTIONAL_STREAM_CODEC; + } + + + @Override + public ResourceLocation getUid() { + return MC_LECTERN; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/MobSpawnerCooldownProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/MobSpawnerCooldownProvider.java new file mode 100644 index 0000000..feb636d --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/MobSpawnerCooldownProvider.java @@ -0,0 +1,42 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerStateData; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum MobSpawnerCooldownProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_MOB_SPAWNER_COOLDOWN = JadeProtocol.mc_id("mob_spawner.cooldown"); + + @Override + public @Nullable Integer streamData(@NotNull BlockAccessor accessor) { + TrialSpawnerBlockEntity spawner = (TrialSpawnerBlockEntity) accessor.getBlockEntity(); + TrialSpawnerStateData spawnerData = spawner.getTrialSpawner().getStateData(); + ServerLevel level = ((ServerLevel) accessor.getLevel()); + if (spawner.getTrialSpawner().canSpawnInLevel(level) && level.getGameTime() < spawnerData.cooldownEndsAt) { + return (int) (spawnerData.cooldownEndsAt - level.getGameTime()); + } + return null; + } + + @Override + public @NotNull StreamCodec streamCodec() { + return ByteBufCodecs.VAR_INT.cast(); + } + + + @Override + public ResourceLocation getUid() { + return MC_MOB_SPAWNER_COOLDOWN; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/RedstoneProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/RedstoneProvider.java new file mode 100644 index 0000000..1cdcf21 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/RedstoneProvider.java @@ -0,0 +1,36 @@ +package org.leavesmc.leaves.protocol.jade.provider.block; + +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.CalibratedSculkSensorBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity; +import net.minecraft.world.level.block.entity.ComparatorBlockEntity; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider; + +public enum RedstoneProvider implements IServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_REDSTONE = JadeProtocol.mc_id("redstone"); + + @Override + public void appendServerData(CompoundTag data, @NotNull BlockAccessor accessor) { + BlockEntity blockEntity = accessor.getBlockEntity(); + if (blockEntity instanceof ComparatorBlockEntity comparator) { + data.putInt("Signal", comparator.getOutputSignal()); + } else if (blockEntity instanceof CalibratedSculkSensorBlockEntity) { + Direction direction = accessor.getBlockState().getValue(CalibratedSculkSensorBlock.FACING).getOpposite(); + int signal = accessor.getLevel().getSignal(accessor.getPosition().relative(direction), direction); + data.putInt("Signal", signal); + } + } + + @Override + public ResourceLocation getUid() { + return MC_REDSTONE; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/AnimalOwnerProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/AnimalOwnerProvider.java new file mode 100644 index 0000000..495815a --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/AnimalOwnerProvider.java @@ -0,0 +1,48 @@ +package org.leavesmc.leaves.protocol.jade.provider.entity; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityReference; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.OwnableEntity; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; +import org.leavesmc.leaves.protocol.jade.util.CommonUtil; + +import java.util.UUID; + +public enum AnimalOwnerProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_ANIMAL_OWNER = JadeProtocol.mc_id("animal_owner"); + + public static UUID getOwnerUUID(Entity entity) { + if (entity instanceof OwnableEntity ownableEntity) { + EntityReference reference = ownableEntity.getOwnerReference(); + if (reference != null) { + return reference.getUUID(); + } + } + return null; + } + + @Override + public String streamData(@NotNull EntityAccessor accessor) { + return CommonUtil.getLastKnownUsername(getOwnerUUID(accessor.getEntity())); + } + + @Override + public @NotNull StreamCodec streamCodec() { + return ByteBufCodecs.STRING_UTF8.cast(); + } + + @Override + public ResourceLocation getUid() { + return MC_ANIMAL_OWNER; + } +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobBreedingProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobBreedingProvider.java new file mode 100644 index 0000000..0acba2f --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobBreedingProvider.java @@ -0,0 +1,44 @@ +package org.leavesmc.leaves.protocol.jade.provider.entity; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.animal.Animal; +import net.minecraft.world.entity.animal.allay.Allay; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum MobBreedingProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_MOB_BREEDING = JadeProtocol.mc_id("mob_breeding"); + + @Override + public @Nullable Integer streamData(@NotNull EntityAccessor accessor) { + int time = 0; + Entity entity = accessor.getEntity(); + if (entity instanceof Allay allay) { + if (allay.duplicationCooldown > 0 && allay.duplicationCooldown < Integer.MAX_VALUE) { + time = (int) allay.duplicationCooldown; + } + } else { + time = ((Animal) entity).getAge(); + } + return time > 0 ? time : null; + } + + @Override + public @NotNull StreamCodec streamCodec() { + return ByteBufCodecs.VAR_INT.cast(); + } + + @Override + public ResourceLocation getUid() { + return MC_MOB_BREEDING; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobGrowthProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobGrowthProvider.java new file mode 100644 index 0000000..44f5f4b --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobGrowthProvider.java @@ -0,0 +1,43 @@ +package org.leavesmc.leaves.protocol.jade.provider.entity; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.AgeableMob; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.animal.frog.Tadpole; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum MobGrowthProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_MOB_GROWTH = JadeProtocol.mc_id("mob_growth"); + + @Override + public @Nullable Integer streamData(@NotNull EntityAccessor accessor) { + int time = -1; + Entity entity = accessor.getEntity(); + if (entity instanceof AgeableMob ageable) { + time = -ageable.getAge(); + } else if (entity instanceof Tadpole tadpole) { + time = tadpole.getTicksLeftUntilAdult(); + } + return time > 0 ? time : null; + } + + @Override + public @NotNull StreamCodec streamCodec() { + return ByteBufCodecs.VAR_INT.cast(); + } + + + @Override + public ResourceLocation getUid() { + return MC_MOB_GROWTH; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/NextEntityDropProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/NextEntityDropProvider.java new file mode 100644 index 0000000..f7d24fd --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/NextEntityDropProvider.java @@ -0,0 +1,42 @@ +package org.leavesmc.leaves.protocol.jade.provider.entity; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.ai.memory.MemoryModuleType; +import net.minecraft.world.entity.animal.Chicken; +import net.minecraft.world.entity.animal.armadillo.Armadillo; +import net.minecraft.world.entity.animal.sniffer.Sniffer; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider; + +public enum NextEntityDropProvider implements IServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_NEXT_ENTITY_DROP = JadeProtocol.mc_id("next_entity_drop"); + + @Override + public void appendServerData(CompoundTag tag, @NotNull EntityAccessor accessor) { + int max = 24000 * 2; + if (accessor.getEntity() instanceof Chicken chicken) { + if (!chicken.isBaby() && chicken.eggTime < max) { + tag.putInt("NextEggIn", chicken.eggTime); + } + } else if (accessor.getEntity() instanceof Armadillo armadillo) { + if (!armadillo.isBaby() && armadillo.scuteTime < max) { + tag.putInt("NextScuteIn", armadillo.scuteTime); + } + } else if (accessor.getEntity() instanceof Sniffer sniffer) { + long time = sniffer.getBrain().getTimeUntilExpiry(MemoryModuleType.SNIFF_COOLDOWN); + if (time > 0 && time < max) { + tag.putInt("NextSniffIn", (int) time); + } + } + } + + @Override + public ResourceLocation getUid() { + return MC_NEXT_ENTITY_DROP; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/PetArmorProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/PetArmorProvider.java new file mode 100644 index 0000000..cb8d173 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/PetArmorProvider.java @@ -0,0 +1,35 @@ +package org.leavesmc.leaves.protocol.jade.provider.entity; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum PetArmorProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_PET_ARMOR = JadeProtocol.mc_id("pet_armor"); + + @Nullable + @Override + public ItemStack streamData(@NotNull EntityAccessor accessor) { + ItemStack armor = ((Mob) accessor.getEntity()).getBodyArmorItem(); + return armor.isEmpty() ? null : armor; + } + + @Override + public StreamCodec streamCodec() { + return ItemStack.OPTIONAL_STREAM_CODEC; + } + + @Override + public ResourceLocation getUid() { + return MC_PET_ARMOR; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/StatusEffectsProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/StatusEffectsProvider.java new file mode 100644 index 0000000..7470627 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/StatusEffectsProvider.java @@ -0,0 +1,45 @@ +package org.leavesmc.leaves.protocol.jade.provider.entity; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.LivingEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +import java.util.List; + +public enum StatusEffectsProvider implements StreamServerDataProvider> { + INSTANCE; + + + private static final StreamCodec> STREAM_CODEC = ByteBufCodecs.list() + .apply(MobEffectInstance.STREAM_CODEC); + private static final ResourceLocation MC_POTION_EFFECTS = JadeProtocol.mc_id("potion_effects"); + + @Override + @Nullable + public List streamData(@NotNull EntityAccessor accessor) { + List effects = ((LivingEntity) accessor.getEntity()).getActiveEffects() + .stream() + .filter(MobEffectInstance::isVisible) + .toList(); + return effects.isEmpty() ? null : effects; + } + + @Override + public StreamCodec> streamCodec() { + return STREAM_CODEC; + } + + + @Override + public ResourceLocation getUid() { + return MC_POTION_EFFECTS; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/ZombieVillagerProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/ZombieVillagerProvider.java new file mode 100644 index 0000000..b7c9afd --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/ZombieVillagerProvider.java @@ -0,0 +1,34 @@ +package org.leavesmc.leaves.protocol.jade.provider.entity; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.monster.ZombieVillager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor; +import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider; + +public enum ZombieVillagerProvider implements StreamServerDataProvider { + INSTANCE; + + private static final ResourceLocation MC_ZOMBIE_VILLAGER = JadeProtocol.mc_id("zombie_villager"); + + @Override + public @Nullable Integer streamData(@NotNull EntityAccessor accessor) { + int time = ((ZombieVillager) accessor.getEntity()).villagerConversionTime; + return time > 0 ? time : null; + } + + @Override + public @NotNull StreamCodec streamCodec() { + return ByteBufCodecs.VAR_INT.cast(); + } + + @Override + public ResourceLocation getUid() { + return MC_ZOMBIE_VILLAGER; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ShearsToolHandler.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ShearsToolHandler.java new file mode 100644 index 0000000..9bbe516 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ShearsToolHandler.java @@ -0,0 +1,37 @@ +package org.leavesmc.leaves.protocol.jade.tool; + +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.component.Tool; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.List; + +public class ShearsToolHandler { + + private static final ShearsToolHandler INSTANCE = new ShearsToolHandler(); + + private final List tools; + + public ShearsToolHandler() { + this.tools = List.of(Items.SHEARS.getDefaultInstance()); + } + + public static ShearsToolHandler getInstance() { + return INSTANCE; + } + + public ItemStack test(BlockState state) { + for (ItemStack toolItem : tools) { + if (toolItem.isCorrectToolForDrops(state)) { + return toolItem; + } + Tool tool = toolItem.get(DataComponents.TOOL); + if (tool != null && tool.getMiningSpeed(state) > tool.defaultMiningSpeed()) { + return toolItem; + } + } + return ItemStack.EMPTY; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/CommonUtil.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/CommonUtil.java new file mode 100644 index 0000000..4e48a26 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/CommonUtil.java @@ -0,0 +1,72 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import com.mojang.authlib.GameProfile; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.boss.EnderDragonPart; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.level.block.entity.SkullBlockEntity; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.LeavesLogger; +import org.leavesmc.leaves.protocol.jade.accessor.Accessor; +import org.leavesmc.leaves.protocol.jade.provider.IServerExtensionProvider; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public class CommonUtil { + + public static Entity wrapPartEntityParent(Entity target) { + if (target instanceof EnderDragonPart part) { + return part.parentMob; + } + return target; + } + + public static Entity getPartEntity(Entity parent, int index) { + if (parent == null) { + return null; + } + if (index < 0) { + return parent; + } + if (parent instanceof EnderDragon dragon) { + EnderDragonPart[] parts = dragon.getSubEntities(); + if (index < parts.length) { + return parts[index]; + } + } + return parent; + } + + + @Nullable + public static String getLastKnownUsername(@Nullable UUID uuid) { + if (uuid == null) { + return null; + } + Optional optional = SkullBlockEntity.fetchGameProfile(String.valueOf(uuid)).getNow(Optional.empty()); + return optional.map(GameProfile::getName).orElse(null); + } + + + public static Map.Entry>> getServerExtensionData( + Accessor accessor, + WrappedHierarchyLookup> lookup) { + for (var provider : lookup.wrappedGet(accessor)) { + List> groups; + try { + groups = provider.getGroups(accessor); + } catch (Exception e) { + LeavesLogger.LOGGER.severe(e.toString()); + continue; + } + if (groups != null) { + return Map.entry(provider.getUid(), groups); + } + } + return null; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/HierarchyLookup.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/HierarchyLookup.java new file mode 100644 index 0000000..b2736d7 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/HierarchyLookup.java @@ -0,0 +1,138 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import com.google.common.base.Preconditions; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import net.minecraft.core.IdMapper; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.LeavesLogger; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider; + +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; + +public class HierarchyLookup implements IHierarchyLookup { + private final Class baseClass; + private final Cache, List> resultCache = CacheBuilder.newBuilder().build(); + private final boolean singleton; + protected boolean idMapped; + @Nullable + protected IdMapper idMapper; + private ListMultimap, T> objects = ArrayListMultimap.create(); + + public HierarchyLookup(Class baseClass) { + this(baseClass, false); + } + + public HierarchyLookup(Class baseClass, boolean singleton) { + this.baseClass = baseClass; + this.singleton = singleton; + } + + @Override + public void idMapped() { + this.idMapped = true; + } + + @Override + @Nullable + public IdMapper idMapper() { + return idMapper; + } + + @Override + public void register(Class clazz, T provider) { + Preconditions.checkArgument(isClassAcceptable(clazz), "Class %s is not acceptable", clazz); + Objects.requireNonNull(provider.getUid()); + JadeProtocol.priorities.put(provider); + objects.put(clazz, provider); + } + + @Override + public boolean isClassAcceptable(Class clazz) { + return baseClass.isAssignableFrom(clazz); + } + + @Override + public List get(Class clazz) { + try { + return resultCache.get(clazz, () -> { + List list = Lists.newArrayList(); + getInternal(clazz, list); + list = ImmutableList.sortedCopyOf(COMPARATOR, list); + if (singleton && !list.isEmpty()) { + return ImmutableList.of(list.getFirst()); + } + return list; + }); + } catch (ExecutionException e) { + LeavesLogger.LOGGER.warning("HierarchyLookup error", e); + } + return List.of(); + } + + private void getInternal(Class clazz, List list) { + if (clazz != baseClass && clazz != Object.class) { + getInternal(clazz.getSuperclass(), list); + } + list.addAll(objects.get(clazz)); + } + + @Override + public boolean isEmpty() { + return objects.isEmpty(); + } + + @Override + public Stream, Collection>> entries() { + return objects.asMap().entrySet().stream(); + } + + @Override + public void invalidate() { + resultCache.invalidateAll(); + } + + @Override + public void loadComplete(PriorityStore priorityStore) { + objects.asMap().forEach((clazz, list) -> { + if (list.size() < 2) { + return; + } + Set set = Sets.newHashSetWithExpectedSize(list.size()); + for (T provider : list) { + if (set.contains(provider.getUid())) { + throw new IllegalStateException("Duplicate UID: %s for %s".formatted(provider.getUid(), list.stream() + .filter(p -> p.getUid().equals(provider.getUid())) + .map(p -> p.getClass().getName()) + .toList() + )); + } + set.add(provider.getUid()); + } + }); + + objects = ImmutableListMultimap., T>builder() + .orderValuesBy(Comparator.comparingInt(priorityStore::byValue)) + .putAll(objects) + .build(); + + if (idMapped) { + idMapper = createIdMapper(); + } + } +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/IHierarchyLookup.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/IHierarchyLookup.java new file mode 100644 index 0000000..c160eaa --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/IHierarchyLookup.java @@ -0,0 +1,71 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import com.google.common.collect.Streams; +import net.minecraft.core.IdMapper; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.JadeProtocol; +import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider; + +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +public interface IHierarchyLookup { + + Comparator COMPARATOR = Comparator.comparingInt(provider -> JadeProtocol.priorities.byValue(provider)); + + default IHierarchyLookup cast() { + return this; + } + + void idMapped(); + + @Nullable + IdMapper idMapper(); + + default List mappedIds() { + return Streams.stream(Objects.requireNonNull(idMapper())) + .map(IJadeProvider::getUid) + .toList(); + } + + void register(Class clazz, T provider); + + boolean isClassAcceptable(Class clazz); + + default List get(Object obj) { + if (obj == null) { + return List.of(); + } + return get(obj.getClass()); + } + + List get(Class clazz); + + boolean isEmpty(); + + Stream, Collection>> entries(); + + void invalidate(); + + void loadComplete(PriorityStore priorityStore); + + default IdMapper createIdMapper() { + List list = entries().flatMap(entry -> entry.getValue().stream()).toList(); + IdMapper idMapper = idMapper(); + if (idMapper == null) { + idMapper = new IdMapper<>(list.size()); + } + for (T provider : list) { + if (idMapper.getId(provider) == IdMapper.DEFAULT) { + idMapper.add(provider); + } + } + return idMapper; + } +} + diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java new file mode 100644 index 0000000..c23cb19 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java @@ -0,0 +1,121 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.TooltipDisplay; +import org.leavesmc.leaves.protocol.jade.accessor.Accessor; + +import java.util.List; +import java.util.Locale; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Predicate; + +public class ItemCollector { + public static final int MAX_SIZE = 54; + public static final ItemCollector EMPTY = new ItemCollector<>(null); + private static final Predicate SHOWN = stack -> { + if (stack.isEmpty()) { + return false; + } + if (stack.getOrDefault(DataComponents.TOOLTIP_DISPLAY, TooltipDisplay.DEFAULT).hideTooltip()) { + return false; + } + if (stack.hasNonDefault(DataComponents.CUSTOM_MODEL_DATA) || stack.hasNonDefault(DataComponents.ITEM_MODEL)) { + CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + for (String key : tag.keySet()) { + if (key.toLowerCase(Locale.ENGLISH).endsWith("clear") && tag.getBooleanOr(key, true)) { + return false; + } + } + } + return true; + }; + private final Object2IntLinkedOpenHashMap items = new Object2IntLinkedOpenHashMap<>(); + private final ItemIterator iterator; + public long version; + public long lastTimeFinished; + public boolean lastTimeIsEmpty; + public List> mergedResult; + + public ItemCollector(ItemIterator iterator) { + this.iterator = iterator; + } + + public List> update(Accessor request) { + if (iterator == null) { + return null; + } + T container = iterator.find(request.getTarget()); + if (container == null) { + return null; + } + long currentVersion = iterator.getVersion(container); + long gameTime = request.getLevel().getGameTime(); + if (mergedResult != null && iterator.isFinished()) { + if (version == currentVersion) { + return mergedResult; // content not changed + } + if (lastTimeFinished + 5 > gameTime) { + return mergedResult; // avoid update too frequently + } + iterator.reset(); + } + AtomicInteger count = new AtomicInteger(); + iterator.populate(container).forEach(stack -> { + count.incrementAndGet(); + if (SHOWN.test(stack)) { + ItemDefinition def = new ItemDefinition(stack); + items.addTo(def, stack.getCount()); + } + }); + iterator.afterPopulate(count.get()); + if (mergedResult != null && !iterator.isFinished()) { + updateCollectingProgress(mergedResult.getFirst()); + return mergedResult; + } + List partialResult = items.object2IntEntrySet().stream().limit(MAX_SIZE).map(entry -> { + ItemDefinition def = entry.getKey(); + return def.toStack(entry.getIntValue()); + }).toList(); + List> groups = List.of(updateCollectingProgress(new ViewGroup<>(partialResult))); + if (iterator.isFinished()) { + mergedResult = groups; + lastTimeIsEmpty = mergedResult.getFirst().views.isEmpty(); + version = currentVersion; + lastTimeFinished = gameTime; + items.clear(); + } + return groups; + } + + protected ViewGroup updateCollectingProgress(ViewGroup group) { + if (lastTimeIsEmpty && group.views.isEmpty()) { + return group; + } + float progress = iterator.getCollectingProgress(); + CompoundTag data = group.getExtraData(); + if (Float.isNaN(progress) || progress >= 1) { + data.remove("Collecting"); + } else { + data.putFloat("Collecting", progress); + } + return group; + } + + public record ItemDefinition(Item item, DataComponentPatch components) { + ItemDefinition(ItemStack stack) { + this(stack.getItem(), stack.getComponentsPatch()); + } + + public ItemStack toStack(int count) { + ItemStack itemStack = new ItemStack(item, count); + itemStack.applyComponents(components); + return itemStack; + } + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemIterator.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemIterator.java new file mode 100644 index 0000000..4d65e9a --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemIterator.java @@ -0,0 +1,102 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import net.minecraft.world.Container; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public abstract class ItemIterator { + public static final AtomicLong version = new AtomicLong(); + protected final Function containerFinder; + protected final int fromIndex; + protected boolean finished; + protected int currentIndex; + + protected ItemIterator(Function containerFinder, int fromIndex) { + this.containerFinder = containerFinder; + this.currentIndex = this.fromIndex = fromIndex; + } + + public @Nullable T find(Object target) { + return containerFinder.apply(target); + } + + public final boolean isFinished() { + return finished; + } + + public long getVersion(T container) { + return version.getAndIncrement(); + } + + public abstract Stream populate(T container); + + public void reset() { + currentIndex = fromIndex; + finished = false; + } + + public void afterPopulate(int count) { + currentIndex += count; + if (count == 0 || currentIndex >= 10000) { + finished = true; + } + } + + public float getCollectingProgress() { + return Float.NaN; + } + + public static abstract class SlottedItemIterator extends ItemIterator { + protected float progress; + + public SlottedItemIterator(Function containerFinder, int fromIndex) { + super(containerFinder, fromIndex); + } + + protected abstract int getSlotCount(T container); + + protected abstract ItemStack getItemInSlot(T container, int slot); + + @Override + public Stream populate(T container) { + int slotCount = getSlotCount(container); + int toIndex = currentIndex + ItemCollector.MAX_SIZE * 2; + if (toIndex >= slotCount) { + toIndex = slotCount; + finished = true; + } + progress = (float) (currentIndex - fromIndex) / (slotCount - fromIndex); + return IntStream.range(currentIndex, toIndex).mapToObj(slot -> getItemInSlot(container, slot)); + } + + @Override + public float getCollectingProgress() { + return progress; + } + } + + public static class ContainerItemIterator extends SlottedItemIterator { + public ContainerItemIterator(int fromIndex) { + this(Container.class::cast, fromIndex); + } + + public ContainerItemIterator(Function containerFinder, int fromIndex) { + super(containerFinder, fromIndex); + } + + @Override + protected int getSlotCount(Container container) { + return container.getContainerSize(); + } + + @Override + protected ItemStack getItemInSlot(Container container, int slot) { + return container.getItem(slot); + } + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/JadeCodec.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/JadeCodec.java new file mode 100644 index 0000000..a046ae4 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/JadeCodec.java @@ -0,0 +1,59 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.NotNull; + +public class JadeCodec { + public static final StreamCodec PRIMITIVE_STREAM_CODEC = new StreamCodec<>() { + @Override + public @NotNull Object decode(@NotNull ByteBuf buf) { + byte b = buf.readByte(); + if (b == 0) { + return false; + } else if (b == 1) { + return true; + } else if (b == 2) { + return ByteBufCodecs.VAR_INT.decode(buf); + } else if (b == 3) { + return ByteBufCodecs.FLOAT.decode(buf); + } else if (b == 4) { + return ByteBufCodecs.STRING_UTF8.decode(buf); + } else if (b > 20) { + return b - 20; + } + throw new IllegalArgumentException("Unknown primitive type: " + b); + } + + @Override + public void encode(@NotNull ByteBuf buf, @NotNull Object o) { + switch (o) { + case Boolean b -> buf.writeByte(b ? 1 : 0); + case Number n -> { + float f = n.floatValue(); + if (f != (int) f) { + buf.writeByte(3); + ByteBufCodecs.FLOAT.encode(buf, f); + } + int i = n.intValue(); + if (i <= Byte.MAX_VALUE - 20 && i >= 0) { + buf.writeByte(i + 20); + } else { + ByteBufCodecs.VAR_INT.encode(buf, i); + } + } + case String s -> { + buf.writeByte(4); + ByteBufCodecs.STRING_UTF8.encode(buf, s); + } + case Enum anEnum -> { + buf.writeByte(4); + ByteBufCodecs.STRING_UTF8.encode(buf, anEnum.name()); + } + case null -> throw new NullPointerException(); + default -> throw new IllegalArgumentException("Unknown primitive type: %s (%s)".formatted(o, o.getClass())); + } + } + }; +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/LootTableMineableCollector.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/LootTableMineableCollector.java new file mode 100644 index 0000000..9c580ab --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/LootTableMineableCollector.java @@ -0,0 +1,109 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import com.google.common.collect.Lists; +import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderGetter; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.storage.loot.LootPool; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.entries.AlternativesEntry; +import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; +import net.minecraft.world.level.storage.loot.entries.NestedLootTable; +import net.minecraft.world.level.storage.loot.predicates.AnyOfCondition; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.level.storage.loot.predicates.MatchTool; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.jade.tool.ShearsToolHandler; + +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +public class LootTableMineableCollector { + + private final HolderGetter lootRegistry; + private final ItemStack toolItem; + + public LootTableMineableCollector(HolderGetter lootRegistry, ItemStack toolItem) { + this.lootRegistry = lootRegistry; + this.toolItem = toolItem; + } + + public static @NotNull List execute(HolderGetter lootRegistry, ItemStack toolItem) { + LootTableMineableCollector collector = new LootTableMineableCollector(lootRegistry, toolItem); + List list = Lists.newArrayList(); + for (Block block : BuiltInRegistries.BLOCK) { + if (!ShearsToolHandler.getInstance().test(block.defaultBlockState()).isEmpty()) { + continue; + } + + if (block.getLootTable().isPresent()) { + LootTable lootTable = lootRegistry.get(block.getLootTable().get()).map(Holder::value).orElse(null); + if (collector.doLootTable(lootTable)) { + list.add(block); + } + } + } + return list; + } + + public static boolean isCorrectConditions(@NotNull List conditions, ItemStack toolItem) { + if (conditions.size() != 1) { + return false; + } + + LootItemCondition condition = conditions.getFirst(); + if (condition instanceof MatchTool(Optional predicate)) { + ItemPredicate itemPredicate = predicate.orElse(null); + return itemPredicate != null && itemPredicate.test(toolItem); + } else if (condition instanceof AnyOfCondition anyOfCondition) { + for (LootItemCondition child : anyOfCondition.terms) { + if (isCorrectConditions(List.of(child), toolItem)) { + return true; + } + } + } + return false; + } + + private boolean doLootTable(LootTable lootTable) { + if (lootTable == null || lootTable == LootTable.EMPTY) { + return false; + } + + for (LootPool pool : lootTable.pools) { + if (doLootPool(pool)) { + return true; + } + } + return false; + } + + private boolean doLootPool(@NotNull LootPool lootPool) { + for (LootPoolEntryContainer entry : lootPool.entries) { + if (doLootPoolEntry(entry)) { + return true; + } + } + return false; + } + + private boolean doLootPoolEntry(LootPoolEntryContainer entry) { + if (entry instanceof AlternativesEntry alternativesEntry) { + for (LootPoolEntryContainer child : alternativesEntry.children) { + if (doLootPoolEntry(child)) { + return true; + } + } + } else if (entry instanceof NestedLootTable nestedLootTable) { + LootTable lootTable = nestedLootTable.contents.map($ -> lootRegistry.get($).map(Holder::value).orElse(null), Function.identity()); + return doLootTable(lootTable); + } else { + return isCorrectConditions(entry.conditions, toolItem); + } + return false; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/PairHierarchyLookup.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/PairHierarchyLookup.java new file mode 100644 index 0000000..9e0dd9c --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/PairHierarchyLookup.java @@ -0,0 +1,115 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import net.minecraft.core.IdMapper; +import net.minecraft.resources.ResourceLocation; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.LeavesLogger; +import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; + +public class PairHierarchyLookup implements IHierarchyLookup { + public final IHierarchyLookup first; + public final IHierarchyLookup second; + private final Cache, Class>, List> mergedCache = CacheBuilder.newBuilder().build(); + protected boolean idMapped; + @Nullable + protected IdMapper idMapper; + + public PairHierarchyLookup(IHierarchyLookup first, IHierarchyLookup second) { + this.first = first; + this.second = second; + } + + @SuppressWarnings("unchecked") + public List getMerged(Object first, Object second) { + Objects.requireNonNull(first); + Objects.requireNonNull(second); + try { + return (List) mergedCache.get(Pair.of(first.getClass(), second.getClass()), () -> { + List firstList = this.first.get(first); + List secondList = this.second.get(second); + if (firstList.isEmpty()) { + return secondList; + } else if (secondList.isEmpty()) { + return firstList; + } + return ImmutableList.sortedCopyOf(COMPARATOR, Iterables.concat(firstList, secondList)); + }); + } catch (ExecutionException e) { + LeavesLogger.LOGGER.severe(e.toString()); + } + return List.of(); + } + + @Override + public void idMapped() { + idMapped = true; + } + + @Override + public @Nullable IdMapper idMapper() { + return idMapper; + } + + @Override + public void register(Class clazz, T provider) { + if (first.isClassAcceptable(clazz)) { + first.register(clazz, provider); + } else if (second.isClassAcceptable(clazz)) { + second.register(clazz, provider); + } else { + throw new IllegalArgumentException("Class " + clazz + " is not acceptable"); + } + } + + @Override + public boolean isClassAcceptable(Class clazz) { + return first.isClassAcceptable(clazz) || second.isClassAcceptable(clazz); + } + + @Override + public List get(Class clazz) { + List result = first.get(clazz); + if (result.isEmpty()) { + result = second.get(clazz); + } + return result; + } + + @Override + public boolean isEmpty() { + return first.isEmpty() && second.isEmpty(); + } + + @Override + public Stream, Collection>> entries() { + return Stream.concat(first.entries(), second.entries()); + } + + @Override + public void invalidate() { + first.invalidate(); + second.invalidate(); + mergedCache.invalidateAll(); + } + + @Override + public void loadComplete(PriorityStore priorityStore) { + first.loadComplete(priorityStore); + second.loadComplete(priorityStore); + if (idMapped) { + idMapper = createIdMapper(); + } + } +} \ No newline at end of file diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/PriorityStore.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/PriorityStore.java new file mode 100644 index 0000000..da4d5a7 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/PriorityStore.java @@ -0,0 +1,40 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; + +import java.util.Objects; +import java.util.function.Function; +import java.util.function.ToIntFunction; + +public class PriorityStore { + + private final Object2IntMap priorities = new Object2IntLinkedOpenHashMap<>(); + private final Function keyGetter; + private final ToIntFunction defaultPriorityGetter; + + public PriorityStore(ToIntFunction defaultPriorityGetter, Function keyGetter) { + this.defaultPriorityGetter = defaultPriorityGetter; + this.keyGetter = keyGetter; + } + + public void put(V provider) { + Objects.requireNonNull(provider); + put(provider, defaultPriorityGetter.applyAsInt(provider)); + } + + public void put(V provider, int priority) { + Objects.requireNonNull(provider); + K uid = keyGetter.apply(provider); + Objects.requireNonNull(uid); + priorities.put(uid, priority); + } + + public int byValue(V value) { + return byKey(keyGetter.apply(value)); + } + + public int byKey(K id) { + return priorities.getInt(id); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ViewGroup.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ViewGroup.java new file mode 100644 index 0000000..56f3e4e --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/ViewGroup.java @@ -0,0 +1,58 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import io.netty.buffer.ByteBuf; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ViewGroup { + public List views; + @Nullable + public String id; + @Nullable + protected CompoundTag extraData; + + public ViewGroup(List views) { + this(views, Optional.empty(), Optional.empty()); + } + + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + public ViewGroup(List views, Optional id, Optional extraData) { + this.views = views; + this.id = id.orElse(null); + this.extraData = extraData.orElse(null); + } + + public static StreamCodec> codec(StreamCodec viewCodec) { + return StreamCodec.composite( + ByteBufCodecs.list().apply(viewCodec), + $ -> $.views, + ByteBufCodecs.optional(ByteBufCodecs.STRING_UTF8), + $ -> Optional.ofNullable($.id), + ByteBufCodecs.optional(ByteBufCodecs.COMPOUND_TAG), + $ -> Optional.ofNullable($.extraData), + ViewGroup::new); + } + + public static StreamCodec>>> listCodec(StreamCodec viewCodec) { + return StreamCodec.composite( + ResourceLocation.STREAM_CODEC, + Map.Entry::getKey, + ByteBufCodecs.>list().apply(codec(viewCodec)), + Map.Entry::getValue, + Map::entry); + } + + public CompoundTag getExtraData() { + if (extraData == null) { + extraData = new CompoundTag(); + } + return extraData; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/WrappedHierarchyLookup.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/WrappedHierarchyLookup.java new file mode 100644 index 0000000..be8abe2 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/jade/util/WrappedHierarchyLookup.java @@ -0,0 +1,107 @@ +package org.leavesmc.leaves.protocol.jade.util; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.protocol.jade.accessor.Accessor; +import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor; +import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Stream; + +public class WrappedHierarchyLookup extends HierarchyLookup { + public final List, Function, @Nullable Object>>> overrides = Lists.newArrayList(); + private boolean empty = true; + + public WrappedHierarchyLookup() { + super(Object.class); + } + + @NotNull + public static WrappedHierarchyLookup forAccessor() { + WrappedHierarchyLookup lookup = new WrappedHierarchyLookup<>(); + lookup.overrides.add(Pair.of( + new HierarchyLookup<>(Block.class), accessor -> { + if (accessor instanceof BlockAccessor blockAccessor) { + return blockAccessor.getBlock(); + } + return null; + })); + return lookup; + } + + public List wrappedGet(Accessor accessor) { + Set set = Sets.newLinkedHashSet(); + for (var override : overrides) { + Object o = override.getRight().apply(accessor); + if (o != null) { + set.addAll(override.getLeft().get(o)); + } + } + set.addAll(get(accessor.getTarget())); + return ImmutableList.sortedCopyOf(COMPARATOR, set); + } + + @Override + public void register(Class clazz, T provider) { + for (var override : overrides) { + if (override.getLeft().isClassAcceptable(clazz)) { + override.getLeft().register(clazz, provider); + empty = false; + return; + } + } + super.register(clazz, provider); + empty = false; + } + + @Override + public boolean isClassAcceptable(Class clazz) { + for (var override : overrides) { + if (override.getLeft().isClassAcceptable(clazz)) { + return true; + } + } + return super.isClassAcceptable(clazz); + } + + @Override + public void invalidate() { + for (var override : overrides) { + override.getLeft().invalidate(); + } + super.invalidate(); + } + + @Override + public void loadComplete(PriorityStore priorityStore) { + for (var override : overrides) { + override.getLeft().loadComplete(priorityStore); + } + super.loadComplete(priorityStore); + } + + @Override + public boolean isEmpty() { + return empty; + } + + @Override + public Stream, Collection>> entries() { + Stream, Collection>> stream = super.entries(); + for (var override : overrides) { + stream = Stream.concat(stream, override.getLeft().entries()); + } + return stream; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java new file mode 100644 index 0000000..c9fcf90 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java @@ -0,0 +1,389 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import com.mojang.authlib.GameProfile; +import io.netty.buffer.Unpooled; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import org.bxteam.divinemc.config.DivineConfig; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.core.LeavesProtocol; +import org.leavesmc.leaves.protocol.core.ProtocolHandler; +import org.leavesmc.leaves.protocol.syncmatica.exchange.DownloadExchange; +import org.leavesmc.leaves.protocol.syncmatica.exchange.Exchange; +import org.leavesmc.leaves.protocol.syncmatica.exchange.ExchangeTarget; +import org.leavesmc.leaves.protocol.syncmatica.exchange.ModifyExchangeServer; +import org.leavesmc.leaves.protocol.syncmatica.exchange.UploadExchange; +import org.leavesmc.leaves.protocol.syncmatica.exchange.VersionHandshakeServer; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@LeavesProtocol.Register(namespace = "syncmatica") +public class CommunicationManager implements LeavesProtocol { + + protected static final Collection broadcastTargets = new ArrayList<>(); + protected static final Map downloadState = new HashMap<>(); + protected static final Map modifyState = new HashMap<>(); + protected static final Rotation[] rotOrdinals = Rotation.values(); + protected static final Mirror[] mirOrdinals = Mirror.values(); + private static final Map> downloadingFile = new HashMap<>(); + private static final Map playerMap = new HashMap<>(); + + public CommunicationManager() { + } + + public static GameProfile getGameProfile(final ExchangeTarget exchangeTarget) { + return playerMap.get(exchangeTarget).getGameProfile(); + } + + @ProtocolHandler.PlayerJoin + public static void onPlayerJoin(ServerPlayer player) { + final ExchangeTarget newPlayer = player.connection.exchangeTarget; + final VersionHandshakeServer hi = new VersionHandshakeServer(newPlayer); + playerMap.put(newPlayer, player); + final GameProfile profile = player.getGameProfile(); + SyncmaticaProtocol.getPlayerIdentifierProvider().updateName(profile.getId(), profile.getName()); + startExchangeUnchecked(hi); + } + + @ProtocolHandler.PlayerLeave + public static void onPlayerLeave(ServerPlayer player) { + final ExchangeTarget oldPlayer = player.connection.exchangeTarget; + final Collection potentialMessageTarget = oldPlayer.getExchanges(); + if (potentialMessageTarget != null) { + for (final Exchange target : potentialMessageTarget) { + target.close(false); + handleExchange(target); + } + } + broadcastTargets.remove(oldPlayer); + playerMap.remove(oldPlayer); + } + + @ProtocolHandler.PayloadReceiver(payload = SyncmaticaPayload.class) + public static void onPacketGet(ServerPlayer player, SyncmaticaPayload payload) { + onPacket(player.connection.exchangeTarget, payload.packetType(), payload.data()); + } + + public static void onPacket(final @NotNull ExchangeTarget source, final ResourceLocation id, final FriendlyByteBuf packetBuf) { + Exchange handler = null; + final Collection potentialMessageTarget = source.getExchanges(); + if (potentialMessageTarget != null) { + for (final Exchange target : potentialMessageTarget) { + if (target.checkPacket(id, packetBuf)) { + target.handle(id, packetBuf); + handler = target; + break; + } + } + } + if (handler == null) { + handle(source, id, packetBuf); + } else if (handler.isFinished()) { + notifyClose(handler); + } + } + + protected static void handle(ExchangeTarget source, @NotNull ResourceLocation id, FriendlyByteBuf packetBuf) { + if (id.equals(PacketType.REQUEST_LITEMATIC.identifier)) { + final UUID syncmaticaId = packetBuf.readUUID(); + final ServerPlacement placement = SyncmaticaProtocol.getSyncmaticManager().getPlacement(syncmaticaId); + if (placement == null) { + return; + } + final File toUpload = SyncmaticaProtocol.getFileStorage().getLocalLitematic(placement); + final UploadExchange upload; + try { + upload = new UploadExchange(placement, toUpload, source); + } catch (final FileNotFoundException e) { + e.printStackTrace(); + return; + } + startExchange(upload); + return; + } + if (id.equals(PacketType.REGISTER_METADATA.identifier)) { + final ServerPlacement placement = receiveMetaData(packetBuf, source); + if (SyncmaticaProtocol.getSyncmaticManager().getPlacement(placement.getId()) != null) { + cancelShare(source, placement); + return; + } + + final GameProfile profile = playerMap.get(source).getGameProfile(); + final PlayerIdentifier playerIdentifier = SyncmaticaProtocol.getPlayerIdentifierProvider().createOrGet(profile); + if (!placement.getOwner().equals(playerIdentifier)) { + placement.setOwner(playerIdentifier); + placement.setLastModifiedBy(playerIdentifier); + } + + if (!SyncmaticaProtocol.getFileStorage().getLocalState(placement).isLocalFileReady()) { + if (SyncmaticaProtocol.getFileStorage().getLocalState(placement) == LocalLitematicState.DOWNLOADING_LITEMATIC) { + downloadingFile.computeIfAbsent(placement.getHash(), key -> new ArrayList<>()).add(placement); + return; + } + try { + download(placement, source); + } catch (final Exception e) { + e.printStackTrace(); + } + return; + } + + addPlacement(source, placement); + return; + } + if (id.equals(PacketType.REMOVE_SYNCMATIC.identifier)) { + final UUID placementId = packetBuf.readUUID(); + final ServerPlacement placement = SyncmaticaProtocol.getSyncmaticManager().getPlacement(placementId); + if (placement != null) { + if (!getGameProfile(source).getId().equals(placement.getOwner().uuid)) { + return; + } + + final Exchange modifier = getModifier(placement); + if (modifier != null) { + modifier.close(true); + notifyClose(modifier); + } + SyncmaticaProtocol.getSyncmaticManager().removePlacement(placement); + for (final ExchangeTarget client : broadcastTargets) { + final FriendlyByteBuf newPacketBuf = new FriendlyByteBuf(Unpooled.buffer()); + newPacketBuf.writeUUID(placement.getId()); + client.sendPacket(PacketType.REMOVE_SYNCMATIC.identifier, newPacketBuf); + } + } + } + if (id.equals(PacketType.MODIFY_REQUEST.identifier)) { + final UUID placementId = packetBuf.readUUID(); + final ModifyExchangeServer modifier = new ModifyExchangeServer(placementId, source); + startExchange(modifier); + } + } + + protected static void handleExchange(Exchange exchange) { + if (exchange instanceof DownloadExchange) { + final ServerPlacement p = ((DownloadExchange) exchange).getPlacement(); + + if (exchange.isSuccessful()) { + addPlacement(exchange.getPartner(), p); + if (downloadingFile.containsKey(p.getHash())) { + for (final ServerPlacement placement : downloadingFile.get(p.getHash())) { + addPlacement(exchange.getPartner(), placement); + } + } + } else { + cancelShare(exchange.getPartner(), p); + if (downloadingFile.containsKey(p.getHash())) { + for (final ServerPlacement placement : downloadingFile.get(p.getHash())) { + cancelShare(exchange.getPartner(), placement); + } + } + } + + downloadingFile.remove(p.getHash()); + return; + } + if (exchange instanceof VersionHandshakeServer && exchange.isSuccessful()) { + broadcastTargets.add(exchange.getPartner()); + } + if (exchange instanceof ModifyExchangeServer && exchange.isSuccessful()) { + final ServerPlacement placement = ((ModifyExchangeServer) exchange).getPlacement(); + for (final ExchangeTarget client : broadcastTargets) { + if (client.getFeatureSet().hasFeature(Feature.MODIFY)) { + final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeUUID(placement.getId()); + putPositionData(placement, buf, client); + if (client.getFeatureSet().hasFeature(Feature.CORE_EX)) { + buf.writeUUID(placement.getLastModifiedBy().uuid); + buf.writeUtf(placement.getLastModifiedBy().getName()); + } + client.sendPacket(PacketType.MODIFY.identifier, buf); + } else { + final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeUUID(placement.getId()); + client.sendPacket(PacketType.REMOVE_SYNCMATIC.identifier, buf); + sendMetaData(placement, client); + } + } + } + } + + private static void addPlacement(final ExchangeTarget t, final @NotNull ServerPlacement placement) { + if (SyncmaticaProtocol.getSyncmaticManager().getPlacement(placement.getId()) != null) { + cancelShare(t, placement); + return; + } + SyncmaticaProtocol.getSyncmaticManager().addPlacement(placement); + for (final ExchangeTarget target : broadcastTargets) { + sendMetaData(placement, target); + } + } + + private static void cancelShare(final @NotNull ExchangeTarget source, final @NotNull ServerPlacement placement) { + final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); + FriendlyByteBuf.writeUUID(placement.getId()); + source.sendPacket(PacketType.CANCEL_SHARE.identifier, FriendlyByteBuf); + } + + public static void sendMetaData(final ServerPlacement metaData, final ExchangeTarget target) { + final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + putMetaData(metaData, buf, target); + target.sendPacket(PacketType.REGISTER_METADATA.identifier, buf); + } + + public static void putMetaData(final @NotNull ServerPlacement metaData, final @NotNull FriendlyByteBuf buf, final @NotNull ExchangeTarget exchangeTarget) { + buf.writeUUID(metaData.getId()); + + buf.writeUtf(SyncmaticaProtocol.sanitizeFileName(metaData.getName())); + buf.writeUUID(metaData.getHash()); + + if (exchangeTarget.getFeatureSet().hasFeature(Feature.CORE_EX)) { + buf.writeUUID(metaData.getOwner().uuid); + buf.writeUtf(metaData.getOwner().getName()); + buf.writeUUID(metaData.getLastModifiedBy().uuid); + buf.writeUtf(metaData.getLastModifiedBy().getName()); + } + + putPositionData(metaData, buf, exchangeTarget); + } + + public static void putPositionData(final @NotNull ServerPlacement metaData, final @NotNull FriendlyByteBuf buf, final @NotNull ExchangeTarget exchangeTarget) { + buf.writeBlockPos(metaData.getPosition()); + buf.writeUtf(metaData.getDimension()); + buf.writeInt(metaData.getRotation().ordinal()); + buf.writeInt(metaData.getMirror().ordinal()); + + if (exchangeTarget.getFeatureSet().hasFeature(Feature.CORE_EX)) { + if (metaData.getSubRegionData().getModificationData() == null) { + buf.writeInt(0); + return; + } + + final Collection regionData = metaData.getSubRegionData().getModificationData().values(); + buf.writeInt(regionData.size()); + + for (final SubRegionPlacementModification subPlacement : regionData) { + buf.writeUtf(subPlacement.name); + buf.writeBlockPos(subPlacement.position); + buf.writeInt(subPlacement.rotation.ordinal()); + buf.writeInt(subPlacement.mirror.ordinal()); + } + } + } + + public static ServerPlacement receiveMetaData(final @NotNull FriendlyByteBuf buf, final @NotNull ExchangeTarget exchangeTarget) { + final UUID id = buf.readUUID(); + + final String fileName = SyncmaticaProtocol.sanitizeFileName(buf.readUtf(32767)); + final UUID hash = buf.readUUID(); + + PlayerIdentifier owner = PlayerIdentifier.MISSING_PLAYER; + PlayerIdentifier lastModifiedBy = PlayerIdentifier.MISSING_PLAYER; + + if (exchangeTarget.getFeatureSet().hasFeature(Feature.CORE_EX)) { + final PlayerIdentifierProvider provider = SyncmaticaProtocol.getPlayerIdentifierProvider(); + owner = provider.createOrGet(buf.readUUID(), buf.readUtf(32767)); + lastModifiedBy = provider.createOrGet(buf.readUUID(), buf.readUtf(32767)); + } + + final ServerPlacement placement = new ServerPlacement(id, fileName, hash, owner); + placement.setLastModifiedBy(lastModifiedBy); + + receivePositionData(placement, buf, exchangeTarget); + + return placement; + } + + public static void receivePositionData(final @NotNull ServerPlacement placement, final @NotNull FriendlyByteBuf buf, final @NotNull ExchangeTarget exchangeTarget) { + final BlockPos pos = buf.readBlockPos(); + final String dimensionId = buf.readUtf(32767); + final Rotation rot = rotOrdinals[buf.readInt()]; + final Mirror mir = mirOrdinals[buf.readInt()]; + placement.move(dimensionId, pos, rot, mir); + + if (exchangeTarget.getFeatureSet().hasFeature(Feature.CORE_EX)) { + final SubRegionData subRegionData = placement.getSubRegionData(); + subRegionData.reset(); + final int limit = buf.readInt(); + for (int i = 0; i < limit; i++) { + subRegionData.modify(buf.readUtf(32767), buf.readBlockPos(), rotOrdinals[buf.readInt()], mirOrdinals[buf.readInt()]); + } + } + } + + public static void download(final ServerPlacement syncmatic, final ExchangeTarget source) throws NoSuchAlgorithmException, IOException { + if (!SyncmaticaProtocol.getFileStorage().getLocalState(syncmatic).isReadyForDownload()) { + throw new IllegalArgumentException(syncmatic.toString() + " is not ready for download local state is: " + SyncmaticaProtocol.getFileStorage().getLocalState(syncmatic).toString()); + } + final File toDownload = SyncmaticaProtocol.getFileStorage().createLocalLitematic(syncmatic); + final Exchange downloadExchange = new DownloadExchange(syncmatic, toDownload, source); + setDownloadState(syncmatic, true); + startExchange(downloadExchange); + } + + public static void setDownloadState(final @NotNull ServerPlacement syncmatic, final boolean b) { + downloadState.put(syncmatic.getHash(), b); + } + + public static boolean getDownloadState(final @NotNull ServerPlacement syncmatic) { + return downloadState.getOrDefault(syncmatic.getHash(), false); + } + + public static void setModifier(final @NotNull ServerPlacement syncmatic, final Exchange exchange) { + modifyState.put(syncmatic.getHash(), exchange); + } + + public static Exchange getModifier(final @NotNull ServerPlacement syncmatic) { + return modifyState.get(syncmatic.getHash()); + } + + public static void startExchange(final @NotNull Exchange newExchange) { + if (!broadcastTargets.contains(newExchange.getPartner())) { + throw new IllegalArgumentException(newExchange.getPartner().toString() + " is not a valid ExchangeTarget"); + } + startExchangeUnchecked(newExchange); + } + + protected static void startExchangeUnchecked(final @NotNull Exchange newExchange) { + newExchange.getPartner().getExchanges().add(newExchange); + newExchange.init(); + if (newExchange.isFinished()) { + notifyClose(newExchange); + } + } + + public static void notifyClose(final @NotNull Exchange e) { + e.getPartner().getExchanges().remove(e); + handleExchange(e); + } + + public void sendMessage(final @NotNull ExchangeTarget client, final MessageType type, final String identifier) { + if (client.getFeatureSet().hasFeature(Feature.MESSAGE)) { + final FriendlyByteBuf newPacketBuf = new FriendlyByteBuf(Unpooled.buffer()); + newPacketBuf.writeUtf(type.toString()); + newPacketBuf.writeUtf(identifier); + client.sendPacket(PacketType.MESSAGE.identifier, newPacketBuf); + } else if (playerMap.containsKey(client)) { + final ServerPlayer player = playerMap.get(client); + player.sendSystemMessage(Component.literal("Syncmatica " + type.toString() + " " + identifier)); + } + } + + @Override + public boolean isActive() { + return DivineConfig.NetworkCategory.protocolsSyncMaticaEnabled; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/Feature.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/Feature.java new file mode 100644 index 0000000..7cb3465 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/Feature.java @@ -0,0 +1,23 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import org.jetbrains.annotations.Nullable; + +public enum Feature { + CORE, + FEATURE, + MODIFY, + MESSAGE, + QUOTA, + DEBUG, + CORE_EX; + + @Nullable + public static Feature fromString(final String s) { + for (final Feature f : Feature.values()) { + if (f.toString().equals(s)) { + return f; + } + } + return null; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/FeatureSet.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/FeatureSet.java new file mode 100644 index 0000000..fdd2e32 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/FeatureSet.java @@ -0,0 +1,68 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class FeatureSet { + + private static final Map versionFeatures; + + static { + versionFeatures = new HashMap<>(); + versionFeatures.put("0.1", new FeatureSet(Collections.singletonList(Feature.CORE))); + } + + private final Collection features; + + public FeatureSet(final Collection features) { + this.features = features; + } + + @Nullable + public static FeatureSet fromVersionString(@NotNull String version) { + if (version.matches("^\\d+(\\.\\d+){2,4}$")) { + final int minSize = version.indexOf("."); + while (version.length() > minSize) { + if (versionFeatures.containsKey(version)) { + return versionFeatures.get(version); + } + final int lastDot = version.lastIndexOf("."); + version = version.substring(0, lastDot); + } + } + return null; + } + + @NotNull + public static FeatureSet fromString(final @NotNull String features) { + final FeatureSet featureSet = new FeatureSet(new ArrayList<>()); + for (final String feature : features.split("\n")) { + final Feature f = Feature.fromString(feature); + if (f != null) { + featureSet.features.add(f); + } + } + return featureSet; + } + + @Override + public String toString() { + final StringBuilder output = new StringBuilder(); + boolean b = false; + for (final Feature feature : features) { + output.append(b ? "\n" + feature.toString() : feature.toString()); + b = true; + } + return output.toString(); + } + + public boolean hasFeature(final Feature f) { + return features.contains(f); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/FileStorage.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/FileStorage.java new file mode 100644 index 0000000..a630b12 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/FileStorage.java @@ -0,0 +1,80 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.UUID; + +public class FileStorage { + + private final HashMap buffer = new HashMap<>(); + + public LocalLitematicState getLocalState(final ServerPlacement placement) { + final File localFile = getSchematicPath(placement); + if (localFile.isFile()) { + if (isDownloading(placement)) { + return LocalLitematicState.DOWNLOADING_LITEMATIC; + } + if ((buffer.containsKey(placement) && buffer.get(placement) == localFile.lastModified()) || hashCompare(localFile, placement)) { + return LocalLitematicState.LOCAL_LITEMATIC_PRESENT; + } + return LocalLitematicState.LOCAL_LITEMATIC_DESYNC; + } + return LocalLitematicState.NO_LOCAL_LITEMATIC; + } + + private boolean isDownloading(final ServerPlacement placement) { + return CommunicationManager.getDownloadState(placement); + } + + public File getLocalLitematic(final ServerPlacement placement) { + if (getLocalState(placement).isLocalFileReady()) { + return getSchematicPath(placement); + } else { + return null; + } + } + + public File createLocalLitematic(final ServerPlacement placement) { + if (getLocalState(placement).isLocalFileReady()) { + throw new IllegalArgumentException(""); + } + final File file = getSchematicPath(placement); + if (file.exists()) { + file.delete(); + } + try { + file.createNewFile(); + } catch (final IOException e) { + e.printStackTrace(); + } + return file; + } + + private boolean hashCompare(final File localFile, final ServerPlacement placement) { + UUID hash = null; + try { + hash = SyncmaticaProtocol.createChecksum(new FileInputStream(localFile)); + } catch (final Exception e) { + e.printStackTrace(); + } + + if (hash == null) { + return false; + } + if (hash.equals(placement.getHash())) { + buffer.put(placement, localFile.lastModified()); + return true; + } + return false; + } + + @Contract("_ -> new") + private @NotNull File getSchematicPath(final @NotNull ServerPlacement placement) { + return new File(SyncmaticaProtocol.getLitematicFolder(), placement.getHash().toString() + ".litematic"); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/LocalLitematicState.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/LocalLitematicState.java new file mode 100644 index 0000000..299c573 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/LocalLitematicState.java @@ -0,0 +1,24 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +public enum LocalLitematicState { + NO_LOCAL_LITEMATIC(true, false), + LOCAL_LITEMATIC_DESYNC(true, false), + DOWNLOADING_LITEMATIC(false, false), + LOCAL_LITEMATIC_PRESENT(false, true); + + private final boolean downloadReady; + private final boolean fileReady; + + LocalLitematicState(final boolean downloadReady, final boolean fileReady) { + this.downloadReady = downloadReady; + this.fileReady = fileReady; + } + + public boolean isReadyForDownload() { + return downloadReady; + } + + public boolean isLocalFileReady() { + return fileReady; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/MessageType.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/MessageType.java new file mode 100644 index 0000000..b56ca12 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/MessageType.java @@ -0,0 +1,8 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +public enum MessageType { + SUCCESS, + INFO, + WARNING, + ERROR +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PacketType.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PacketType.java new file mode 100644 index 0000000..d364382 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PacketType.java @@ -0,0 +1,30 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import net.minecraft.resources.ResourceLocation; + +public enum PacketType { + REGISTER_METADATA("register_metadata"), + CANCEL_SHARE("cancel_share"), + REQUEST_LITEMATIC("request_download"), + SEND_LITEMATIC("send_litematic"), + RECEIVED_LITEMATIC("received_litematic"), + FINISHED_LITEMATIC("finished_litematic"), + CANCEL_LITEMATIC("cancel_litematic"), + REMOVE_SYNCMATIC("remove_syncmatic"), + REGISTER_VERSION("register_version"), + CONFIRM_USER("confirm_user"), + FEATURE_REQUEST("feature_request"), + FEATURE("feature"), + MODIFY("modify"), + MODIFY_REQUEST("modify_request"), + MODIFY_REQUEST_DENY("modify_request_deny"), + MODIFY_REQUEST_ACCEPT("modify_request_accept"), + MODIFY_FINISH("modify_finish"), + MESSAGE("mesage"); + + public final ResourceLocation identifier; + + PacketType(final String id) { + identifier = ResourceLocation.tryBuild(SyncmaticaProtocol.PROTOCOL_ID, id); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PlayerIdentifier.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PlayerIdentifier.java new file mode 100644 index 0000000..b5891b0 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PlayerIdentifier.java @@ -0,0 +1,37 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import java.util.UUID; + +public class PlayerIdentifier { + + public static final UUID MISSING_PLAYER_UUID = UUID.fromString("4c1b738f-56fa-4011-8273-498c972424ea"); + public static final PlayerIdentifier MISSING_PLAYER = new PlayerIdentifier(MISSING_PLAYER_UUID, "No Player"); + + public final UUID uuid; + private String bufferedPlayerName; + + PlayerIdentifier(final UUID uuid, final String bufferedPlayerName) { + this.uuid = uuid; + this.bufferedPlayerName = bufferedPlayerName; + } + + public String getName() { + return bufferedPlayerName; + } + + public void updatePlayerName(final String name) { + bufferedPlayerName = name; + } + + public JsonObject toJson() { + final JsonObject jsonObject = new JsonObject(); + + jsonObject.add("uuid", new JsonPrimitive(uuid.toString())); + jsonObject.add("name", new JsonPrimitive(bufferedPlayerName)); + + return jsonObject; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PlayerIdentifierProvider.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PlayerIdentifierProvider.java new file mode 100644 index 0000000..4a6248f --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/PlayerIdentifierProvider.java @@ -0,0 +1,46 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.syncmatica.exchange.ExchangeTarget; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class PlayerIdentifierProvider { + + private final Map identifiers = new HashMap<>(); + + public PlayerIdentifierProvider() { + identifiers.put(PlayerIdentifier.MISSING_PLAYER_UUID, PlayerIdentifier.MISSING_PLAYER); + } + + public PlayerIdentifier createOrGet(final ExchangeTarget exchangeTarget) { + return createOrGet(CommunicationManager.getGameProfile(exchangeTarget)); + } + + public PlayerIdentifier createOrGet(final @NotNull GameProfile gameProfile) { + return createOrGet(gameProfile.getId(), gameProfile.getName()); + } + + public PlayerIdentifier createOrGet(final UUID uuid, final String playerName) { + return identifiers.computeIfAbsent(uuid, id -> new PlayerIdentifier(uuid, playerName)); + } + + public void updateName(final UUID uuid, final String playerName) { + createOrGet(uuid, playerName).updatePlayerName(playerName); + } + + public PlayerIdentifier fromJson(final @NotNull JsonObject obj) { + if (!obj.has("uuid") || !obj.has("name")) { + return PlayerIdentifier.MISSING_PLAYER; + } + + final UUID jsonUUID = UUID.fromString(obj.get("uuid").getAsString()); + return identifiers.computeIfAbsent(jsonUUID, + key -> new PlayerIdentifier(jsonUUID, obj.get("name").getAsString()) + ); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/ServerPlacement.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/ServerPlacement.java new file mode 100644 index 0000000..2c7ca6c --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/ServerPlacement.java @@ -0,0 +1,166 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public class ServerPlacement { + + private final UUID id; + + private final String fileName; + private final UUID hashValue; + + private PlayerIdentifier owner; + private PlayerIdentifier lastModifiedBy; + + private ServerPosition origin; + private Rotation rotation; + private Mirror mirror; + + private SubRegionData subRegionData = new SubRegionData(); + + public ServerPlacement(final UUID id, final String fileName, final UUID hashValue, final PlayerIdentifier owner) { + this.id = id; + this.fileName = fileName; + this.hashValue = hashValue; + this.owner = owner; + lastModifiedBy = owner; + } + + @Nullable + public static ServerPlacement fromJson(final @NotNull JsonObject obj) { + if (obj.has("id") + && obj.has("file_name") + && obj.has("hash") + && obj.has("origin") + && obj.has("rotation") + && obj.has("mirror")) { + final UUID id = UUID.fromString(obj.get("id").getAsString()); + final String name = obj.get("file_name").getAsString(); + final UUID hashValue = UUID.fromString(obj.get("hash").getAsString()); + + PlayerIdentifier owner = PlayerIdentifier.MISSING_PLAYER; + if (obj.has("owner")) { + owner = SyncmaticaProtocol.getPlayerIdentifierProvider().fromJson(obj.get("owner").getAsJsonObject()); + } + + final ServerPlacement newPlacement = new ServerPlacement(id, name, hashValue, owner); + final ServerPosition pos = ServerPosition.fromJson(obj.get("origin").getAsJsonObject()); + if (pos == null) { + return null; + } + newPlacement.origin = pos; + newPlacement.rotation = Rotation.valueOf(obj.get("rotation").getAsString()); + newPlacement.mirror = Mirror.valueOf(obj.get("mirror").getAsString()); + + if (obj.has("lastModifiedBy")) { + newPlacement.lastModifiedBy = SyncmaticaProtocol.getPlayerIdentifierProvider() + .fromJson(obj.get("lastModifiedBy").getAsJsonObject()); + } else { + newPlacement.lastModifiedBy = owner; + } + + if (obj.has("subregionData")) { + newPlacement.subRegionData = SubRegionData.fromJson(obj.get("subregionData")); + } + + return newPlacement; + } + + return null; + } + + public UUID getId() { + return id; + } + + public String getName() { + return fileName; + } + + public UUID getHash() { + return hashValue; + } + + public String getDimension() { + return origin.getDimensionId(); + } + + public BlockPos getPosition() { + return origin.getBlockPosition(); + } + + public ServerPosition getOrigin() { + return origin; + } + + public Rotation getRotation() { + return rotation; + } + + public Mirror getMirror() { + return mirror; + } + + public ServerPlacement move(final String dimensionId, final BlockPos origin, final Rotation rotation, final Mirror mirror) { + move(new ServerPosition(origin, dimensionId), rotation, mirror); + return this; + } + + public ServerPlacement move(final ServerPosition origin, final Rotation rotation, final Mirror mirror) { + this.origin = origin; + this.rotation = rotation; + this.mirror = mirror; + return this; + } + + public PlayerIdentifier getOwner() { + return owner; + } + + public void setOwner(final PlayerIdentifier playerIdentifier) { + owner = playerIdentifier; + } + + public PlayerIdentifier getLastModifiedBy() { + return lastModifiedBy; + } + + public void setLastModifiedBy(final PlayerIdentifier lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public SubRegionData getSubRegionData() { + return subRegionData; + } + + public JsonObject toJson() { + final JsonObject obj = new JsonObject(); + obj.add("id", new JsonPrimitive(id.toString())); + + obj.add("file_name", new JsonPrimitive(fileName)); + obj.add("hash", new JsonPrimitive(hashValue.toString())); + + obj.add("origin", origin.toJson()); + obj.add("rotation", new JsonPrimitive(rotation.name())); + obj.add("mirror", new JsonPrimitive(mirror.name())); + + obj.add("owner", owner.toJson()); + if (!owner.equals(lastModifiedBy)) { + obj.add("lastModifiedBy", lastModifiedBy.toJson()); + } + + if (subRegionData.isModified()) { + obj.add("subregionData", subRegionData.toJson()); + } + + return obj; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/ServerPosition.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/ServerPosition.java new file mode 100644 index 0000000..63573bc --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/ServerPosition.java @@ -0,0 +1,51 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import net.minecraft.core.BlockPos; + +public class ServerPosition { + + private final BlockPos position; + private final String dimensionId; + + public ServerPosition(final BlockPos pos, final String dim) { + position = pos; + dimensionId = dim; + } + + public static ServerPosition fromJson(final JsonObject obj) { + if (obj.has("position") && obj.has("dimension")) { + final int x; + final int y; + final int z; + final JsonArray arr = obj.get("position").getAsJsonArray(); + x = arr.get(0).getAsInt(); + y = arr.get(1).getAsInt(); + z = arr.get(2).getAsInt(); + final BlockPos pos = new BlockPos(x, y, z); + return new ServerPosition(pos, obj.get("dimension").getAsString()); + } + return null; + } + + public BlockPos getBlockPosition() { + return position; + } + + public String getDimensionId() { + return dimensionId; + } + + public JsonObject toJson() { + final JsonObject obj = new JsonObject(); + final JsonArray arr = new JsonArray(); + arr.add(new JsonPrimitive(position.getX())); + arr.add(new JsonPrimitive(position.getY())); + arr.add(new JsonPrimitive(position.getZ())); + obj.add("position", arr); + obj.add("dimension", new JsonPrimitive(dimensionId)); + return obj; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SubRegionData.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SubRegionData.java new file mode 100644 index 0000000..09bf795 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SubRegionData.java @@ -0,0 +1,90 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +public class SubRegionData { + + private boolean isModified; + private Map modificationData; // is null when isModified is false + + public SubRegionData() { + this(false, null); + } + + public SubRegionData(final boolean isModified, final Map modificationData) { + this.isModified = isModified; + this.modificationData = modificationData; + } + + @NotNull + public static SubRegionData fromJson(final @NotNull JsonElement obj) { + final SubRegionData newSubRegionData = new SubRegionData(); + + newSubRegionData.isModified = true; + + for (final JsonElement modification : obj.getAsJsonArray()) { + newSubRegionData.modify(SubRegionPlacementModification.fromJson(modification.getAsJsonObject())); + } + + return newSubRegionData; + } + + public void reset() { + isModified = false; + modificationData = null; + } + + public void modify(final String name, final BlockPos position, final Rotation rotation, final Mirror mirror) { + modify(new SubRegionPlacementModification(name, position, rotation, mirror)); + } + + public void modify(final SubRegionPlacementModification subRegionPlacementModification) { + if (subRegionPlacementModification == null) { + return; + } + isModified = true; + if (modificationData == null) { + modificationData = new HashMap<>(); + } + modificationData.put(subRegionPlacementModification.name, subRegionPlacementModification); + } + + public boolean isModified() { + return isModified; + } + + public Map getModificationData() { + return modificationData; + } + + public JsonElement toJson() { + return modificationDataToJson(); + } + + @NotNull + private JsonElement modificationDataToJson() { + final JsonArray arr = new JsonArray(); + + for (final Map.Entry entry : modificationData.entrySet()) { + arr.add(entry.getValue().toJson()); + } + + return arr; + } + + @Override + public String toString() { + if (!isModified) { + return "[]"; + } + return modificationData == null ? "[ERROR:null]" : modificationData.toString(); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SubRegionPlacementModification.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SubRegionPlacementModification.java new file mode 100644 index 0000000..2410075 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SubRegionPlacementModification.java @@ -0,0 +1,65 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SubRegionPlacementModification { + + public final String name; + public final BlockPos position; + public final Rotation rotation; + public final Mirror mirror; + + SubRegionPlacementModification(final String name, final BlockPos position, final Rotation rotation, final Mirror mirror) { + this.name = name; + this.position = position; + this.rotation = rotation; + this.mirror = mirror; + } + + @Nullable + public static SubRegionPlacementModification fromJson(final @NotNull JsonObject obj) { + if (!obj.has("name") || !obj.has("position") || !obj.has("rotation") || !obj.has("mirror")) { + return null; + } + + final String name = obj.get("name").getAsString(); + final JsonArray arr = obj.get("position").getAsJsonArray(); + if (arr.size() != 3) { + return null; + } + + final BlockPos position = new BlockPos(arr.get(0).getAsInt(), arr.get(1).getAsInt(), arr.get(2).getAsInt()); + final Rotation rotation = Rotation.valueOf(obj.get("rotation").getAsString()); + final Mirror mirror = Mirror.valueOf(obj.get("mirror").getAsString()); + + return new SubRegionPlacementModification(name, position, rotation, mirror); + } + + public JsonObject toJson() { + final JsonObject obj = new JsonObject(); + + final JsonArray arr = new JsonArray(); + arr.add(position.getX()); + arr.add(position.getY()); + arr.add(position.getZ()); + obj.add("position", arr); + + obj.add("name", new JsonPrimitive(name)); + obj.add("rotation", new JsonPrimitive(rotation.name())); + obj.add("mirror", new JsonPrimitive(mirror.name())); + + return obj; + } + + @Override + public String toString() { + return String.format("[name=%s, position=%s, rotation=%s, mirror=%s]", name, position, rotation, mirror); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticManager.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticManager.java new file mode 100644 index 0000000..27a056b --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticManager.java @@ -0,0 +1,108 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class SyncmaticManager { + + public static final String PLACEMENTS_JSON_KEY = "placements"; + private final Map schematics = new HashMap<>(); + + public void addPlacement(final ServerPlacement placement) { + schematics.put(placement.getId(), placement); + updateServerPlacement(); + } + + public ServerPlacement getPlacement(final UUID id) { + return schematics.get(id); + } + + public Collection getAll() { + return schematics.values(); + } + + public void removePlacement(final @NotNull ServerPlacement placement) { + schematics.remove(placement.getId()); + updateServerPlacement(); + } + + public void updateServerPlacement() { + saveServer(); + } + + public void startup() { + loadServer(); + } + + private void saveServer() { + final JsonObject obj = new JsonObject(); + final JsonArray arr = new JsonArray(); + + for (final ServerPlacement p : getAll()) { + arr.add(p.toJson()); + } + + obj.add(PLACEMENTS_JSON_KEY, arr); + final File backup = new File(SyncmaticaProtocol.getLitematicFolder(), "placements.json.bak"); + final File incoming = new File(SyncmaticaProtocol.getLitematicFolder(), "placements.json.new"); + final File current = new File(SyncmaticaProtocol.getLitematicFolder(), "placements.json"); + + try (final FileWriter writer = new FileWriter(incoming)) { + writer.write(new GsonBuilder().setPrettyPrinting().create().toJson(obj)); + } catch (final IOException e) { + e.printStackTrace(); + return; + } + + SyncmaticaProtocol.backupAndReplace(backup.toPath(), current.toPath(), incoming.toPath()); + } + + private void loadServer() { + final File f = new File(SyncmaticaProtocol.getLitematicFolder(), "placements.json"); + if (f.exists() && f.isFile() && f.canRead()) { + JsonElement element = null; + try { + final JsonParser parser = new JsonParser(); + final FileReader reader = new FileReader(f); + + element = parser.parse(reader); + reader.close(); + + } catch (final Exception e) { + e.printStackTrace(); + } + if (element == null) { + return; + } + try { + final JsonObject obj = element.getAsJsonObject(); + if (obj == null || !obj.has(PLACEMENTS_JSON_KEY)) { + return; + } + final JsonArray arr = obj.getAsJsonArray(PLACEMENTS_JSON_KEY); + for (final JsonElement elem : arr) { + final ServerPlacement placement = ServerPlacement.fromJson(elem.getAsJsonObject()); + if (placement != null) { + schematics.put(placement.getId(), placement); + } + } + + } catch (final IllegalStateException | NullPointerException e) { + e.printStackTrace(); + } + } + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticaPayload.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticaPayload.java new file mode 100644 index 0000000..d161e73 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticaPayload.java @@ -0,0 +1,18 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import org.leavesmc.leaves.protocol.core.LeavesCustomPayload; + +public record SyncmaticaPayload(ResourceLocation packetType, FriendlyByteBuf data) implements LeavesCustomPayload { + + @ID + private static final ResourceLocation NETWORK_ID = ResourceLocation.tryBuild(SyncmaticaProtocol.PROTOCOL_ID, "main"); + + @Codec + private static final StreamCodec CODEC = StreamCodec.of( + (buf, payload) -> buf.writeResourceLocation(payload.packetType()).writeBytes(payload.data()), + buf -> new SyncmaticaPayload(buf.readResourceLocation(), new FriendlyByteBuf(buf.readBytes(buf.readableBytes()))) + ); +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticaProtocol.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticaProtocol.java new file mode 100644 index 0000000..fdd9550 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/SyncmaticaProtocol.java @@ -0,0 +1,127 @@ +package org.leavesmc.leaves.protocol.syncmatica; + +import org.bxteam.divinemc.config.DivineConfig; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.UUID; + +public class SyncmaticaProtocol { + public static final String PROTOCOL_ID = "syncmatica"; + public static final String PROTOCOL_VERSION = "leaves-syncmatica-1.1.0"; + private static final File litematicFolder = new File("." + File.separator + "syncmatics"); + private static final PlayerIdentifierProvider playerIdentifierProvider = new PlayerIdentifierProvider(); + private static final CommunicationManager communicationManager = new CommunicationManager(); + private static final FeatureSet featureSet = new FeatureSet(Arrays.asList(Feature.values())); + private static final SyncmaticManager syncmaticManager = new SyncmaticManager(); + private static final FileStorage fileStorage = new FileStorage(); + private static final int[] ILLEGAL_CHARS = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47, 34, 60, 62, 124}; + private static final String ILLEGAL_PATTERNS = "(^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$)|(^\\.\\.*$)"; + private static boolean loaded = false; + + public static File getLitematicFolder() { + return litematicFolder; + } + + public static PlayerIdentifierProvider getPlayerIdentifierProvider() { + return playerIdentifierProvider; + } + + public static CommunicationManager getCommunicationManager() { + return communicationManager; + } + + public static FeatureSet getFeatureSet() { + return featureSet; + } + + public static SyncmaticManager getSyncmaticManager() { + return syncmaticManager; + } + + public static FileStorage getFileStorage() { + return fileStorage; + } + + public static void init(boolean status) { + if (status && !loaded) { + litematicFolder.mkdirs(); + syncmaticManager.startup(); + loaded = true; + } else if (!status && loaded) { + syncmaticManager.updateServerPlacement(); + loaded = false; + } + } + + @NotNull + public static UUID createChecksum(final @NotNull InputStream fis) throws NoSuchAlgorithmException, IOException { + final byte[] buffer = new byte[4096]; + final MessageDigest messageDigest = MessageDigest.getInstance("MD5"); + int numRead; + + do { + numRead = fis.read(buffer); + if (numRead > 0) { + messageDigest.update(buffer, 0, numRead); + } + } while (numRead != -1); + + fis.close(); + return UUID.nameUUIDFromBytes(messageDigest.digest()); + } + + @NotNull + public static String sanitizeFileName(final @NotNull String badFileName) { + final StringBuilder sanitized = new StringBuilder(); + final int len = badFileName.codePointCount(0, badFileName.length()); + + for (int i = 0; i < len; i++) { + final int c = badFileName.codePointAt(i); + if (Arrays.binarySearch(ILLEGAL_CHARS, c) < 0) { + sanitized.appendCodePoint(c); + if (sanitized.length() == 255) { + break; + } + } + } + + return sanitized.toString().replaceAll(ILLEGAL_PATTERNS, "_"); + } + + public static boolean isOverQuota(int sent) { + return DivineConfig.NetworkCategory.protocolsSyncMaticaQuota && sent > DivineConfig.NetworkCategory.protocolsSyncMaticaQuotaLimit; + } + + public static void backupAndReplace(final Path backup, final Path current, final Path incoming) { + if (!Files.exists(incoming)) { + return; + } + if (overwrite(backup, current, 2) && !overwrite(current, incoming, 4)) { + overwrite(current, backup, 8); + } + } + + private static boolean overwrite(final Path backup, final Path current, final int tries) { + if (!Files.exists(current)) { + return true; + } + try { + Files.deleteIfExists(backup); + Files.move(current, backup); + } catch (final IOException exception) { + if (tries <= 0) { + return false; + } + return overwrite(backup, current, tries - 1); + } + return true; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/AbstractExchange.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/AbstractExchange.java new file mode 100644 index 0000000..aa40f0a --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/AbstractExchange.java @@ -0,0 +1,66 @@ +package org.leavesmc.leaves.protocol.syncmatica.exchange; + +import net.minecraft.network.FriendlyByteBuf; +import org.leavesmc.leaves.protocol.syncmatica.CommunicationManager; +import org.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; + +import java.util.UUID; + +public abstract class AbstractExchange implements Exchange { + + private final ExchangeTarget partner; + private boolean success = false; + private boolean finished = false; + + protected AbstractExchange(final ExchangeTarget partner) { + this.partner = partner; + } + + protected static boolean checkUUID(final FriendlyByteBuf sourceBuf, final UUID targetId) { + final int r = sourceBuf.readerIndex(); + final UUID sourceId = sourceBuf.readUUID(); + sourceBuf.readerIndex(r); + return sourceId.equals(targetId); + } + + @Override + public ExchangeTarget getPartner() { + return partner; + } + + @Override + public boolean isFinished() { + return finished; + } + + @Override + public boolean isSuccessful() { + return success; + } + + @Override + public void close(final boolean notifyPartner) { + finished = true; + success = false; + onClose(); + if (notifyPartner) { + sendCancelPacket(); + } + } + + public CommunicationManager getManager() { + return SyncmaticaProtocol.getCommunicationManager(); + } + + protected void sendCancelPacket() { + } + + protected void onClose() { + } + + protected void succeed() { + finished = true; + success = true; + onClose(); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/DownloadExchange.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/DownloadExchange.java new file mode 100644 index 0000000..3bf1c27 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/DownloadExchange.java @@ -0,0 +1,128 @@ +package org.leavesmc.leaves.protocol.syncmatica.exchange; + +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.syncmatica.CommunicationManager; +import org.leavesmc.leaves.protocol.syncmatica.MessageType; +import org.leavesmc.leaves.protocol.syncmatica.PacketType; +import org.leavesmc.leaves.protocol.syncmatica.ServerPlacement; +import org.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.UUID; + +public class DownloadExchange extends AbstractExchange { + + private final ServerPlacement toDownload; + private final OutputStream outputStream; + private final MessageDigest md5; + private final File downloadFile; + private int bytesSent; + + public DownloadExchange(final ServerPlacement syncmatic, final File downloadFile, final ExchangeTarget partner) throws IOException, NoSuchAlgorithmException { + super(partner); + this.downloadFile = downloadFile; + final OutputStream os = new FileOutputStream(downloadFile); + toDownload = syncmatic; + md5 = MessageDigest.getInstance("MD5"); + outputStream = new DigestOutputStream(os, md5); + } + + @Override + public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { + if (id.equals(PacketType.SEND_LITEMATIC.identifier) + || id.equals(PacketType.FINISHED_LITEMATIC.identifier) + || id.equals(PacketType.CANCEL_LITEMATIC.identifier)) { + return checkUUID(packetBuf, toDownload.getId()); + } + return false; + } + + @Override + public void handle(final @NotNull ResourceLocation id, final @NotNull FriendlyByteBuf packetBuf) { + packetBuf.readUUID(); + if (id.equals(PacketType.SEND_LITEMATIC.identifier)) { + final int size = packetBuf.readInt(); + bytesSent += size; + if (SyncmaticaProtocol.isOverQuota(bytesSent)) { + close(true); + SyncmaticaProtocol.getCommunicationManager().sendMessage( + getPartner(), + MessageType.ERROR, + "syncmatica.error.cancelled_transmit_exceed_quota" + ); + return; + } + try { + packetBuf.readBytes(outputStream, size); + } catch (final IOException e) { + close(true); + e.printStackTrace(); + return; + } + final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); + FriendlyByteBuf.writeUUID(toDownload.getId()); + getPartner().sendPacket(PacketType.RECEIVED_LITEMATIC.identifier, FriendlyByteBuf); + return; + } + if (id.equals(PacketType.FINISHED_LITEMATIC.identifier)) { + try { + outputStream.flush(); + } catch (final IOException e) { + close(false); + e.printStackTrace(); + return; + } + final UUID downloadHash = UUID.nameUUIDFromBytes(md5.digest()); + if (downloadHash.equals(toDownload.getHash())) { + succeed(); + } else { + close(false); + } + return; + } + if (id.equals(PacketType.CANCEL_LITEMATIC.identifier)) { + close(false); + } + } + + @Override + public void init() { + final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); + FriendlyByteBuf.writeUUID(toDownload.getId()); + getPartner().sendPacket(PacketType.REQUEST_LITEMATIC.identifier, FriendlyByteBuf); + } + + @Override + protected void onClose() { + getManager(); + CommunicationManager.setDownloadState(toDownload, false); + try { + outputStream.close(); + } catch (final IOException e) { + e.printStackTrace(); + } + if (!isSuccessful() && downloadFile.exists()) { + downloadFile.delete(); + } + } + + @Override + protected void sendCancelPacket() { + final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); + FriendlyByteBuf.writeUUID(toDownload.getId()); + getPartner().sendPacket(PacketType.CANCEL_LITEMATIC.identifier, FriendlyByteBuf); + } + + public ServerPlacement getPlacement() { + return toDownload; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/Exchange.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/Exchange.java new file mode 100644 index 0000000..0f45ef7 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/Exchange.java @@ -0,0 +1,20 @@ +package org.leavesmc.leaves.protocol.syncmatica.exchange; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; + +public interface Exchange { + ExchangeTarget getPartner(); + + boolean checkPacket(ResourceLocation id, FriendlyByteBuf packetBuf); + + void handle(ResourceLocation id, FriendlyByteBuf packetBuf); + + boolean isFinished(); + + boolean isSuccessful(); + + void close(boolean notifyPartner); + + void init(); +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/ExchangeTarget.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/ExchangeTarget.java new file mode 100644 index 0000000..b0da7ab --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/ExchangeTarget.java @@ -0,0 +1,39 @@ +package org.leavesmc.leaves.protocol.syncmatica.exchange; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import org.leavesmc.leaves.protocol.core.ProtocolUtils; +import org.leavesmc.leaves.protocol.syncmatica.FeatureSet; +import org.leavesmc.leaves.protocol.syncmatica.SyncmaticaPayload; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class ExchangeTarget { + + private final List ongoingExchanges = new ArrayList<>(); + private final ServerGamePacketListenerImpl client; + private FeatureSet features; + + public ExchangeTarget(final ServerGamePacketListenerImpl client) { + this.client = client; + } + + public void sendPacket(final ResourceLocation id, final FriendlyByteBuf packetBuf) { + ProtocolUtils.sendPayloadPacket(client.player, new SyncmaticaPayload(id, packetBuf)); + } + + public FeatureSet getFeatureSet() { + return features; + } + + public void setFeatureSet(final FeatureSet f) { + features = f; + } + + public Collection getExchanges() { + return ongoingExchanges; + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/FeatureExchange.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/FeatureExchange.java new file mode 100644 index 0000000..45fc019 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/FeatureExchange.java @@ -0,0 +1,48 @@ +package org.leavesmc.leaves.protocol.syncmatica.exchange; + +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.syncmatica.FeatureSet; +import org.leavesmc.leaves.protocol.syncmatica.PacketType; +import org.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; + +public abstract class FeatureExchange extends AbstractExchange { + + protected FeatureExchange(final ExchangeTarget partner) { + super(partner); + } + + @Override + public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { + return id.equals(PacketType.FEATURE_REQUEST.identifier) + || id.equals(PacketType.FEATURE.identifier); + } + + @Override + public void handle(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { + if (id.equals(PacketType.FEATURE_REQUEST.identifier)) { + sendFeatures(); + } else if (id.equals(PacketType.FEATURE.identifier)) { + final FeatureSet fs = FeatureSet.fromString(packetBuf.readUtf(32767)); + getPartner().setFeatureSet(fs); + onFeatureSetReceive(); + } + } + + protected void onFeatureSetReceive() { + succeed(); + } + + public void requestFeatureSet() { + getPartner().sendPacket(PacketType.FEATURE_REQUEST.identifier, new FriendlyByteBuf(Unpooled.buffer())); + } + + private void sendFeatures() { + final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + final FeatureSet fs = SyncmaticaProtocol.getFeatureSet(); + buf.writeUtf(fs.toString(), 32767); + getPartner().sendPacket(PacketType.FEATURE.identifier, buf); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/ModifyExchangeServer.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/ModifyExchangeServer.java new file mode 100644 index 0000000..f7f423c --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/ModifyExchangeServer.java @@ -0,0 +1,82 @@ +package org.leavesmc.leaves.protocol.syncmatica.exchange; + +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.syncmatica.CommunicationManager; +import org.leavesmc.leaves.protocol.syncmatica.PacketType; +import org.leavesmc.leaves.protocol.syncmatica.PlayerIdentifier; +import org.leavesmc.leaves.protocol.syncmatica.ServerPlacement; +import org.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; + +import java.util.UUID; + +public class ModifyExchangeServer extends AbstractExchange { + + private final ServerPlacement placement; + UUID placementId; + + public ModifyExchangeServer(final UUID placeId, final ExchangeTarget partner) { + super(partner); + placementId = placeId; + placement = SyncmaticaProtocol.getSyncmaticManager().getPlacement(placementId); + } + + @Override + public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { + return id.equals(PacketType.MODIFY_FINISH.identifier) && checkUUID(packetBuf, placement.getId()); + } + + @Override + public void handle(final @NotNull ResourceLocation id, final @NotNull FriendlyByteBuf packetBuf) { + packetBuf.readUUID(); + if (id.equals(PacketType.MODIFY_FINISH.identifier)) { + CommunicationManager.receivePositionData(placement, packetBuf, getPartner()); + final PlayerIdentifier identifier = SyncmaticaProtocol.getPlayerIdentifierProvider().createOrGet( + getPartner() + ); + placement.setLastModifiedBy(identifier); + SyncmaticaProtocol.getSyncmaticManager().updateServerPlacement(); + succeed(); + } + } + + @Override + public void init() { + if (getPlacement() == null || CommunicationManager.getModifier(placement) != null) { + close(true); + } else { + if (SyncmaticaProtocol.getPlayerIdentifierProvider().createOrGet(this.getPartner()).uuid.equals(placement.getOwner().uuid)) { + accept(); + } else { + close(true); + } + } + } + + private void accept() { + final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeUUID(placement.getId()); + getPartner().sendPacket(PacketType.MODIFY_REQUEST_ACCEPT.identifier, buf); + CommunicationManager.setModifier(placement, this); + } + + @Override + protected void sendCancelPacket() { + final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeUUID(placementId); + getPartner().sendPacket(PacketType.MODIFY_REQUEST_DENY.identifier, buf); + } + + public ServerPlacement getPlacement() { + return placement; + } + + @Override + protected void onClose() { + if (CommunicationManager.getModifier(placement) == this) { + CommunicationManager.setModifier(placement, null); + } + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/UploadExchange.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/UploadExchange.java new file mode 100644 index 0000000..065a399 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/UploadExchange.java @@ -0,0 +1,101 @@ +package org.leavesmc.leaves.protocol.syncmatica.exchange; + +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.syncmatica.PacketType; +import org.leavesmc.leaves.protocol.syncmatica.ServerPlacement; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +public class UploadExchange extends AbstractExchange { + + private static final int BUFFER_SIZE = 16384; + + private final ServerPlacement toUpload; + private final InputStream inputStream; + private final byte[] buffer = new byte[BUFFER_SIZE]; + + public UploadExchange(final ServerPlacement syncmatic, final File uploadFile, final ExchangeTarget partner) throws FileNotFoundException { + super(partner); + toUpload = syncmatic; + inputStream = new FileInputStream(uploadFile); + } + + @Override + public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { + if (id.equals(PacketType.RECEIVED_LITEMATIC.identifier) + || id.equals(PacketType.CANCEL_LITEMATIC.identifier)) { + return checkUUID(packetBuf, toUpload.getId()); + } + return false; + } + + @Override + public void handle(final @NotNull ResourceLocation id, final @NotNull FriendlyByteBuf packetBuf) { + packetBuf.readUUID(); + if (id.equals(PacketType.RECEIVED_LITEMATIC.identifier)) { + send(); + } + if (id.equals(PacketType.CANCEL_LITEMATIC.identifier)) { + close(false); + } + } + + private void send() { + final int bytesRead; + try { + bytesRead = inputStream.read(buffer); + } catch (final IOException e) { + close(true); + e.printStackTrace(); + return; + } + if (bytesRead == -1) { + sendFinish(); + } else { + sendData(bytesRead); + } + } + + private void sendData(final int bytesRead) { + final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); + FriendlyByteBuf.writeUUID(toUpload.getId()); + FriendlyByteBuf.writeInt(bytesRead); + FriendlyByteBuf.writeBytes(buffer, 0, bytesRead); + getPartner().sendPacket(PacketType.SEND_LITEMATIC.identifier, FriendlyByteBuf); + } + + private void sendFinish() { + final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); + FriendlyByteBuf.writeUUID(toUpload.getId()); + getPartner().sendPacket(PacketType.FINISHED_LITEMATIC.identifier, FriendlyByteBuf); + succeed(); + } + + @Override + public void init() { + send(); + } + + @Override + protected void onClose() { + try { + inputStream.close(); + } catch (final IOException e) { + e.printStackTrace(); + } + } + + @Override + protected void sendCancelPacket() { + final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); + FriendlyByteBuf.writeUUID(toUpload.getId()); + getPartner().sendPacket(PacketType.CANCEL_LITEMATIC.identifier, FriendlyByteBuf); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/VersionHandshakeServer.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/VersionHandshakeServer.java new file mode 100644 index 0000000..cb7aed6 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/syncmatica/exchange/VersionHandshakeServer.java @@ -0,0 +1,66 @@ +package org.leavesmc.leaves.protocol.syncmatica.exchange; + +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.protocol.syncmatica.CommunicationManager; +import org.leavesmc.leaves.protocol.syncmatica.FeatureSet; +import org.leavesmc.leaves.protocol.syncmatica.PacketType; +import org.leavesmc.leaves.protocol.syncmatica.ServerPlacement; +import org.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; + +import java.util.Collection; + +public class VersionHandshakeServer extends FeatureExchange { + + public VersionHandshakeServer(final ExchangeTarget partner) { + super(partner); + } + + @Override + public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { + return id.equals(PacketType.REGISTER_VERSION.identifier) + || super.checkPacket(id, packetBuf); + } + + @Override + public void handle(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { + if (id.equals(PacketType.REGISTER_VERSION.identifier)) { + String partnerVersion = packetBuf.readUtf(); + if (partnerVersion.equals("0.0.1")) { + close(false); + return; + } + final FeatureSet fs = FeatureSet.fromVersionString(partnerVersion); + if (fs == null) { + requestFeatureSet(); + } else { + getPartner().setFeatureSet(fs); + onFeatureSetReceive(); + } + } else { + super.handle(id, packetBuf); + } + + } + + @Override + public void onFeatureSetReceive() { + final FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); + final Collection l = SyncmaticaProtocol.getSyncmaticManager().getAll(); + newBuf.writeInt(l.size()); + for (final ServerPlacement p : l) { + CommunicationManager.putMetaData(p, newBuf, getPartner()); + } + getPartner().sendPacket(PacketType.CONFIRM_USER.identifier, newBuf); + succeed(); + } + + @Override + public void init() { + final FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); + newBuf.writeUtf(SyncmaticaProtocol.PROTOCOL_VERSION); + getPartner().sendPacket(PacketType.REGISTER_VERSION.identifier, newBuf); + } +} diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/util/NbtUtils.java b/divinemc-server/src/main/java/org/leavesmc/leaves/util/NbtUtils.java new file mode 100644 index 0000000..3c75d50 --- /dev/null +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/util/NbtUtils.java @@ -0,0 +1,75 @@ +package org.leavesmc.leaves.util; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class NbtUtils { + + public static void writeBlockPosToTag(Vec3i pos, CompoundTag tag) { + tag.putInt("x", pos.getX()); + tag.putInt("y", pos.getY()); + tag.putInt("z", pos.getZ()); + } + + @Nullable + public static BlockPos readBlockPos(@Nullable CompoundTag tag) { + if (tag != null && tag.contains("x") && tag.contains("y") && tag.contains("z")) { + return new BlockPos(tag.getIntOr("x", 0), tag.getIntOr("y", 0), tag.getIntOr("z", 0)); + } + + return null; + } + + public static void writeEntityPositionToTag(Vec3 pos, CompoundTag tag) { + ListTag posList = new ListTag(); + + posList.add(DoubleTag.valueOf(pos.x)); + posList.add(DoubleTag.valueOf(pos.y)); + posList.add(DoubleTag.valueOf(pos.z)); + tag.put("Pos", posList); + } + + @Nullable + public static Vec3 readVec3(@Nullable CompoundTag tag) { + if (tag != null && tag.contains("dx") && tag.contains("dy") && tag.contains("dz")) { + return new Vec3(tag.getDoubleOr("dx", 0.0), tag.getDoubleOr("dy", 0.0), tag.getDoubleOr("dz", 0.0)); + } + return null; + } + + @Nullable + public static Vec3 readEntityPositionFromTag(@Nullable CompoundTag tag) { + if (tag == null || !tag.contains("Pos")) { + return null; + } + ListTag tagList = tag.getListOrEmpty("Pos"); + if (tagList.size() != 3) { + return null; + } + return new Vec3(tagList.getDoubleOr(0, 0.0), tagList.getDoubleOr(1, 0.0), tagList.getDoubleOr(2, 0.0)); + } + + @Nullable + public static Vec3i readVec3iFromTag(@Nullable CompoundTag tag) { + if (tag != null && tag.contains("x") && tag.contains("y") && tag.contains("z")) { + return new Vec3i(tag.getIntOr("x", 0), tag.getIntOr("y", 0), tag.getIntOr("z", 0)); + } + return null; + } + + public static BlockPos readBlockPosFromArrayTag(@NotNull CompoundTag tag, String tagName) { + if (tag.contains(tagName)) { + int[] pos = tag.getIntArray(tagName).orElse(new int[0]); + if (pos.length == 3) { + return new BlockPos(pos[0], pos[1], pos[2]); + } + } + return null; + } +} From 30fdc59f45bd43d22dff5079cb80e82568efc41a Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 11 Jul 2025 20:24:44 +0300 Subject: [PATCH 30/67] Updated Upstream (Purpur) Upstream has released updates that appear to apply and compile correctly Purpur Changes: PurpurMC/Purpur@7dbe4153 Add support for "/chase", a disabled Minecraft command. (#1690) --- .../minecraft-patches/features/0001-Rebrand.patch | 8 ++++---- .../features/0003-Completely-remove-Mojang-profiler.patch | 8 ++++---- .../minecraft-patches/features/0066-Virtual-Threads.patch | 4 ++-- gradle.properties | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index 6aa2336..b5e2000 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -18,10 +18,10 @@ index 394443d00e661715439be1e56dddc129947699a4..480ad57a6b7b74e6b83e9c6ceb69ea1f public CrashReport(String title, Throwable exception) { io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java -index bc3209d3cbe971af74b7856caa6300b59b0bb6bc..9a19c36074b9d8eb291b15b080687e47bcd5d007 100644 +index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..a476b53e0c5b18d9b0abceb4ffeb5ab4c5d7d6d9 100644 --- a/net/minecraft/server/Main.java +++ b/net/minecraft/server/Main.java -@@ -124,7 +124,6 @@ public class Main { +@@ -125,7 +125,6 @@ public class Main { dedicatedServerSettings.forceSave(); RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression); Path path2 = Paths.get("eula.txt"); @@ -29,7 +29,7 @@ index bc3209d3cbe971af74b7856caa6300b59b0bb6bc..9a19c36074b9d8eb291b15b080687e47 // Paper start - load config files early for access below if needed 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")); -@@ -147,19 +146,6 @@ public class Main { +@@ -148,19 +147,6 @@ public class Main { return; } @@ -50,7 +50,7 @@ index bc3209d3cbe971af74b7856caa6300b59b0bb6bc..9a19c36074b9d8eb291b15b080687e47 String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck(); if (awtException != null) { diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 306230339574bc35a309877033fa6012e4596f08..1362f3d2ef75d8b18ac2142194ff5b3f2104ac1e 100644 +index 1c064e1d2edcda5d0b10fb3cc3417937ac0b3835..3b6d2cf670caefd42536de896d3e13c96ebf87b1 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -1176,6 +1176,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop contextChain = finishParsing(parseResults, command, commandSourceStack); try { -@@ -395,8 +391,6 @@ public class Commands { +@@ -401,8 +397,6 @@ public class Commands { commandSourceStack.sendFailure(Component.literal(Util.describeError(var12))); LOGGER.error("'/{}' threw an exception", command, var12); } @@ -49,7 +49,7 @@ index c638d30ba12bde2ae9d55b1c579129d40bcc8b1e..25aeb8628a79b62b70dbbb1299d4b4e5 } } -@@ -453,7 +447,7 @@ public class Commands { +@@ -459,7 +453,7 @@ public class Commands { int max = Math.max(1, server.getGameRules().getInt(GameRules.RULE_MAX_COMMAND_CHAIN_LENGTH)); int _int = server.getGameRules().getInt(GameRules.RULE_MAX_COMMAND_FORK_COUNT); diff --git a/divinemc-server/minecraft-patches/features/0066-Virtual-Threads.patch b/divinemc-server/minecraft-patches/features/0066-Virtual-Threads.patch index 7275e8c..8ccbf4c 100644 --- a/divinemc-server/minecraft-patches/features/0066-Virtual-Threads.patch +++ b/divinemc-server/minecraft-patches/features/0066-Virtual-Threads.patch @@ -23,10 +23,10 @@ index 138a58c5e5698b926b01e0170733dc3dbc5589ec..bfe52d5a93a35cafcb8965482b1c1d6c private final AtomicInteger count = new AtomicInteger(); diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java -index 25aeb8628a79b62b70dbbb1299d4b4e52986b96d..62aeee570d10ab4ac5c21c88987ba6d2c75ae2b8 100644 +index 758ce439d2e10e6ef42a58d147a77093667e0acd..de622982f864d96a5b76efcd69f1836ef541317b 100644 --- a/net/minecraft/commands/Commands.java +++ b/net/minecraft/commands/Commands.java -@@ -475,7 +475,7 @@ public class Commands { +@@ -481,7 +481,7 @@ public class Commands { } // Fixed pool, but with discard policy diff --git a/gradle.properties b/gradle.properties index 2210a95..9b09d8b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group = org.bxteam.divinemc version=1.21.7-R0.1-SNAPSHOT mcVersion=1.21.7 -purpurRef=4d5a8e6ebd004ca76663071c77200b80f35406fd +purpurRef=7dbe41536b8509e1867132778950c994a3e81040 experimental=false org.gradle.configuration-cache=true From 42b0a101ec76c29d71b39447c7385af21ad665a4 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 11 Jul 2025 20:33:08 +0300 Subject: [PATCH 31/67] update purpur rebrand settings --- .../features/0001-Rebrand.patch | 8 +++--- .../0001-Update-Purpur-rebrand-settings.patch | 27 +++++++++++++++++++ ...02-Add-missing-purpur-config-options.patch | 8 +++--- ...Optimize-default-values-for-configs.patch} | 8 +++--- ...gurable-movement-speed-for-entities.patch} | 0 ...> 0005-MSPT-Tracking-for-each-world.patch} | 0 6 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 divinemc-server/purpur-patches/features/0001-Update-Purpur-rebrand-settings.patch rename divinemc-server/purpur-patches/features/{0001-Optimize-default-values-for-configs.patch => 0003-Optimize-default-values-for-configs.patch} (86%) rename divinemc-server/purpur-patches/features/{0003-Configurable-movement-speed-for-entities.patch => 0004-Configurable-movement-speed-for-entities.patch} (100%) rename divinemc-server/purpur-patches/features/{0004-MSPT-Tracking-for-each-world.patch => 0005-MSPT-Tracking-for-each-world.patch} (100%) diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index b5e2000..1b985a5 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -62,7 +62,7 @@ index 1c064e1d2edcda5d0b10fb3cc3417937ac0b3835..3b6d2cf670caefd42536de896d3e13c9 throw new IllegalStateException("Failed to initialize server"); } diff --git a/net/minecraft/server/gui/MinecraftServerGui.java b/net/minecraft/server/gui/MinecraftServerGui.java -index 614c7d9f673c926562acc8fa3b3788623900db41..33456c7c106abbddf743e1203a6e8122cf10b797 100644 +index 614c7d9f673c926562acc8fa3b3788623900db41..937469a134e721c47e235a34acc565f12adf85ff 100644 --- a/net/minecraft/server/gui/MinecraftServerGui.java +++ b/net/minecraft/server/gui/MinecraftServerGui.java @@ -51,7 +51,7 @@ public class MinecraftServerGui extends JComponent { @@ -70,7 +70,7 @@ index 614c7d9f673c926562acc8fa3b3788623900db41..33456c7c106abbddf743e1203a6e8122 } - final JFrame jFrame = new JFrame("Purpur Minecraft server"); // Purpur - Improve GUI -+ final JFrame jFrame = new JFrame("DivineMC Minecraft server"); // Purpur - Improve GUI // DivineMC - Rebrand ++ final JFrame jFrame = new JFrame(org.purpurmc.purpur.PurpurConfig.serverGUIName); // Purpur - Improve GUI // DivineMC - Update Purpur rebrand settings final MinecraftServerGui minecraftServerGui = new MinecraftServerGui(server); jFrame.setDefaultCloseOperation(2); jFrame.add(minecraftServerGui); @@ -79,7 +79,7 @@ index 614c7d9f673c926562acc8fa3b3788623900db41..33456c7c106abbddf743e1203a6e8122 jFrame.setVisible(true); // Paper start - Improve ServerGUI - jFrame.setName("Purpur Minecraft server"); // Purpur - Improve GUI -+ jFrame.setName("DivineMC Minecraft server"); // Purpur - Improve GUI // DivineMC - Rebrand ++ jFrame.setName(org.purpurmc.purpur.PurpurConfig.serverGUIName); // Purpur - Improve GUI // DivineMC - Update Purpur rebrand settings try { jFrame.setIconImage(javax.imageio.ImageIO.read(java.util.Objects.requireNonNull(MinecraftServerGui.class.getClassLoader().getResourceAsStream("logo.png")))); } catch (java.io.IOException ignore) { @@ -88,7 +88,7 @@ index 614c7d9f673c926562acc8fa3b3788623900db41..33456c7c106abbddf743e1203a6e8122 public void windowClosing(WindowEvent event) { if (!minecraftServerGui.isClosing.getAndSet(true)) { - jFrame.setTitle("Purpur Minecraft server - shutting down!"); // Purpur - Improve GUI -+ jFrame.setTitle("DivineMC Minecraft server - shutting down!"); // Purpur - Improve GUI // DivineMC - Rebrand ++ jFrame.setTitle(org.purpurmc.purpur.PurpurConfig.serverGUIName + " - shutting down!"); // Purpur - Improve GUI // DivineMC - Update Purpur rebrand settings server.halt(true); minecraftServerGui.runFinalizers(); } diff --git a/divinemc-server/purpur-patches/features/0001-Update-Purpur-rebrand-settings.patch b/divinemc-server/purpur-patches/features/0001-Update-Purpur-rebrand-settings.patch new file mode 100644 index 0000000..fa36843 --- /dev/null +++ b/divinemc-server/purpur-patches/features/0001-Update-Purpur-rebrand-settings.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Fri, 11 Jul 2025 20:26:35 +0300 +Subject: [PATCH] Update Purpur rebrand settings + + +diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java +index 31bf765d2dfa75d854f7f8e55bab7792ace843ab..d923efc61592c430e3945fd9c38e558f9e85710e 100644 +--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java ++++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java +@@ -230,10 +230,14 @@ public class PurpurConfig { + deathMessageOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.death.only-broadcast-to-affected-player", deathMessageOnlyBroadcastToAffectedPlayer); + } + ++ // DivineMC start - Update Purpur rebrand settings + public static String serverModName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); +- private static void serverModName() { +- serverModName = getString("settings.server-mod-name", serverModName); ++ public static String serverGUIName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName() + " Console"; ++ private static void serverName() { ++ serverModName = getString("settings.rebrand.server-mod-name", serverModName); ++ serverGUIName = getString("settings.rebrand.server-gui-name", serverGUIName); + } ++ // DivineMC end - Update Purpur rebrand settings + + public static double laggingThreshold = 19.0D; + private static void tickLoopSettings() { diff --git a/divinemc-server/purpur-patches/features/0002-Add-missing-purpur-config-options.patch b/divinemc-server/purpur-patches/features/0002-Add-missing-purpur-config-options.patch index cdc9479..000e5d5 100644 --- a/divinemc-server/purpur-patches/features/0002-Add-missing-purpur-config-options.patch +++ b/divinemc-server/purpur-patches/features/0002-Add-missing-purpur-config-options.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add missing purpur config options diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 72fcad4a0b5857551221741b9c73fa75596e6981..374af5eb6b55c731535be4e8c242ffc3a6e4647a 100644 +index d923efc61592c430e3945fd9c38e558f9e85710e..01094a003a96118bdc1fdc7a665cce89a2f54dfb 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -327,6 +327,7 @@ public class PurpurConfig { +@@ -331,6 +331,7 @@ public class PurpurConfig { } public static int barrelRows = 3; @@ -16,7 +16,7 @@ index 72fcad4a0b5857551221741b9c73fa75596e6981..374af5eb6b55c731535be4e8c242ffc3 public static boolean enderChestSixRows = false; public static boolean enderChestPermissionRows = false; public static boolean cryingObsidianValidForPortalFrame = false; -@@ -370,6 +371,7 @@ public class PurpurConfig { +@@ -374,6 +375,7 @@ public class PurpurConfig { case 1 -> 9; default -> 27; }); @@ -25,7 +25,7 @@ index 72fcad4a0b5857551221741b9c73fa75596e6981..374af5eb6b55c731535be4e8c242ffc3 org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3346e45393776c9ed120c2be70e24a9289f74fd3..225d3fab20ef461c87b260b2674229806649bc56 100644 +index a03e166b490952534e8050654c1afa975795f731..1b17643fffecd7af6ec60ef8a24eac85ddd7b80d 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java @@ -1184,12 +1184,20 @@ public class PurpurWorldConfig { diff --git a/divinemc-server/purpur-patches/features/0001-Optimize-default-values-for-configs.patch b/divinemc-server/purpur-patches/features/0003-Optimize-default-values-for-configs.patch similarity index 86% rename from divinemc-server/purpur-patches/features/0001-Optimize-default-values-for-configs.patch rename to divinemc-server/purpur-patches/features/0003-Optimize-default-values-for-configs.patch index 98e9811..cd991c3 100644 --- a/divinemc-server/purpur-patches/features/0001-Optimize-default-values-for-configs.patch +++ b/divinemc-server/purpur-patches/features/0003-Optimize-default-values-for-configs.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimize default values for configs diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index e5bf7ea47143cf3f8d4c0f1840698068bb70cbf8..72fcad4a0b5857551221741b9c73fa75596e6981 100644 +index 01094a003a96118bdc1fdc7a665cce89a2f54dfb..34edbde5707326ac6e364a24c9640ac1263c85b0 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -240,7 +240,7 @@ public class PurpurConfig { +@@ -244,7 +244,7 @@ public class PurpurConfig { laggingThreshold = getDouble("settings.lagging-threshold", laggingThreshold); } @@ -18,10 +18,10 @@ index e5bf7ea47143cf3f8d4c0f1840698068bb70cbf8..72fcad4a0b5857551221741b9c73fa75 useAlternateKeepAlive = getBoolean("settings.use-alternate-keepalive", useAlternateKeepAlive); } diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index a03e166b490952534e8050654c1afa975795f731..3346e45393776c9ed120c2be70e24a9289f74fd3 100644 +index 1b17643fffecd7af6ec60ef8a24eac85ddd7b80d..225d3fab20ef461c87b260b2674229806649bc56 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -3164,8 +3164,8 @@ public class PurpurWorldConfig { +@@ -3208,8 +3208,8 @@ public class PurpurWorldConfig { public boolean villagerDisplayTradeItem = true; public int villagerSpawnIronGolemRadius = 0; public int villagerSpawnIronGolemLimit = 0; diff --git a/divinemc-server/purpur-patches/features/0003-Configurable-movement-speed-for-entities.patch b/divinemc-server/purpur-patches/features/0004-Configurable-movement-speed-for-entities.patch similarity index 100% rename from divinemc-server/purpur-patches/features/0003-Configurable-movement-speed-for-entities.patch rename to divinemc-server/purpur-patches/features/0004-Configurable-movement-speed-for-entities.patch diff --git a/divinemc-server/purpur-patches/features/0004-MSPT-Tracking-for-each-world.patch b/divinemc-server/purpur-patches/features/0005-MSPT-Tracking-for-each-world.patch similarity index 100% rename from divinemc-server/purpur-patches/features/0004-MSPT-Tracking-for-each-world.patch rename to divinemc-server/purpur-patches/features/0005-MSPT-Tracking-for-each-world.patch From a19a224b303c6921726d484cf4afae0a60724d36 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 11 Jul 2025 20:42:02 +0300 Subject: [PATCH 32/67] Optimise non-flush packet sending --- ...PR-Optimise-non-flush-packet-sending.patch | 60 +++++++++++++++++++ .../bxteam/divinemc/config/DivineConfig.java | 5 ++ 2 files changed, 65 insertions(+) create mode 100644 divinemc-server/minecraft-patches/features/0095-Paper-PR-Optimise-non-flush-packet-sending.patch diff --git a/divinemc-server/minecraft-patches/features/0095-Paper-PR-Optimise-non-flush-packet-sending.patch b/divinemc-server/minecraft-patches/features/0095-Paper-PR-Optimise-non-flush-packet-sending.patch new file mode 100644 index 0000000..ef4f93b --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0095-Paper-PR-Optimise-non-flush-packet-sending.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Fri, 11 Jul 2025 20:39:54 +0300 +Subject: [PATCH] Paper PR: Optimise non-flush packet sending + +Original project: https://github.com/PaperMC/Paper +Original license: GPLv3 +Paper pull request: https://github.com/PaperMC/Paper/pull/10172 + +Places like entity tracking make heavy use of packet sending, +and internally netty will use some very expensive thread wakeup +calls when scheduling. + +Thanks to various hacks in ProtocolLib as well as other +plugins, we cannot simply use a queue of packets to group +send on execute. We have to call execute for each packet. + +Tux's suggestion here is exactly what was needed - tag +the Runnable indicating it should not make a wakeup call. + +Big thanks to Tux for making this possible as I had given +up on this optimisation before he came along. + +Locally this patch drops the entity tracker tick by a full 1.5x. + +diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java +index 4ab30d291de7db5ad7d5684662f41348270802b9..8bb7d9f2bce06880164f0ae36e1674e9dc380809 100644 +--- a/net/minecraft/network/Connection.java ++++ b/net/minecraft/network/Connection.java +@@ -149,6 +149,7 @@ public class Connection extends SimpleChannelInboundHandler> { + // Paper start - Optimize network + public boolean isPending = true; + public boolean queueImmunity; ++ private io.netty.channel.SingleThreadEventLoop eventLoop; // Paper - Optimise non-flush packet sending + // Paper end - Optimize network + + public Connection(PacketFlow receiving) { +@@ -159,6 +160,7 @@ public class Connection extends SimpleChannelInboundHandler> { + public void channelActive(ChannelHandlerContext context) throws Exception { + super.channelActive(context); + this.channel = context.channel(); ++ this.eventLoop = (io.netty.channel.SingleThreadEventLoop) this.channel.eventLoop(); // Paper - Optimise non-flush packet sending + this.address = this.channel.remoteAddress(); + this.preparing = false; // Spigot + if (this.delayedDisconnect != null) { +@@ -473,7 +475,13 @@ public class Connection extends SimpleChannelInboundHandler> { + if (this.channel.eventLoop().inEventLoop()) { + this.doSendPacket(packet, channelFutureListener, flag); + } else { +- this.channel.eventLoop().execute(() -> this.doSendPacket(packet, channelFutureListener, flag)); ++ // Paper start - Optimise non-flush packet sending ++ if (!flag && org.bxteam.divinemc.config.DivineConfig.NetworkCategory.optimizeNonFlushPacketSending) { ++ this.eventLoop.lazyExecute(() -> this.doSendPacket(packet, channelFutureListener, flag)); ++ } else { ++ this.channel.eventLoop().execute(() -> this.doSendPacket(packet, channelFutureListener, flag)); ++ } ++ // Paper end - Optimise non-flush packet sending + } + } + diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 72b96ee..d0787f3 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -676,6 +676,7 @@ public class DivineConfig { public static class NetworkCategory { // General network settings + public static boolean optimizeNonFlushPacketSending = false; public static boolean disableDisconnectSpam = false; public static boolean dontRespondPingBeforeStart = true; public static boolean playerProfileResultCachingEnabled = true; @@ -706,6 +707,10 @@ public class DivineConfig { } private static void networkSettings() { + optimizeNonFlushPacketSending = getBoolean(ConfigCategory.NETWORK.key("general.optimize-non-flush-packet-sending"), optimizeNonFlushPacketSending, + "Optimizes non-flush packet sending by using Netty's lazyExecute method to avoid expensive thread wakeup calls when scheduling packet operations.", + "", + "NOTE: This option is NOT compatible with ProtocolLib and may cause issues with other plugins that modify packet handling!"); disableDisconnectSpam = getBoolean(ConfigCategory.NETWORK.key("general.disable-disconnect-spam"), disableDisconnectSpam, "Prevents players being disconnected by 'disconnect.spam' when sending too many chat packets"); dontRespondPingBeforeStart = getBoolean(ConfigCategory.NETWORK.key("general.dont-respond-ping-before-start"), dontRespondPingBeforeStart, From ee4c61957b1fc6bee141c2a45abc1b7d702dfbea Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 11 Jul 2025 21:56:07 +0300 Subject: [PATCH 33/67] remove debug logs from leaves protocol manager --- .../protocol/core/LeavesProtocolManager.java | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java index ab74a47..1609446 100644 --- a/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java +++ b/divinemc-server/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java @@ -213,49 +213,6 @@ public class LeavesProtocolManager { } ID2CODEC.put(idInfo.getValue(), codec); } - // Log all found instances - LOGGER.info("Protocol initialization complete. Found instances:"); - LOGGER.info(" Payload receivers: " + PAYLOAD_RECEIVERS.size()); - PAYLOAD_RECEIVERS.forEach((clazz, holder) -> - LOGGER.info(" " + clazz.getSimpleName() + " -> " + holder.getClass().getSimpleName())); - - LOGGER.info(" IDs: " + IDS.size()); - IDS.forEach((clazz, id) -> - LOGGER.info(" " + clazz.getSimpleName() + " -> " + id)); - - LOGGER.info(" Codecs: " + CODECS.size()); - CODECS.forEach((clazz, codec) -> - LOGGER.info(" " + clazz.getSimpleName() + " -> " + codec.getClass().getSimpleName())); - - LOGGER.info(" Strict bytebuf receivers: " + STRICT_BYTEBUF_RECEIVERS.size()); - STRICT_BYTEBUF_RECEIVERS.forEach((key, holder) -> - LOGGER.info(" " + key + " -> " + holder.getClass().getSimpleName())); - - LOGGER.info(" Namespaced bytebuf receivers: " + NAMESPACED_BYTEBUF_RECEIVERS.size()); - NAMESPACED_BYTEBUF_RECEIVERS.forEach((key, holder) -> - LOGGER.info(" " + key + " -> " + holder.getClass().getSimpleName())); - - LOGGER.info(" Generic bytebuf receivers: " + GENERIC_BYTEBUF_RECEIVERS.size()); - GENERIC_BYTEBUF_RECEIVERS.forEach(holder -> - LOGGER.info(" " + holder.getClass().getSimpleName())); - - LOGGER.info(" Tickers: " + TICKERS.size()); - LOGGER.info(" Player join handlers: " + PLAYER_JOIN.size()); - LOGGER.info(" Player leave handlers: " + PLAYER_LEAVE.size()); - LOGGER.info(" Server reload handlers: " + RELOAD_SERVER.size()); - LOGGER.info(" DataPack reload handlers: " + RELOAD_DATAPACK.size()); - - LOGGER.info(" Strict minecraft register: " + STRICT_MINECRAFT_REGISTER.size()); - STRICT_MINECRAFT_REGISTER.forEach((key, holder) -> - LOGGER.info(" " + key + " -> " + holder.getClass().getSimpleName())); - - LOGGER.info(" Namespaced minecraft register: " + NAMESPACED_MINECRAFT_REGISTER.size()); - NAMESPACED_MINECRAFT_REGISTER.forEach((key, holder) -> - LOGGER.info(" " + key + " -> " + holder.getClass().getSimpleName())); - - LOGGER.info(" Wild minecraft register: " + WILD_MINECRAFT_REGISTER.size()); - WILD_MINECRAFT_REGISTER.forEach(holder -> - LOGGER.info(" " + holder.getClass().getSimpleName())); } public static LeavesCustomPayload decode(ResourceLocation location, FriendlyByteBuf buf) { From 1c4e3e52846049b713e09f29326c0ce25e21795e Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 11 Jul 2025 22:07:00 +0300 Subject: [PATCH 34/67] experimental buffered linear region format --- divinemc-server/build.gradle.kts.patch | 2 +- .../0096-Buffered-Linear-region-format.patch | 215 +++--- .../bxteam/divinemc/config/DivineConfig.java | 21 + .../divinemc/region/BufferReleaser.java | 34 + .../divinemc/region/BufferedRegionFile.java | 620 ++++++++++++++++++ .../region/EnumRegionFileExtension.java | 39 ++ .../region/IRegionCreateFunction.java | 7 + .../bxteam/divinemc/region/IRegionFile.java | 41 ++ .../divinemc/region/RegionFileInfo.java | 7 + 9 files changed, 903 insertions(+), 83 deletions(-) rename patches/work/server/minecraft/0038-Linear-region-file-format.patch => divinemc-server/minecraft-patches/features/0096-Buffered-Linear-region-format.patch (66%) create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferReleaser.java create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferedRegionFile.java create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/EnumRegionFileExtension.java create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionCreateFunction.java create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileInfo.java diff --git a/divinemc-server/build.gradle.kts.patch b/divinemc-server/build.gradle.kts.patch index b526f81..50fd4f9 100644 --- a/divinemc-server/build.gradle.kts.patch +++ b/divinemc-server/build.gradle.kts.patch @@ -84,7 +84,7 @@ + implementation ("me.carleslc.Simple-YAML:Simple-Yaml:1.8.4") { + exclude(group="org.yaml", module="snakeyaml") + } -+ implementation("com.github.luben:zstd-jni:1.5.6-9") ++ implementation("com.github.luben:zstd-jni:1.5.7-3") + implementation("org.lz4:lz4-java:1.8.0") + // DivineMC end - Dependencies + diff --git a/patches/work/server/minecraft/0038-Linear-region-file-format.patch b/divinemc-server/minecraft-patches/features/0096-Buffered-Linear-region-format.patch similarity index 66% rename from patches/work/server/minecraft/0038-Linear-region-file-format.patch rename to divinemc-server/minecraft-patches/features/0096-Buffered-Linear-region-format.patch index b97144c..2f42a2f 100644 --- a/patches/work/server/minecraft/0038-Linear-region-file-format.patch +++ b/divinemc-server/minecraft-patches/features/0096-Buffered-Linear-region-format.patch @@ -1,11 +1,11 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 16 Mar 2025 21:16:55 +0300 -Subject: [PATCH] Linear region file format +Date: Fri, 11 Jul 2025 21:47:45 +0300 +Subject: [PATCH] Buffered Linear region format diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java -index a814512fcfb85312474ae2c2c21443843bf57831..fdccc27c528b01b16a72e614ffd96523aa6f50d2 100644 +index a814512fcfb85312474ae2c2c21443843bf57831..215d4444fbd9821811fbd4724de088dbb589f179 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java @@ -8,9 +8,9 @@ public interface ChunkSystemRegionFileStorage { @@ -13,15 +13,15 @@ index a814512fcfb85312474ae2c2c21443843bf57831..fdccc27c528b01b16a72e614ffd96523 public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ); - public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); -+ public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // DivineMC - Linear region file format ++ public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // DivineMC - Buffered Linear region format - public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; -+ public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // DivineMC - Linear region file format ++ public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // DivineMC - Buffered Linear region format public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite( final int chunkX, final int chunkZ, final CompoundTag compound diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java -index f5ed467c0880e4bcdf1b9ae773a5aac21c4381c3..95fb49f7b9ee3d132cf2405d99b2d63ee295d76d 100644 +index f5ed467c0880e4bcdf1b9ae773a5aac21c4381c3..64c157252f2288b507025ea96bfe4f76c635f1d9 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java @@ -1260,7 +1260,7 @@ public final class MoonriseRegionFileIO { @@ -29,7 +29,7 @@ index f5ed467c0880e4bcdf1b9ae773a5aac21c4381c3..95fb49f7b9ee3d132cf2405d99b2d63e // Paper start - flush regionfiles on save if (this.world.paperConfig().chunks.flushRegionsOnSave) { - final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); -+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // DivineMC - Linear region file format ++ final org.bxteam.divinemc.region.IRegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // DivineMC - Buffered Linear region format if (regionFile != null) { regionFile.flush(); } // else: evicted from cache, which should have called flush @@ -38,40 +38,46 @@ index f5ed467c0880e4bcdf1b9ae773a5aac21c4381c3..95fb49f7b9ee3d132cf2405d99b2d63e public static interface IORunnable { - public void run(final RegionFile regionFile) throws IOException; -+ public void run(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format ++ public void run(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Buffered Linear region format } } diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java -index 51c126735ace8fdde89ad97b5cab62f244212db0..8713d00d767c9225a0823d2fdbb0b479005738d7 100644 +index 51c126735ace8fdde89ad97b5cab62f244212db0..23f6ed26b531ea570fdf2ae48c1e2710e0ed22ed 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java -@@ -8,5 +8,5 @@ public interface ChunkSystemChunkBuffer { +@@ -3,10 +3,10 @@ package ca.spottedleaf.moonrise.patches.chunk_system.storage; + import net.minecraft.world.level.chunk.storage.RegionFile; + import java.io.IOException; + +-public interface ChunkSystemChunkBuffer { ++public interface ChunkSystemChunkBuffer { + public boolean moonrise$getWriteOnClose(); public void moonrise$setWriteOnClose(final boolean value); - public void moonrise$write(final RegionFile regionFile) throws IOException; -+ public void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format ++ public void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Buffered Linear region format } diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 5c05a41e6f64f37fc365cde6333ed5a684f167f2..1a36a7c071c9f203d32f524008cf031fb1a4d6a6 100644 +index 0072f3f07b1962adc1766930bb9a2f709cb76e6e..0bb53e820fbc8891cc9942d375e77bf6f9d5a1aa 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -928,10 +928,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> progressMap = Reference2FloatMaps.synchronize(new Reference2FloatOpenHashMap<>()); volatile Component status = Component.translatable("optimizeWorld.stage.counting"); - static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$"); -+ static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.(linear | mca)$"); // DivineMC - Linear region file format ++ static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\\\"+ net.minecraft.world.level.chunk.storage.RegionFileStorage.getExtensionName() +"$"); // DivineMC - Buffered Linear region format final DimensionDataStorage overworldDataStorage; public WorldUpgrader( @@ -88,7 +94,7 @@ index 79d57ca8a7870a02e95562d89cbd4341d8282660..b5711b348a2e1480b041587c220af587 private static List getAllChunkPositions(RegionStorageInfo regionStorageInfo, Path path) { - File[] files = path.toFile().listFiles((directory, filename) -> filename.endsWith(".mca")); -+ File[] files = path.toFile().listFiles((directory, filename) -> filename.endsWith(".linear") || filename.endsWith(".mca")); // DivineMC - Linear region file format ++ File[] files = path.toFile().listFiles((directory, filename) -> filename.endsWith(net.minecraft.world.level.chunk.storage.RegionFileStorage.getExtensionName())); // DivineMC - Buffered Linear region format if (files == null) { return List.of(); } else { @@ -97,7 +103,7 @@ index 79d57ca8a7870a02e95562d89cbd4341d8282660..b5711b348a2e1480b041587c220af587 List list1 = Lists.newArrayList(); - try (RegionFile regionFile = new RegionFile(regionStorageInfo, file.toPath(), path, true)) { -+ try (org.bxteam.divinemc.region.IRegionFile regionFile = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(regionStorageInfo, file.toPath(), path, true)) { // DivineMC - Linear region file format ++ try (org.bxteam.divinemc.region.IRegionFile regionFile = net.minecraft.world.level.chunk.storage.RegionFileStorage.createNew(regionStorageInfo, file.toPath(), path, true)) { // DivineMC - Buffered Linear region format for (int i2 = 0; i2 < 32; i2++) { for (int i3 = 0; i3 < 32; i3++) { ChunkPos chunkPos = new ChunkPos(i2 + i, i3 + i1); @@ -106,7 +112,7 @@ index 79d57ca8a7870a02e95562d89cbd4341d8282660..b5711b348a2e1480b041587c220af587 protected abstract boolean tryProcessOnePosition(T chunkStorage, ChunkPos chunkPos, ResourceKey dimension); - private void onFileFinished(RegionFile regionFile) { -+ private void onFileFinished(org.bxteam.divinemc.region.IRegionFile regionFile) { // DivineMC - Linear region file format ++ private void onFileFinished(org.bxteam.divinemc.region.IRegionFile regionFile) { // DivineMC - Buffered Linear region format if (WorldUpgrader.this.recreateRegionFiles) { if (this.previousWriteFuture != null) { this.previousWriteFuture.join(); @@ -115,12 +121,12 @@ index 79d57ca8a7870a02e95562d89cbd4341d8282660..b5711b348a2e1480b041587c220af587 } - record FileToUpgrade(RegionFile file, List chunksToUpgrade) { -+ record FileToUpgrade(org.bxteam.divinemc.region.IRegionFile file, List chunksToUpgrade) { // DivineMC - Linear region file format ++ record FileToUpgrade(org.bxteam.divinemc.region.IRegionFile file, List chunksToUpgrade) { // DivineMC - Buffered Linear region format } class PoiUpgrader extends WorldUpgrader.SimpleRegionStorageUpgrader { diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java -index ae0a893498d0bfe90c14508f15b431d4885e06ff..6fba4d36377359dbcf8c804b194c4aefdde53b01 100644 +index 22f3aa1674664906e8ec45372d758d79017e3987..55eaf7a5d4ceb957717298991fecce0b81c0f377 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java @@ -22,7 +22,7 @@ import net.minecraft.util.profiling.jfr.JvmProfiler; @@ -128,21 +134,62 @@ index ae0a893498d0bfe90c14508f15b431d4885e06ff..6fba4d36377359dbcf8c804b194c4aef import org.slf4j.Logger; -public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system -+public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile, org.bxteam.divinemc.region.IRegionFile { // Paper - rewrite chunk system // DivineMC - Linear region file format ++public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile, org.bxteam.divinemc.region.IRegionFile { // Paper - rewrite chunk system // DivineMC - Buffered Linear region format private static final Logger LOGGER = LogUtils.getLogger(); public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails private static final int SECTOR_BYTES = 4096; +@@ -130,7 +130,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + return this.recalculateCount.get(); + } + +- boolean recalculateHeader() throws IOException { ++ public boolean recalculateHeader() throws IOException { // DivineMC - Buffered Linear region format + if (!this.canRecalcHeader) { + return false; + } +@@ -794,7 +794,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + } + } + +- protected synchronized void write(ChunkPos chunkPos, ByteBuffer chunkData) throws IOException { ++ public synchronized void write(ChunkPos chunkPos, ByteBuffer chunkData) throws IOException { // DivineMC - Buffered Linear region format + int offsetIndex = getOffsetIndex(chunkPos); + int i = this.offsets.get(offsetIndex); + int sectorNumber = getSectorNumber(i); @@ -912,7 +912,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche } @Override - public final void moonrise$write(final RegionFile regionFile) throws IOException { -+ public final void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException { // DivineMC - Linear region file format ++ public final void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException { // DivineMC - Buffered Linear region format regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count)); } // Paper end - rewrite chunk system +@@ -978,11 +978,11 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + return (x & 31) + (z & 31) * 32; + } + +- synchronized boolean isOversized(int x, int z) { ++ public synchronized boolean isOversized(int x, int z) { // DivineMC - Buffered Linear region format + return this.oversized[getChunkIndex(x, z)] == 1; + } + +- synchronized void setOversized(int x, int z, boolean oversized) throws IOException { ++ public synchronized void setOversized(int x, int z, boolean oversized) throws IOException { // DivineMC - Buffered Linear region format + final int offset = getChunkIndex(x, z); + boolean previous = this.oversized[offset] == 1; + this.oversized[offset] = (byte) (oversized ? 1 : 0); +@@ -1021,7 +1021,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + return this.path.getParent().resolve(this.path.getFileName().toString().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt"); + } + +- synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException { ++ public synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException { + Path file = getOversizedFile(x, z); + try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new java.util.zip.InflaterInputStream(Files.newInputStream(file))))) { + return net.minecraft.nbt.NbtIo.read((java.io.DataInput) out); diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index c98cb390bda4b536f97445f228e06aaebcd84609..4e90366c5cea27ca2a38983c5de7b8eb68d72603 100644 +index 8d1174f25e0e90d0533970f4ddd8448442024936..ee797d6b3cd898cba1abd3422cb54b17eb4a639f 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -18,7 +18,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise @@ -150,188 +197,192 @@ index c98cb390bda4b536f97445f228e06aaebcd84609..4e90366c5cea27ca2a38983c5de7b8eb public static final String ANVIL_EXTENSION = ".mca"; private static final int MAX_CACHE_SIZE = 256; - public final Long2ObjectLinkedOpenHashMap regionCache = new Long2ObjectLinkedOpenHashMap<>(); -+ public final Long2ObjectLinkedOpenHashMap regionCache = new Long2ObjectLinkedOpenHashMap<>(); // DivineMC - Linear region file format ++ public final Long2ObjectLinkedOpenHashMap regionCache = new Long2ObjectLinkedOpenHashMap<>(); // DivineMC - Buffered Linear region format private final RegionStorageInfo info; private final Path folder; private final boolean sync; -@@ -33,7 +33,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - @Nullable - public static ChunkPos getRegionFileCoordinates(Path file) { - String fileName = file.getFileName().toString(); -- if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) { -+ if (!fileName.startsWith("r.") || !fileName.endsWith(".mca") || !fileName.endsWith(".linear")) { // DivineMC - Linear region file format - return null; - } - -@@ -58,6 +58,12 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -58,9 +58,29 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise private static final int MAX_NON_EXISTING_CACHE = 1024 * 4; private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet(); private static String getRegionFileName(final int chunkX, final int chunkZ) { -+ // DivineMC start - Linear region file format -+ if (org.bxteam.divinemc.config.DivineConfig.MiscCategory.regionFormatTypeName == org.bxteam.divinemc.region.RegionFileFormat.LINEAR) { -+ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".linear"; -+ } -+ // DivineMC end - Linear region file format -+ - return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".mca"; +- return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".mca"; ++ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + getExtensionName(); // DivineMC - Buffered Linear region format } -@@ -93,15 +99,15 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise ++ // DivineMC start - Buffered Linear region format ++ public static org.bxteam.divinemc.region.IRegionFile createNew(RegionStorageInfo info, Path filePath, Path folder, boolean sync) throws IOException{ ++ final org.bxteam.divinemc.region.EnumRegionFileExtension regionFormat = org.bxteam.divinemc.config.DivineConfig.MiscCategory.regionFileType; ++ final String fullFileName = filePath.getFileName().toString(); ++ final String[] fullNameSplit = fullFileName.split("\\."); ++ final String extensionName = fullNameSplit[fullNameSplit.length - 1]; ++ ++ if (!regionFormat.getArgument().equalsIgnoreCase(extensionName)) { ++ net.minecraft.server.MinecraftServer.setFatalException(new RuntimeException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument())); ++ throw new IOException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument()); ++ } ++ ++ return regionFormat.getCreator().create(new org.bxteam.divinemc.region.RegionFileInfo(info, filePath, folder, sync)); ++ } ++ ++ public static String getExtensionName() { ++ return "." + org.bxteam.divinemc.config.DivineConfig.MiscCategory.regionFileType.getArgument(); ++ } ++ // DivineMC end - Buffered Linear region format ++ + private boolean doesRegionFilePossiblyExist(final long position) { + synchronized (this.nonExistingRegionFiles) { + if (this.nonExistingRegionFiles.contains(position)) { +@@ -93,15 +113,15 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise } @Override - public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { -+ public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // DivineMC - Linear region file format ++ public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // DivineMC - Buffered Linear region format return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT)); } @Override - public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { -+ public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // DivineMC - Linear region file format ++ public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // DivineMC - Buffered Linear region format final long key = ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT); - RegionFile ret = this.regionCache.getAndMoveToFirst(key); -+ org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format ++ org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Buffered Linear region format if (ret != null) { return ret; } -@@ -125,7 +131,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -125,7 +145,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise FileUtil.createDirectoriesSafe(this.folder); - ret = new RegionFile(this.info, regionPath, this.folder, this.sync); -+ ret = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format ++ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // DivineMC - Buffered Linear region format this.regionCache.putAndMoveToFirst(key, ret); -@@ -144,11 +150,11 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -144,7 +164,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise } final ChunkPos pos = new ChunkPos(chunkX, chunkZ); - final RegionFile regionFile = this.getRegionFile(pos); -+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Linear region file format ++ final org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Buffered Linear region format // note: not required to keep regionfile loaded after this call, as the write param takes a regionfile as input // (and, the regionfile parameter is unused for writing until the write call) -- final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = ((ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile)regionFile).moonrise$startWrite(compound, pos); -+ final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = regionFile.moonrise$startWrite(compound, pos); // DivineMC - Linear region file format - - try { // Paper - implement RegionFileSizeException - try { -@@ -178,7 +184,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -178,7 +198,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise ) throws IOException { final ChunkPos pos = new ChunkPos(chunkX, chunkZ); if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) { - final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); -+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format ++ final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Buffered Linear region format if (regionFile != null) { regionFile.clear(pos); } // else: didn't exist -@@ -193,7 +199,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -193,7 +213,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.ReadData moonrise$readData( final int chunkX, final int chunkZ ) throws IOException { - final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); -+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format ++ final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Buffered Linear region format final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ)); -@@ -238,7 +244,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -238,7 +258,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise final ChunkPos pos = new ChunkPos(chunkX, chunkZ); final ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(ret); - final RegionFile regionFile = this.getRegionFile(pos); -+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Linear region file format ++ final org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Buffered Linear region format if (regionFile.getRecalculateCount() != readData.recalculateCount()) { return null; -@@ -262,7 +268,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -262,7 +282,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise } // Paper end - rewrite chunk system // Paper start - rewrite chunk system - public RegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { -+ public org.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { // DivineMC - Linear region file format ++ public org.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { // DivineMC - Buffered Linear region format return this.getRegionFile(chunkcoordintpair, false); } // Paper end - rewrite chunk system -@@ -274,7 +280,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -274,7 +294,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers } - @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit -+ @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private org.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit // DivineMC - Linear region file format ++ @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private org.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit // DivineMC - Buffered Linear region format // Paper start - rewrite chunk system if (existingOnly) { return this.moonrise$getRegionFileIfExists(chunkPos.x, chunkPos.z); -@@ -282,7 +288,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -282,7 +302,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise synchronized (this) { final long key = ChunkPos.asLong(chunkPos.x >> REGION_SHIFT, chunkPos.z >> REGION_SHIFT); - RegionFile ret = this.regionCache.getAndMoveToFirst(key); -+ org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format ++ org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Buffered Linear region format if (ret != null) { return ret; } -@@ -297,7 +303,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -297,7 +317,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise FileUtil.createDirectoriesSafe(this.folder); - ret = new RegionFile(this.info, regionPath, this.folder, this.sync); -+ ret = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format ++ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // DivineMC - Buffered Linear region format this.regionCache.putAndMoveToFirst(key, ret); -@@ -311,7 +317,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -311,7 +331,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO DIVINEMC - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); // DivineMC - Rebrand } - private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { -+ private static CompoundTag readOversizedChunk(org.bxteam.divinemc.region.IRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // DivineMC - Linear region file format ++ private static CompoundTag readOversizedChunk(org.bxteam.divinemc.region.IRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // DivineMC - Buffered Linear region format synchronized (regionfile) { try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) { CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z); -@@ -346,7 +352,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -346,7 +366,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise @Nullable public CompoundTag read(ChunkPos chunkPos) throws IOException { // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing - RegionFile regionFile = this.getRegionFile(chunkPos, true); -+ org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format ++ org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Buffered Linear region format if (regionFile == null) { return null; } -@@ -385,7 +391,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -385,7 +405,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise public void scanChunk(ChunkPos chunkPos, StreamTagVisitor visitor) throws IOException { // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing - RegionFile regionFile = this.getRegionFile(chunkPos, true); -+ org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format ++ org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Buffered Linear region format if (regionFile == null) { return; } -@@ -399,7 +405,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -399,7 +419,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise } public void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException { // Paper - rewrite chunk system - public - RegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system -+ org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system // DivineMC - Linear region file format ++ org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system // DivineMC - Buffered Linear region format // Paper start - rewrite chunk system if (regionFile == null) { // if the RegionFile doesn't exist, no point in deleting from it -@@ -429,7 +435,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -429,7 +449,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise // Paper start - rewrite chunk system synchronized (this) { final ExceptionCollector exceptionCollector = new ExceptionCollector<>(); - for (final RegionFile regionFile : this.regionCache.values()) { -+ for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format ++ for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Buffered Linear region format try { regionFile.close(); } catch (final IOException ex) { -@@ -445,7 +451,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -445,7 +465,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise // Paper start - rewrite chunk system synchronized (this) { final ExceptionCollector exceptionCollector = new ExceptionCollector<>(); - for (final RegionFile regionFile : this.regionCache.values()) { -+ for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format ++ for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Buffered Linear region format try { regionFile.flush(); } catch (final IOException ex) { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index d0787f3..1b4303f 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -11,6 +11,7 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; import org.bxteam.divinemc.config.annotations.Experimental; import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy; +import org.bxteam.divinemc.region.EnumRegionFileExtension; import org.bxteam.divinemc.server.network.AsyncJoinHandler; import org.jetbrains.annotations.Nullable; import org.simpleyaml.configuration.comments.CommentType; @@ -595,6 +596,10 @@ public class DivineConfig { public static boolean timeAcceleration = true; public static boolean randomTickSpeedAcceleration = true; + // Region Format + public static EnumRegionFileExtension regionFileType = EnumRegionFileExtension.MCA; + public static int linearCompressionLevel = 1; + // Sentry public static String sentryDsn = ""; public static String logLevel = "WARN"; @@ -615,6 +620,7 @@ public class DivineConfig { public static void load() { secureSeed(); lagCompensation(); + regionFileExtension(); sentrySettings(); ret(); oldFeatures(); @@ -642,6 +648,21 @@ public class DivineConfig { randomTickSpeedAcceleration = getBoolean(ConfigCategory.MISC.key("lag-compensation.random-tick-speed-acceleration"), randomTickSpeedAcceleration); } + private static void regionFileExtension() { + regionFileType = EnumRegionFileExtension.fromString(getString(ConfigCategory.MISC.key("region-format.type"), regionFileType.toString(), + "The type of region file format to use for storing chunk data.", + "Valid values:", + " - MCA: Default Minecraft region file format", + " - B_LINEAR: Buffered region file format")); + linearCompressionLevel = getInt(ConfigCategory.MISC.key("region-format.compression-level"), linearCompressionLevel, + "The compression level to use for the linear region file format."); + + if (linearCompressionLevel > 22 || linearCompressionLevel < 1) { + LOGGER.warn("Invalid linear compression level: {}, resetting to default (1)", linearCompressionLevel); + linearCompressionLevel = 1; + } + } + private static void sentrySettings() { sentryDsn = getString(ConfigCategory.MISC.key("sentry.dsn"), sentryDsn, "The DSN for Sentry, a service that provides real-time crash reporting that helps you monitor and fix crashes in real time. Leave blank to disable. Obtain link at https://sentry.io"); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferReleaser.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferReleaser.java new file mode 100644 index 0000000..88739d1 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferReleaser.java @@ -0,0 +1,34 @@ +package org.bxteam.divinemc.region; + +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; + +public class BufferReleaser { + private static final Method CLEANER_METHOD; + private static final Object UNSAFE; + + static { + try { + Class unsafeClass = Class.forName("sun.misc.Unsafe"); + Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + UNSAFE = theUnsafe.get(null); + CLEANER_METHOD = unsafeClass.getMethod("invokeCleaner", ByteBuffer.class); + } catch (Exception ex) { + throw new RuntimeException("Unsafe init failed", ex); + } + } + + public static boolean clean(@NotNull ByteBuffer buffer) { + if (!buffer.isDirect()) return false; + try { + CLEANER_METHOD.invoke(UNSAFE, buffer); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferedRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferedRegionFile.java new file mode 100644 index 0000000..bd25e6f --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferedRegionFile.java @@ -0,0 +1,620 @@ +package org.bxteam.divinemc.region; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import net.jpountz.xxhash.XXHash32; +import net.jpountz.xxhash.XXHashFactory; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.ChunkPos; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.atomic.AtomicInteger; + +public class BufferedRegionFile implements IRegionFile { + private static final double AUTO_COMPACT_PERCENT = 3.0 / 5.0; // 60% + private static final long AUTO_COMPACT_SIZE = 1024 * 1024; // 1 MiB + private static final long SUPER_BLOCK = 0x1145141919810L; + private static final int HASH_SEED = 0x0721; + private static final byte VERSION = 0x01; // Version 1 + + private final Path filePath; + private final ReadWriteLock fileAccessLock = new ReentrantReadWriteLock(); + private final XXHash32 xxHash32 = XXHashFactory.fastestInstance().hash32(); + private final Sector[] sectors = new Sector[1024]; + private final AtomicInteger recalculateCount = new AtomicInteger(0); + private long currentAcquiredIndex = this.headerSize(); + private byte compressionLevel = 6; + private int xxHash32Seed = HASH_SEED; + private FileChannel channel; + + public BufferedRegionFile(Path filePath, int compressionLevel) throws IOException { + this(filePath); + + this.compressionLevel = (byte) compressionLevel; + } + + public BufferedRegionFile(Path filePath) throws IOException { + this.channel = FileChannel.open( + filePath, + StandardOpenOption.CREATE, + StandardOpenOption.WRITE, + StandardOpenOption.READ + ); + this.filePath = filePath; + + for (int i = 0; i < 1024; i++) { + this.sectors[i] = new Sector(i, this.headerSize(), 0); + } + + this.readHeaders(); + } + + private void readHeaders() throws IOException { + if (this.channel.size() < this.headerSize()) { + return; + } + + final ByteBuffer buffer = ByteBuffer.allocateDirect(this.headerSize()); + this.channel.read(buffer, 0); + buffer.flip(); + + if (buffer.getLong() != SUPER_BLOCK || buffer.get() != VERSION) { + throw new IOException("Invalid file format or version mismatch"); + } + + this.compressionLevel = buffer.get(); // Compression level + this.xxHash32Seed = buffer.getInt(); // XXHash32 seed + this.currentAcquiredIndex = buffer.getLong(); // Acquired index + + for (Sector sector : this.sectors) { + sector.restoreFrom(buffer); + if (sector.hasData()) { + this.currentAcquiredIndex = Math.max(this.currentAcquiredIndex, sector.offset + sector.length); + } + } + + BufferReleaser.clean(buffer); + } + + private void writeHeaders() throws IOException { + final ByteBuffer buffer = ByteBuffer.allocateDirect(this.headerSize()); + + buffer.putLong(SUPER_BLOCK); // Magic + buffer.put(VERSION); // Version + buffer.put(this.compressionLevel); // Compression level + buffer.putInt(this.xxHash32Seed); // XXHash32 seed + buffer.putLong(this.currentAcquiredIndex); // Acquired index + + for (Sector sector : this.sectors) { + buffer.put(sector.getEncoded()); + } + + buffer.flip(); + + long offset = 0; + while (buffer.hasRemaining()) { + offset += this.channel.write(buffer, offset); + } + + BufferReleaser.clean(buffer); + } + + private int sectorSize() { + return this.sectors.length * Sector.sizeOfSingle(); + } + + private int headerSize() { + int result = 0; + + result += Long.BYTES; // Magic + result += Byte.BYTES; // Version + result += Byte.BYTES; // Compression level + result += Integer.BYTES; // XXHash32 seed + result += Long.BYTES; // Acquired index + result += this.sectorSize(); // Sectors + + return result; + } + + private void flushInternal() throws IOException { + this.writeHeaders(); + + long spareSize = this.channel.size(); + + spareSize -= this.headerSize(); + for (Sector sector : this.sectors) { + spareSize -= sector.length; + } + + long sectorSize = 0; + for (Sector sector : this.sectors) { + sectorSize += sector.length; + } + + if (spareSize > AUTO_COMPACT_SIZE && (double)spareSize > ((double)sectorSize) * AUTO_COMPACT_PERCENT) { + this.compact(); + } + } + + private void closeInternal() throws IOException { + this.writeHeaders(); + this.channel.force(true); + this.compact(); + this.channel.close(); + } + + private void compact() throws IOException { + this.writeHeaders(); + this.channel.force(true); + try (FileChannel tempChannel = FileChannel.open( + new File(this.filePath.toString() + ".tmp").toPath(), + StandardOpenOption.CREATE, + StandardOpenOption.WRITE, + StandardOpenOption.READ + )){ + final ByteBuffer headerBuffer = ByteBuffer.allocateDirect(this.headerSize()); + this.channel.read(headerBuffer, 0); + headerBuffer.flip(); + + long offsetHeader = 0; + while (headerBuffer.hasRemaining()) { + offsetHeader += tempChannel.write(headerBuffer, offsetHeader); + } + BufferReleaser.clean(headerBuffer); + + int offsetPointer = this.headerSize(); + for (Sector sector : this.sectors) { + if (!sector.hasData()) { + continue; + } + + final ByteBuffer sectorData = sector.read(this.channel); + final int length = sectorData.remaining(); + + final Sector newRecalculated = new Sector(sector.index, offsetPointer, length); + offsetPointer += length; + this.sectors[sector.index] = newRecalculated; + + newRecalculated.hasData = true; + + long offset = newRecalculated.offset; + while (sectorData.hasRemaining()) { + offset += tempChannel.write(sectorData, offset); + } + + BufferReleaser.clean(sectorData); + } + + tempChannel.force(true); + this.currentAcquiredIndex = tempChannel.size(); + } + + Files.move( + new File(this.filePath.toString() + ".tmp").toPath(), + this.filePath, + java.nio.file.StandardCopyOption.REPLACE_EXISTING + ); + + this.reopenChannel(); + this.writeHeaders(); + } + + private void reopenChannel() throws IOException { + if (this.channel.isOpen()) { + this.channel.close(); + } + + this.channel = FileChannel.open( + filePath, + StandardOpenOption.CREATE, + StandardOpenOption.WRITE, + StandardOpenOption.READ + ); + } + + private void writeChunkDataRaw(int chunkOrdinal, ByteBuffer chunkData) throws IOException { + final Sector sector = this.sectors[chunkOrdinal]; + + sector.store(chunkData, this.channel); + } + + private @Nullable ByteBuffer readChunkDataRaw(int chunkOrdinal) throws IOException { + final Sector sector = this.sectors[chunkOrdinal]; + + if (!sector.hasData()) { + return null; + } + + return sector.read(this.channel); + } + + private void clearChunkData(int chunkOrdinal) throws IOException { + final Sector sector = this.sectors[chunkOrdinal]; + + sector.clear(); + + this.writeHeaders(); + } + + private static int getChunkIndex(int x, int z) { + return (x & 31) + ((z & 31) << 5); + } + + private boolean hasData(int chunkOriginal) { + return this.sectors[chunkOriginal].hasData(); + } + + private void writeChunk(int x, int z, @NotNull ByteBuffer data) throws IOException { + final int chunkIndex = getChunkIndex(x, z); + + final int oldPositionOfData = data.position(); + final int xxHash32OfData = this.xxHash32.hash(data, this.xxHash32Seed); + data.position(oldPositionOfData); + + final ByteBuffer compressedData = this.compress(this.ensureDirectBuffer(data)); + final ByteBuffer chunkSectionBuilder = ByteBuffer.allocateDirect(compressedData.remaining() + 4 + 8 + 4); + + chunkSectionBuilder.putInt(data.remaining()); // Uncompressed length + chunkSectionBuilder.putLong(System.nanoTime()); // Timestamp + chunkSectionBuilder.putInt(xxHash32OfData); // xxHash32 of the original data + chunkSectionBuilder.put(compressedData); // Compressed data + chunkSectionBuilder.flip(); + + this.writeChunkDataRaw(chunkIndex, chunkSectionBuilder); + BufferReleaser.clean(chunkSectionBuilder); + } + + private @Nullable ByteBuffer readChunk(int x, int z) throws IOException { + final ByteBuffer compressed = this.readChunkDataRaw(getChunkIndex(x, z)); + + if (compressed == null) { + return null; + } + + final int uncompressedLength = compressed.getInt(); // compressed length + final long timestamp = compressed.getLong(); // TODO use this timestamp for something? + final int dataXXHash32 = compressed.getInt(); // XXHash32 for validation + + final ByteBuffer decompressed = this.decompress(this.ensureDirectBuffer(compressed), uncompressedLength); + + BufferReleaser.clean(compressed); + + final IOException xxHash32CheckFailedEx = this.checkXXHash32(dataXXHash32, decompressed); + if (xxHash32CheckFailedEx != null) { + throw xxHash32CheckFailedEx; // prevent from loading + } + + return decompressed; + } + + private @NotNull ByteBuffer ensureDirectBuffer(@NotNull ByteBuffer buffer) { + if (buffer.isDirect()) { + return buffer; + } + + ByteBuffer direct = ByteBuffer.allocateDirect(buffer.remaining()); + int originalPosition = buffer.position(); + direct.put(buffer); + direct.flip(); + buffer.position(originalPosition); + + return direct; + } + + private @NotNull ByteBuffer compress(@NotNull ByteBuffer input) throws IOException { + final int originalPosition = input.position(); + final int originalLimit = input.limit(); + + try { + byte[] inputArray; + int inputLength = input.remaining(); + if (input.hasArray()) { + inputArray = input.array(); + int arrayOffset = input.arrayOffset() + input.position(); + if (arrayOffset != 0 || inputLength != inputArray.length) { + byte[] temp = new byte[inputLength]; + System.arraycopy(inputArray, arrayOffset, temp, 0, inputLength); + inputArray = temp; + } + } else { + inputArray = new byte[inputLength]; + input.get(inputArray); + input.position(originalPosition); + } + + byte[] compressed = com.github.luben.zstd.Zstd.compress(inputArray, this.compressionLevel); + + ByteBuffer result = ByteBuffer.allocateDirect(compressed.length); + result.put(compressed); + result.flip(); + + return result; + + } catch (Exception e) { + throw new IOException("Compression failed for input size: " + input.remaining(), e); + } finally { + input.position(originalPosition); + input.limit(originalLimit); + } + } + + private @NotNull ByteBuffer decompress(@NotNull ByteBuffer input, int originalSize) throws IOException { + final int originalPosition = input.position(); + final int originalLimit = input.limit(); + + try { + byte[] inputArray; + int inputLength = input.remaining(); + + if (input.hasArray()) { + inputArray = input.array(); + int arrayOffset = input.arrayOffset() + input.position(); + if (arrayOffset != 0 || inputLength != inputArray.length) { + byte[] temp = new byte[inputLength]; + System.arraycopy(inputArray, arrayOffset, temp, 0, inputLength); + inputArray = temp; + } + } else { + inputArray = new byte[inputLength]; + input.get(inputArray); + input.position(originalPosition); + } + + byte[] decompressed = com.github.luben.zstd.Zstd.decompress(inputArray, originalSize); + + if (decompressed.length != originalSize) { + throw new IOException("Decompression size mismatch: expected " + + originalSize + ", got " + decompressed.length); + } + + ByteBuffer result = ByteBuffer.allocateDirect(originalSize); + result.put(decompressed); + result.flip(); + + return result; + + } catch (Exception e) { + throw new IOException("Decompression failed", e); + } finally { + input.position(originalPosition); + input.limit(originalLimit); + } + } + + private @Nullable IOException checkXXHash32(long originalXXHash32, @NotNull ByteBuffer input) { + final int oldPositionOfInput = input.position(); + final int currentXXHash32 = this.xxHash32.hash(input, this.xxHash32Seed); + input.position(oldPositionOfInput); + + if (originalXXHash32 != currentXXHash32) { + return new IOException("XXHash32 check failed ! Expected: " + originalXXHash32 + ",but got: " + currentXXHash32); + } + + return null; + } + + @Override + public Path getPath() { + return this.filePath; + } + + @Override + public DataInputStream getChunkDataInputStream(@NotNull ChunkPos pos) throws IOException { + this.fileAccessLock.readLock().lock(); + try { + final ByteBuffer data = this.readChunk(pos.x, pos.z); + + if (data == null) { + return null; + } + + final byte[] dataBytes = new byte[data.remaining()]; + data.get(dataBytes); + + BufferReleaser.clean(data); + + return new DataInputStream(new ByteArrayInputStream(dataBytes)); + }finally { + this.fileAccessLock.readLock().unlock(); + } + } + + @Override + public boolean doesChunkExist(@NotNull ChunkPos pos) { + this.fileAccessLock.readLock().lock(); + try { + return this.hasData(getChunkIndex(pos.x, pos.z)); + }finally { + this.fileAccessLock.readLock().unlock(); + } + } + + @Override + public DataOutputStream getChunkDataOutputStream(ChunkPos pos) { + return new DataOutputStream(new ChunkBufferHelper(pos)); + } + + @Override + public void clear(@NotNull ChunkPos pos) throws IOException { + this.fileAccessLock.writeLock().lock(); + try { + this.clearChunkData(getChunkIndex(pos.x, pos.z)); + }finally { + this.fileAccessLock.writeLock().unlock(); + } + } + + @Override + public boolean hasChunk(@NotNull ChunkPos pos) { + this.fileAccessLock.readLock().lock(); + try { + return this.hasData(getChunkIndex(pos.x, pos.z)); + }finally { + this.fileAccessLock.readLock().unlock(); + } + } + + @Override + public void write(@NotNull ChunkPos pos, ByteBuffer buf) throws IOException { + this.fileAccessLock.writeLock().lock(); + try { + this.writeChunk(pos.x, pos.z, buf); + }finally { + this.fileAccessLock.writeLock().unlock(); + } + } + + @Override + public CompoundTag getOversizedData(int x, int z) { + return null; + } + + @Override + public boolean isOversized(int x, int z) { + return false; + } + + @Override + public boolean recalculateHeader() { + this.recalculateCount.incrementAndGet(); + return false; + } + + @Override + public void setOversized(int x, int z, boolean oversized) { + + } + + @Override + public int getRecalculateCount() { + return this.recalculateCount.get(); + } + // MCC end + + @Override + public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) { + final DataOutputStream out = this.getChunkDataOutputStream(pos); + + return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData( + data, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE, + out, regionFile -> out.close() + ); + } + + @Override + public void flush() throws IOException { + this.fileAccessLock.writeLock().lock(); + try { + this.flushInternal(); + }finally { + this.fileAccessLock.writeLock().unlock(); + } + } + + @Override + public void close() throws IOException { + this.fileAccessLock.writeLock().lock(); + try { + this.closeInternal(); + }finally { + this.fileAccessLock.writeLock().unlock(); + } + } + + private class Sector{ + private final int index; + private long offset; + private long length; + private boolean hasData = false; + + private Sector(int index, long offset, long length) { + this.index = index; + this.offset = offset; + this.length = length; + } + + public @NotNull ByteBuffer read(@NotNull FileChannel channel) throws IOException { + final ByteBuffer result = ByteBuffer.allocateDirect((int) this.length); + + channel.read(result, this.offset); + result.flip(); + + return result; + } + + public void store(@NotNull ByteBuffer newData, @NotNull FileChannel channel) throws IOException { + this.hasData = true; + this.length = newData.remaining(); + this.offset = currentAcquiredIndex; + + BufferedRegionFile.this.currentAcquiredIndex += this.length; + + long offset = this.offset; + while (newData.hasRemaining()) { + offset = channel.write(newData, offset); + } + } + + private @NotNull ByteBuffer getEncoded() { + final ByteBuffer buffer = ByteBuffer.allocateDirect(sizeOfSingle()); + + buffer.putLong(this.offset); + buffer.putLong(this.length); + buffer.put((byte) (this.hasData ? 1 : 0)); + buffer.flip(); + + return buffer; + } + + public void restoreFrom(@NotNull ByteBuffer buffer) { + this.offset = buffer.getLong(); + this.length = buffer.getLong(); + this.hasData = buffer.get() == 1; + + if (this.length < 0 || this.offset < 0) { + throw new IllegalStateException("Invalid sector data: " + this); + } + } + + public void clear() { + this.hasData = false; + } + + public boolean hasData() { + return this.hasData; + } + + static int sizeOfSingle() { + // offset length hasData + return Long.BYTES * 2 + 1; + } + } + + private class ChunkBufferHelper extends ByteArrayOutputStream { + private final ChunkPos pos; + + private ChunkBufferHelper(ChunkPos pos) { + this.pos = pos; + } + + @Override + public void close() throws IOException { + BufferedRegionFile.this.fileAccessLock.writeLock().lock(); + try { + ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); + + BufferedRegionFile.this.writeChunk(this.pos.x, this.pos.z, bytebuffer); + }finally { + BufferedRegionFile.this.fileAccessLock.writeLock().unlock(); + } + } + } +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/EnumRegionFileExtension.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/EnumRegionFileExtension.java new file mode 100644 index 0000000..99e9eff --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/EnumRegionFileExtension.java @@ -0,0 +1,39 @@ +package org.bxteam.divinemc.region; + +import net.minecraft.world.level.chunk.storage.RegionFile; +import org.bxteam.divinemc.config.DivineConfig; +import org.jetbrains.annotations.Nullable; + +public enum EnumRegionFileExtension { + MCA("mca", "mca" , (info) -> new RegionFile(info.info(), info.filePath(), info.folder(), info.sync())), + B_LINEAR("b_linear", "b_linear", (info) -> new BufferedRegionFile(info.filePath(), DivineConfig.MiscCategory.linearCompressionLevel)); + + private final String name; + private final String argument; + private final IRegionCreateFunction creator; + + EnumRegionFileExtension(String name, String argument, IRegionCreateFunction creator) { + this.name = name; + this.argument = argument; + this.creator = creator; + } + + @Nullable + public static EnumRegionFileExtension fromString(String string) { + for (EnumRegionFileExtension format : values()) { + if (format.name.equalsIgnoreCase(string)) { + return format; + } + } + + return null; + } + + public IRegionCreateFunction getCreator() { + return this.creator; + } + + public String getArgument() { + return this.argument; + } +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionCreateFunction.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionCreateFunction.java new file mode 100644 index 0000000..ea202d3 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionCreateFunction.java @@ -0,0 +1,7 @@ +package org.bxteam.divinemc.region; + +import java.io.IOException; + +public interface IRegionCreateFunction { + IRegionFile create(RegionFileInfo info) throws IOException; +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java new file mode 100644 index 0000000..18708b5 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java @@ -0,0 +1,41 @@ +package org.bxteam.divinemc.region; + +import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.ChunkPos; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.file.Path; + +public interface IRegionFile extends ChunkSystemRegionFile, AutoCloseable { + Path getPath(); + + DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException; + + boolean doesChunkExist(ChunkPos pos) throws Exception; + + DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException; + + void flush() throws IOException; + + void clear(ChunkPos pos) throws IOException; + + boolean hasChunk(ChunkPos pos); + + void close() throws IOException; + + void write(ChunkPos pos, ByteBuffer buf) throws IOException; + + CompoundTag getOversizedData(int x, int z) throws IOException; + + boolean isOversized(int x, int z); + + boolean recalculateHeader() throws IOException; + + void setOversized(int x, int z, boolean oversized) throws IOException; + + int getRecalculateCount(); +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileInfo.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileInfo.java new file mode 100644 index 0000000..985348b --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileInfo.java @@ -0,0 +1,7 @@ +package org.bxteam.divinemc.region; + +import net.minecraft.world.level.chunk.storage.RegionStorageInfo; + +import java.nio.file.Path; + +public record RegionFileInfo(RegionStorageInfo info, Path filePath, Path folder, boolean sync) { } From b631cf937576d06a60c48ea93ca691bf37005b6f Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 12 Jul 2025 15:15:41 +0300 Subject: [PATCH 35/67] Updated Upstream (Purpur) Upstream has released updates that appear to apply and compile correctly Purpur Changes: PurpurMC/Purpur@11c030a8 Updated Upstream (Paper) --- divinemc-server/build.gradle.kts.patch | 2 +- .../0003-Completely-remove-Mojang-profiler.patch | 16 ++++++++-------- .../features/0021-Fix-MC-31819.patch | 4 ++-- ...MP-skip-entity-move-if-movement-is-zero.patch | 4 ++-- .../features/0037-Configurable-MC-67.patch | 4 ++-- .../0049-Option-to-disable-disconnect.spam.patch | 4 ++-- ...078-SparklyPaper-Parallel-world-ticking.patch | 12 ++++++------ .../features/0089-Raytrace-Entity-Tracker.patch | 8 ++++---- .../features/0092-Leaves-Protocol-Core.patch | 6 +++--- gradle.properties | 2 +- 10 files changed, 31 insertions(+), 31 deletions(-) diff --git a/divinemc-server/build.gradle.kts.patch b/divinemc-server/build.gradle.kts.patch index 50fd4f9..4540517 100644 --- a/divinemc-server/build.gradle.kts.patch +++ b/divinemc-server/build.gradle.kts.patch @@ -7,7 +7,7 @@ +val bxTeamMavenPublicUrl = "https://repo.bxteam.org/snapshots/" dependencies { - mache("io.papermc:mache:1.21.7+build.1") + mache("io.papermc:mache:1.21.7+build.2") @@ -29,6 +_,7 @@ // Purpur start - Rebrand diff --git a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch index 420f563..6e13845 100644 --- a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch +++ b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch @@ -1479,7 +1479,7 @@ index 3c7159d0981c948e71a5612ba4083accb5849ed4..5f2c27800f047f128857044493a6d932 for (Entity entity : passengerEntity.getPassengers()) { this.tickPassenger(passengerEntity, entity, isActive); // Paper - EAR 2 diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index ac4e3a66c5979bbd65618eec0c8e0b744f397603..890c295d2318767081580e9aabddedd2535388cc 100644 +index ba9e1f5963aeda8b5ed52c7daaa2a9fe62006d3b..9a296776480af489561eb19c6ed18d9558ee746a 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -106,8 +106,6 @@ import net.minecraft.util.HashOps; @@ -4006,7 +4006,7 @@ index 39a604c9a53930b53d959b1d2eb504aa964e9a58..0d0380e3955836ce125f777841477503 @Override diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index ce3e5ec505ac37c820436bcf7c7d6452ff015f70..f8b37b4ce54afd61a72e9d18ac323540431c655d 100644 +index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894dc49d303 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -80,8 +80,6 @@ import net.minecraft.tags.TagKey; @@ -4079,7 +4079,7 @@ index ce3e5ec505ac37c820436bcf7c7d6452ff015f70..f8b37b4ce54afd61a72e9d18ac323540 } } // Paper start - detailed watchdog information -@@ -3467,8 +3455,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3466,8 +3454,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.processPortalCooldown(); if (this.portalProcess != null) { if (this.portalProcess.processPortalTeleportation(serverLevel, this, this.canUsePortal(false))) { @@ -4088,7 +4088,7 @@ index ce3e5ec505ac37c820436bcf7c7d6452ff015f70..f8b37b4ce54afd61a72e9d18ac323540 this.setPortalCooldown(); TeleportTransition portalDestination = this.portalProcess.getPortalDestination(serverLevel, this); if (portalDestination != null) { -@@ -3478,8 +3464,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3477,8 +3463,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.teleport(portalDestination); } } @@ -4097,7 +4097,7 @@ index ce3e5ec505ac37c820436bcf7c7d6452ff015f70..f8b37b4ce54afd61a72e9d18ac323540 } else if (this.portalProcess.hasExpired()) { this.portalProcess = null; } -@@ -4046,15 +4030,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4045,15 +4029,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess entity.teleport(this.calculatePassengerTransition(teleportTransition, entity)); } @@ -4113,7 +4113,7 @@ index ce3e5ec505ac37c820436bcf7c7d6452ff015f70..f8b37b4ce54afd61a72e9d18ac323540 return this; } -@@ -4070,11 +4051,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4069,11 +4050,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } @@ -4125,7 +4125,7 @@ index ce3e5ec505ac37c820436bcf7c7d6452ff015f70..f8b37b4ce54afd61a72e9d18ac323540 return null; } else { // Paper start - Fix item duplication and teleport issues -@@ -4094,7 +4072,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4093,7 +4071,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess newLevel.resetEmptyTime(); teleportTransition.postTeleportTransition().onTransition(entityx); this.teleportSpectators(teleportTransition, oldLevel); @@ -4134,7 +4134,7 @@ index ce3e5ec505ac37c820436bcf7c7d6452ff015f70..f8b37b4ce54afd61a72e9d18ac323540 } } diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index 3d93e89e7bad80cd5b5c7ccbb738980f4b3469bc..02765eab997874c7c8f6ebe78a3473ef9be2380a 100644 +index ddd3acbc804cbc07eaccf578349d3f9e0e00b6fc..0c0144679c9d44d50af153c792d7e5da175365d8 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java @@ -69,8 +69,6 @@ import net.minecraft.tags.FluidTags; diff --git a/divinemc-server/minecraft-patches/features/0021-Fix-MC-31819.patch b/divinemc-server/minecraft-patches/features/0021-Fix-MC-31819.patch index 51d07aa..e38988c 100644 --- a/divinemc-server/minecraft-patches/features/0021-Fix-MC-31819.patch +++ b/divinemc-server/minecraft-patches/features/0021-Fix-MC-31819.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Fix MC-31819 Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-31819 diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java -index 97b104679bb2b9e466caa10d7b022ee6d597e7e5..18b670a1e6e62c3b79281e529c89f35b16427c69 100644 +index d72e338232b95826b63d784ac0731f5a20bf8dcb..05634e09200fa613b69aafe9b2505dbc9b5c54eb 100644 --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java -@@ -1818,6 +1818,11 @@ public abstract class Player extends LivingEntity { +@@ -1817,6 +1817,11 @@ public abstract class Player extends LivingEntity { } public void causeFoodExhaustion(float exhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason reason) { diff --git a/divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch b/divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch index c6e254d..6a3d39e 100644 --- a/divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch +++ b/divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch @@ -10,7 +10,7 @@ As part of: VMP (https://github.com/RelativityMC/VMP-fabric) Licensed under: MIT (https://opensource.org/licenses/MIT) diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index f8b37b4ce54afd61a72e9d18ac323540431c655d..54307d5795d3cf36c3a39ff7fd21c92b46626c17 100644 +index 02f39e3dc420a5bd49cd6e247c9b1894dc49d303..0171befef713e89d9241c7735d5d285b23373e8f 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -372,6 +372,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -29,7 +29,7 @@ index f8b37b4ce54afd61a72e9d18ac323540431c655d..54307d5795d3cf36c3a39ff7fd21c92b final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity // Paper start - detailed watchdog information ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); -@@ -4426,6 +4428,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4425,6 +4427,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public final void setBoundingBox(AABB bb) { diff --git a/divinemc-server/minecraft-patches/features/0037-Configurable-MC-67.patch b/divinemc-server/minecraft-patches/features/0037-Configurable-MC-67.patch index 28a1699..bb59b9d 100644 --- a/divinemc-server/minecraft-patches/features/0037-Configurable-MC-67.patch +++ b/divinemc-server/minecraft-patches/features/0037-Configurable-MC-67.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Configurable MC-67 diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 54307d5795d3cf36c3a39ff7fd21c92b46626c17..39076c52a1ed15d1403d08851d53787a9055d6ee 100644 +index 0171befef713e89d9241c7735d5d285b23373e8f..5bc7f37290eb99145a2ea3e40d31180f3494979b 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -4199,6 +4199,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4198,6 +4198,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public boolean canTeleport(Level fromLevel, Level toLevel) { diff --git a/divinemc-server/minecraft-patches/features/0049-Option-to-disable-disconnect.spam.patch b/divinemc-server/minecraft-patches/features/0049-Option-to-disable-disconnect.spam.patch index b962f45..984de26 100644 --- a/divinemc-server/minecraft-patches/features/0049-Option-to-disable-disconnect.spam.patch +++ b/divinemc-server/minecraft-patches/features/0049-Option-to-disable-disconnect.spam.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Option to disable disconnect.spam diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index a8b2c19cc9803058b421b07c739166afdf291e47..8f4bca6a99b35e869e34f0fa216c13189cd7b384 100644 +index a63ade75461b68a780c56bfb5ff7c61f99f76744..fe7d68f3947bf55a389c73ef301fae8e396bf1da 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -844,7 +844,7 @@ public class ServerGamePacketListenerImpl @@ -42,7 +42,7 @@ index a8b2c19cc9803058b421b07c739166afdf291e47..8f4bca6a99b35e869e34f0fa216c1318 && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause & add proper async disconnect -@@ -3386,7 +3388,7 @@ public class ServerGamePacketListenerImpl +@@ -3328,7 +3330,7 @@ public class ServerGamePacketListenerImpl public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { // Paper start - auto recipe limit if (!org.bukkit.Bukkit.isPrimaryThread()) { diff --git a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch index ab00baa..87881bb 100644 --- a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch @@ -460,7 +460,7 @@ index 3c1795eb56900cd80cfec38bd1d922d566463ecb..07b9a2529be69bf8158528e996e7ddb9 // Paper start - extra debug info if (entity.valid) { diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index b75d2d2746c3e7b12f65b0bcb559cd7e0ce7ebf8..52f3c374c91f877b51b243b46cd05c5e2fc0face 100644 +index c33dbe22a74576935c1a18450502c4ec8d83a4c3..86470728c2d03063c4eb0c43cfe323e809cac846 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -431,6 +431,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc @@ -633,10 +633,10 @@ index f9e7532f86122a379692561a639a209a126e8bba..839f6b7696ef85314da185bedba7cfc5 if (isLocatorBarEnabledFor(player)) { if (!connection.isBroken()) { diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index cad10bd55ac1e52d00b3b9c3205562b346c54e2a..44cd33cec38b1a2af304ec819b14124187011df1 100644 +index bdf9899f960b6cca3529af97ebff738761208439..adea48cfde04df3107341075f414133ae37d986e 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -3460,14 +3460,34 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3459,14 +3459,34 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess if (this.portalProcess != null) { if (this.portalProcess.processPortalTeleportation(serverLevel, this, this.canUsePortal(false))) { this.setPortalCooldown(); @@ -677,7 +677,7 @@ index cad10bd55ac1e52d00b3b9c3205562b346c54e2a..44cd33cec38b1a2af304ec819b141241 } else if (this.portalProcess.hasExpired()) { this.portalProcess = null; } -@@ -4044,6 +4064,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4043,6 +4063,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } private Entity teleportCrossDimension(ServerLevel oldLevel, ServerLevel newLevel, TeleportTransition teleportTransition) { @@ -909,7 +909,7 @@ index 2258736e6f9f52efe5bd353b8949a7a0b9a4fdb8..440fbe301782e81cec679a27a876dd3c } else { Entity entity = owner.teleport( diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java -index 1f601781643945920c7522b9c6100d0a37ad535d..bd31350c5b9b727cfd9150a399d207839a51e4dd 100644 +index 2305a3ef6bbb21ab77cb261f20c08ac8ce1bf9ed..b313f6a4e27f6918d174dacba37479a93936668f 100644 --- a/net/minecraft/world/inventory/AbstractContainerMenu.java +++ b/net/minecraft/world/inventory/AbstractContainerMenu.java @@ -96,8 +96,14 @@ public abstract class AbstractContainerMenu { @@ -928,7 +928,7 @@ index 1f601781643945920c7522b9c6100d0a37ad535d..bd31350c5b9b727cfd9150a399d20783 this.containerId = containerId; } diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java -index b95acf4c688a9113a34e9be2639536245c66c83e..160fd27bdd02e9c276cdae241b0652ae547517cf 100644 +index d3892cc9ef3ab66a45fe3ab72e8a5ef8b904b7c0..6b5b6d73897ded23dd2fbf17abb1b5c1ee5b1082 100644 --- a/net/minecraft/world/item/ItemStack.java +++ b/net/minecraft/world/item/ItemStack.java @@ -398,8 +398,10 @@ public final class ItemStack implements DataComponentHolder { diff --git a/divinemc-server/minecraft-patches/features/0089-Raytrace-Entity-Tracker.patch b/divinemc-server/minecraft-patches/features/0089-Raytrace-Entity-Tracker.patch index cee2bed..e2fda09 100644 --- a/divinemc-server/minecraft-patches/features/0089-Raytrace-Entity-Tracker.patch +++ b/divinemc-server/minecraft-patches/features/0089-Raytrace-Entity-Tracker.patch @@ -23,7 +23,7 @@ index a3290eb416ecb377d240bf334aef4e2b5e3bbefc..269c3312c1633faf48c1b471583ca71a double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1); if (rangeY != -1) { diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 44cd33cec38b1a2af304ec819b14124187011df1..ae8f7a1fdf85b9468d310123c77097df8c7054a4 100644 +index adea48cfde04df3107341075f414133ae37d986e..c1c8e235b9c096cd36c3e83b0831af7cb722cad2 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -145,7 +145,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter; @@ -35,7 +35,7 @@ index 44cd33cec38b1a2af304ec819b14124187011df1..ae8f7a1fdf85b9468d310123c77097df public static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur - Configurable entity base attributes // CraftBukkit start private static final int CURRENT_LEVEL = 2; -@@ -5475,4 +5475,47 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -5474,4 +5474,47 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return false; } // Purpur end - Ridables @@ -96,7 +96,7 @@ index 0159627e2c9a540d062073faf9018f5215e10866..26f6941dfbe0453ed5b091e408d84229 private static EntityType register(ResourceKey> key, EntityType.Builder builder) { return Registry.register(BuiltInRegistries.ENTITY_TYPE, key, builder.build(key)); diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java -index 18b670a1e6e62c3b79281e529c89f35b16427c69..5ed70f2f427f8cccaeab494b2f5c62442c288e53 100644 +index 05634e09200fa613b69aafe9b2505dbc9b5c54eb..80ce59b79896ff415cf3a93eb6ea3272f42c3d02 100644 --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java @@ -122,7 +122,6 @@ import net.minecraft.world.phys.AABB; @@ -159,7 +159,7 @@ index 18b670a1e6e62c3b79281e529c89f35b16427c69..5ed70f2f427f8cccaeab494b2f5c6244 // Purpur start - Burp delay if (this.burpDelay > 0 && --this.burpDelay == 0) { this.level().playSound(null, getX(), getY(), getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 1.0F, this.level().random.nextFloat() * 0.1F + 0.9F); -@@ -1467,6 +1504,7 @@ public abstract class Player extends LivingEntity { +@@ -1466,6 +1503,7 @@ public abstract class Player extends LivingEntity { if (this.containerMenu != null && this.hasContainerOpen()) { this.doCloseContainer(); } diff --git a/divinemc-server/minecraft-patches/features/0092-Leaves-Protocol-Core.patch b/divinemc-server/minecraft-patches/features/0092-Leaves-Protocol-Core.patch index 642ff50..4eff526 100644 --- a/divinemc-server/minecraft-patches/features/0092-Leaves-Protocol-Core.patch +++ b/divinemc-server/minecraft-patches/features/0092-Leaves-Protocol-Core.patch @@ -67,7 +67,7 @@ index b31a4edee0616a63026f7a4335205f2d99d2f641..0072f3f07b1962adc1766930bb9a2f70 this.tickables.get(i).run(); } diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 52f3c374c91f877b51b243b46cd05c5e2fc0face..d383532219bccb706bebbd3ef2923c70553d1a46 100644 +index 86470728c2d03063c4eb0c43cfe323e809cac846..cd43a45b7dfca2520972d2156df8b6069ce54f34 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -432,6 +432,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc @@ -91,10 +91,10 @@ index a7c4fad2b1cb0cbac742a18d37d688bb2663944e..b94243d293e805743453adf7b4fc8d85 bridge.removeChannel(channel); } diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index bc738535f67d789e9d240b245e9247e026b3c751..9d771e7fba94c09df602a249f58a9caf1d339bcf 100644 +index 42ab4f50d07539aafba120e863d5b9cfc5a436e8..e8fd78e2898931f65e783ad46b5b73ce3fbde235 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -3734,6 +3734,17 @@ public class ServerGamePacketListenerImpl +@@ -3676,6 +3676,17 @@ public class ServerGamePacketListenerImpl @Override public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { diff --git a/gradle.properties b/gradle.properties index 9b09d8b..64a92dd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group = org.bxteam.divinemc version=1.21.7-R0.1-SNAPSHOT mcVersion=1.21.7 -purpurRef=7dbe41536b8509e1867132778950c994a3e81040 +purpurRef=11c030a8f81b2f845a9f2749790692c2d152f284 experimental=false org.gradle.configuration-cache=true From 2c5f1ee9f37e97f3af15c760a2aaa6174ba67ce3 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 12 Jul 2025 23:51:57 +0300 Subject: [PATCH 36/67] fix branch name in releaseInfo.sh --- scripts/releaseInfo.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/releaseInfo.sh b/scripts/releaseInfo.sh index b253933..3a8fb53 100644 --- a/scripts/releaseInfo.sh +++ b/scripts/releaseInfo.sh @@ -48,7 +48,7 @@ mv divinemc-server/build/libs/divinemc-paperclip-"$version"-mojmap.jar "$jarName fi } >> $changelog -number=$(git log --oneline master ^"$(git describe --tags --abbrev=0)" | wc -l) +number=$(git log --oneline ver/1.21.7 ^"$(git describe --tags --abbrev=0)" | wc -l) git log --pretty='- [`%h`](https://github.com/BX-Team/DivineMC/commit/%H) %s' "-$number" >> $changelog { @@ -60,4 +60,3 @@ git log --pretty='- [`%h`](https://github.com/BX-Team/DivineMC/commit/%H) %s' "- echo "| SHA1 | $(sha1 "$jarName") |" echo "| SHA256 | $(sha256 "$jarName") |" } >> $changelog - From 650d06ae5cc55750cd0ed957cfe2b41359e381f9 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 13 Jul 2025 01:04:45 +0300 Subject: [PATCH 37/67] add back old linear impl; switch to AT's --- build-data/divinemc.at | 5 + divinemc-server/build.gradle.kts.patch | 3 +- ...h => 0096-Linear-region-file-format.patch} | 45 +- .../bxteam/divinemc/config/DivineConfig.java | 29 +- .../region/EnumRegionFileExtension.java | 5 +- .../region/{ => type}/BufferedRegionFile.java | 4 +- .../region/type/LinearRegionFile.java | 605 ++++++++++++++++++ 7 files changed, 648 insertions(+), 48 deletions(-) rename divinemc-server/minecraft-patches/features/{0096-Buffered-Linear-region-format.patch => 0096-Linear-region-file-format.patch} (90%) rename divinemc-server/src/main/java/org/bxteam/divinemc/region/{ => type}/BufferedRegionFile.java (99%) create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/type/LinearRegionFile.java diff --git a/build-data/divinemc.at b/build-data/divinemc.at index 016f220..dda3c44 100644 --- a/build-data/divinemc.at +++ b/build-data/divinemc.at @@ -15,6 +15,11 @@ public net.minecraft.world.entity.ai.sensing.Sensor timeToTick public net.minecraft.world.entity.animal.armadillo.Armadillo scuteTime public net.minecraft.world.entity.animal.frog.Tadpole getTicksLeftUntilAdult()I public net.minecraft.world.level.chunk.PaletteResize +public net.minecraft.world.level.chunk.storage.RegionFile getOversizedData(II)Lnet/minecraft/nbt/CompoundTag; +public net.minecraft.world.level.chunk.storage.RegionFile isOversized(II)Z +public net.minecraft.world.level.chunk.storage.RegionFile recalculateHeader()Z +public net.minecraft.world.level.chunk.storage.RegionFile setOversized(IIZ)V +public net.minecraft.world.level.chunk.storage.RegionFile write(Lnet/minecraft/world/level/ChunkPos;Ljava/nio/ByteBuffer;)V public net.minecraft.world.level.entity.EntityTickList entities public net.minecraft.world.level.levelgen.DensityFunctions$BlendAlpha public net.minecraft.world.level.levelgen.DensityFunctions$BlendDensity diff --git a/divinemc-server/build.gradle.kts.patch b/divinemc-server/build.gradle.kts.patch index 4540517..8658595 100644 --- a/divinemc-server/build.gradle.kts.patch +++ b/divinemc-server/build.gradle.kts.patch @@ -72,7 +72,7 @@ } } val log4jPlugins = sourceSets.create("log4jPlugins") { -@@ -156,10 +_,20 @@ +@@ -156,10 +_,21 @@ } dependencies { @@ -86,6 +86,7 @@ + } + implementation("com.github.luben:zstd-jni:1.5.7-3") + implementation("org.lz4:lz4-java:1.8.0") ++ implementation("net.openhft:zero-allocation-hashing:0.16") + // DivineMC end - Dependencies + implementation("ca.spottedleaf:concurrentutil:0.0.3") diff --git a/divinemc-server/minecraft-patches/features/0096-Buffered-Linear-region-format.patch b/divinemc-server/minecraft-patches/features/0096-Linear-region-file-format.patch similarity index 90% rename from divinemc-server/minecraft-patches/features/0096-Buffered-Linear-region-format.patch rename to divinemc-server/minecraft-patches/features/0096-Linear-region-file-format.patch index 2f42a2f..907250e 100644 --- a/divinemc-server/minecraft-patches/features/0096-Buffered-Linear-region-format.patch +++ b/divinemc-server/minecraft-patches/features/0096-Linear-region-file-format.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 11 Jul 2025 21:47:45 +0300 -Subject: [PATCH] Buffered Linear region format +Subject: [PATCH] Linear region file format diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java @@ -126,7 +126,7 @@ index 79d57ca8a7870a02e95562d89cbd4341d8282660..1156772217b139d54266f470b18d4a98 class PoiUpgrader extends WorldUpgrader.SimpleRegionStorageUpgrader { diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java -index 22f3aa1674664906e8ec45372d758d79017e3987..55eaf7a5d4ceb957717298991fecce0b81c0f377 100644 +index ae0a893498d0bfe90c14508f15b431d4885e06ff..00656cf8634e06f7ce1067ef7ba44edfb4519be3 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java @@ -22,7 +22,7 @@ import net.minecraft.util.profiling.jfr.JvmProfiler; @@ -138,24 +138,6 @@ index 22f3aa1674664906e8ec45372d758d79017e3987..55eaf7a5d4ceb957717298991fecce0b private static final Logger LOGGER = LogUtils.getLogger(); public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails private static final int SECTOR_BYTES = 4096; -@@ -130,7 +130,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - return this.recalculateCount.get(); - } - -- boolean recalculateHeader() throws IOException { -+ public boolean recalculateHeader() throws IOException { // DivineMC - Buffered Linear region format - if (!this.canRecalcHeader) { - return false; - } -@@ -794,7 +794,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - } - } - -- protected synchronized void write(ChunkPos chunkPos, ByteBuffer chunkData) throws IOException { -+ public synchronized void write(ChunkPos chunkPos, ByteBuffer chunkData) throws IOException { // DivineMC - Buffered Linear region format - int offsetIndex = getOffsetIndex(chunkPos); - int i = this.offsets.get(offsetIndex); - int sectorNumber = getSectorNumber(i); @@ -912,7 +912,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche } @@ -165,29 +147,6 @@ index 22f3aa1674664906e8ec45372d758d79017e3987..55eaf7a5d4ceb957717298991fecce0b regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count)); } // Paper end - rewrite chunk system -@@ -978,11 +978,11 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - return (x & 31) + (z & 31) * 32; - } - -- synchronized boolean isOversized(int x, int z) { -+ public synchronized boolean isOversized(int x, int z) { // DivineMC - Buffered Linear region format - return this.oversized[getChunkIndex(x, z)] == 1; - } - -- synchronized void setOversized(int x, int z, boolean oversized) throws IOException { -+ public synchronized void setOversized(int x, int z, boolean oversized) throws IOException { // DivineMC - Buffered Linear region format - final int offset = getChunkIndex(x, z); - boolean previous = this.oversized[offset] == 1; - this.oversized[offset] = (byte) (oversized ? 1 : 0); -@@ -1021,7 +1021,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - return this.path.getParent().resolve(this.path.getFileName().toString().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt"); - } - -- synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException { -+ public synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException { - Path file = getOversizedFile(x, z); - try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new java.util.zip.InflaterInputStream(Files.newInputStream(file))))) { - return net.minecraft.nbt.NbtIo.read((java.io.DataInput) out); diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java index 8d1174f25e0e90d0533970f4ddd8448442024936..ee797d6b3cd898cba1abd3422cb54b17eb4a639f 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 1b4303f..7fd8e16 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -12,6 +12,7 @@ import org.bukkit.configuration.MemoryConfiguration; import org.bxteam.divinemc.config.annotations.Experimental; import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy; import org.bxteam.divinemc.region.EnumRegionFileExtension; +import org.bxteam.divinemc.region.type.LinearRegionFile; import org.bxteam.divinemc.server.network.AsyncJoinHandler; import org.jetbrains.annotations.Nullable; import org.simpleyaml.configuration.comments.CommentType; @@ -599,6 +600,9 @@ public class DivineConfig { // Region Format public static EnumRegionFileExtension regionFileType = EnumRegionFileExtension.MCA; public static int linearCompressionLevel = 1; + public static int linearIoThreadCount = 6; + public static int linearIoFlushDelayMs = 100; + public static boolean linearUseVirtualThreads = true; // Sentry public static String sentryDsn = ""; @@ -649,18 +653,39 @@ public class DivineConfig { } private static void regionFileExtension() { - regionFileType = EnumRegionFileExtension.fromString(getString(ConfigCategory.MISC.key("region-format.type"), regionFileType.toString(), + EnumRegionFileExtension configuredType = EnumRegionFileExtension.fromString(getString(ConfigCategory.MISC.key("region-format.type"), regionFileType.toString(), "The type of region file format to use for storing chunk data.", "Valid values:", " - MCA: Default Minecraft region file format", - " - B_LINEAR: Buffered region file format")); + " - LINEAR: Linear region file format V2", + " - B_LINEAR: Buffered region file format (just uses Zstd)")); + + if (configuredType != null) { + regionFileType = configuredType; + } else { + LOGGER.warn("Invalid region file type: {}, resetting to default (MCA)", getString(ConfigCategory.MISC.key("region-format.type"), regionFileType.toString())); + regionFileType = EnumRegionFileExtension.MCA; + } + linearCompressionLevel = getInt(ConfigCategory.MISC.key("region-format.compression-level"), linearCompressionLevel, "The compression level to use for the linear region file format."); + linearIoThreadCount = getInt(ConfigCategory.MISC.key("region-format.linear-io-thread-count"), linearIoThreadCount, + "The number of threads to use for IO operations."); + linearIoFlushDelayMs = getInt(ConfigCategory.MISC.key("region-format.linear-io-flush-delay-ms"), linearIoFlushDelayMs, + "The delay in milliseconds to wait before flushing IO operations."); + linearUseVirtualThreads = getBoolean(ConfigCategory.MISC.key("region-format.linear-use-virtual-threads"), linearUseVirtualThreads, + "Whether to use virtual threads for IO operations that was introduced in Java 21."); if (linearCompressionLevel > 22 || linearCompressionLevel < 1) { LOGGER.warn("Invalid linear compression level: {}, resetting to default (1)", linearCompressionLevel); linearCompressionLevel = 1; } + + if (regionFileType == EnumRegionFileExtension.LINEAR) { + LinearRegionFile.SAVE_DELAY_MS = linearIoFlushDelayMs; + LinearRegionFile.SAVE_THREAD_MAX_COUNT = linearIoThreadCount; + LinearRegionFile.USE_VIRTUAL_THREAD = linearUseVirtualThreads; + } } private static void sentrySettings() { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/EnumRegionFileExtension.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/EnumRegionFileExtension.java index 99e9eff..17eef9a 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/EnumRegionFileExtension.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/EnumRegionFileExtension.java @@ -2,10 +2,13 @@ package org.bxteam.divinemc.region; import net.minecraft.world.level.chunk.storage.RegionFile; import org.bxteam.divinemc.config.DivineConfig; +import org.bxteam.divinemc.region.type.BufferedRegionFile; +import org.bxteam.divinemc.region.type.LinearRegionFile; import org.jetbrains.annotations.Nullable; public enum EnumRegionFileExtension { - MCA("mca", "mca" , (info) -> new RegionFile(info.info(), info.filePath(), info.folder(), info.sync())), + MCA("mca", "mca", (info) -> new RegionFile(info.info(), info.filePath(), info.folder(), info.sync())), + LINEAR("linear", "linear", (info) -> new LinearRegionFile(info.info(), info.filePath(), info.folder(), info.sync(), DivineConfig.MiscCategory.linearCompressionLevel)), B_LINEAR("b_linear", "b_linear", (info) -> new BufferedRegionFile(info.filePath(), DivineConfig.MiscCategory.linearCompressionLevel)); private final String name; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferedRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java similarity index 99% rename from divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferedRegionFile.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java index bd25e6f..5f773dd 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferedRegionFile.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java @@ -1,10 +1,12 @@ -package org.bxteam.divinemc.region; +package org.bxteam.divinemc.region.type; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import net.jpountz.xxhash.XXHash32; import net.jpountz.xxhash.XXHashFactory; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.ChunkPos; +import org.bxteam.divinemc.region.BufferReleaser; +import org.bxteam.divinemc.region.IRegionFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/LinearRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/LinearRegionFile.java new file mode 100644 index 0000000..5b71ff5 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/LinearRegionFile.java @@ -0,0 +1,605 @@ +package org.bxteam.divinemc.region.type; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.github.luben.zstd.ZstdInputStream; +import com.github.luben.zstd.ZstdOutputStream; +import net.jpountz.lz4.LZ4Compressor; +import net.jpountz.lz4.LZ4Factory; +import net.jpountz.lz4.LZ4FastDecompressor; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.storage.RegionFileVersion; +import net.minecraft.world.level.chunk.storage.RegionStorageInfo; +import net.openhft.hashing.LongHashFunction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bxteam.divinemc.region.IRegionFile; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; + +public class LinearRegionFile implements IRegionFile { + private static final long SUPERBLOCK = 0xc3ff13183cca9d9aL; + private static final byte VERSION = 3; + private static final int HEADER_SIZE = 27; + private static final int FOOTER_SIZE = 8; + private static final Logger LOGGER = LogManager.getLogger(LinearRegionFile.class.getSimpleName()); + private static final Object saveLock = new Object(); + + public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; + public static int SAVE_THREAD_MAX_COUNT = 6; + public static int SAVE_DELAY_MS = 100; + public static boolean USE_VIRTUAL_THREAD = true; + private static int activeSaveThreads = 0; + + public final ReentrantLock fileLock = new ReentrantLock(true); + public Path regionFile; + public boolean regionFileOpen = false; + + private final byte[][] buffer = new byte[1024][]; + private final int[] bufferUncompressedSize = new int[1024]; + private final long[] chunkTimestamps = new long[1024]; + private final Object markedToSaveLock = new Object(); + private final LZ4Compressor compressor; + private final LZ4FastDecompressor decompressor; + private final int compressionLevel; + private final Thread bindThread; + private final java.util.concurrent.atomic.AtomicInteger recalculateCount = new java.util.concurrent.atomic.AtomicInteger(); + + private byte[][] bucketBuffers; + private boolean markedToSave = false; + private boolean close = false; + private int gridSize = 8; + private int bucketSize = 4; + + public LinearRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync, int compressionLevel) throws IOException { + this(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync, compressionLevel); + } + + public LinearRegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync, int compressionLevel) throws IOException { + Runnable flushCheck = () -> { + while (!close) { + synchronized (saveLock) { + if (markedToSave && activeSaveThreads < SAVE_THREAD_MAX_COUNT) { + activeSaveThreads++; + Runnable flushOperation = () -> { + try { + flush(); + } catch (IOException ex) { + LOGGER.error("Region file {} flush failed", this.regionFile.toAbsolutePath(), ex); + } finally { + synchronized (saveLock) { + activeSaveThreads--; + } + } + }; + + Thread saveThread = USE_VIRTUAL_THREAD ? + Thread.ofVirtual().name("Linear IO - " + LinearRegionFile.this.hashCode()).unstarted(flushOperation) : + Thread.ofPlatform().name("Linear IO - " + LinearRegionFile.this.hashCode()).unstarted(flushOperation); + saveThread.setPriority(Thread.NORM_PRIORITY - 3); + saveThread.start(); + } + } + LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(SAVE_DELAY_MS)); + } + }; + this.bindThread = USE_VIRTUAL_THREAD ? Thread.ofVirtual().unstarted(flushCheck) : Thread.ofPlatform().unstarted(flushCheck); + this.bindThread.setName("Linear IO Schedule - " + this.hashCode()); + this.regionFile = path; + this.compressionLevel = compressionLevel; + + this.compressor = LZ4Factory.fastestInstance().fastCompressor(); + this.decompressor = LZ4Factory.fastestInstance().fastDecompressor(); + } + + public Path getRegionFile() { + return this.regionFile; + } + + public ReentrantLock getFileLock() { + return this.fileLock; + } + + public Path getPath() { + return this.regionFile; + } + + public int getRecalculateCount() { + return this.recalculateCount.get(); + } + + public boolean recalculateHeader() { + return false; + } + + private int chunkToBucketIdx(int chunkX, int chunkZ) { + int bx = chunkX / bucketSize, bz = chunkZ / bucketSize; + return bx * gridSize + bz; + } + + private void openBucket(int chunkX, int chunkZ) { + chunkX = Math.floorMod(chunkX, 32); + chunkZ = Math.floorMod(chunkZ, 32); + int idx = chunkToBucketIdx(chunkX, chunkZ); + + if (bucketBuffers == null) return; + if (bucketBuffers[idx] != null) { + try { + ByteArrayInputStream bucketByteStream = new ByteArrayInputStream(bucketBuffers[idx]); + ZstdInputStream zstdStream = new ZstdInputStream(bucketByteStream); + ByteBuffer bucketBuffer = ByteBuffer.wrap(zstdStream.readAllBytes()); + + int bx = chunkX / bucketSize, bz = chunkZ / bucketSize; + + for (int cx = 0; cx < 32 / gridSize; cx++) { + for (int cz = 0; cz < 32 / gridSize; cz++) { + int chunkIndex = (bx * (32 / gridSize) + cx) + (bz * (32 / gridSize) + cz) * 32; + + int chunkSize = bucketBuffer.getInt(); + long timestamp = bucketBuffer.getLong(); + this.chunkTimestamps[chunkIndex] = timestamp; + + if (chunkSize > 0) { + byte[] chunkData = new byte[chunkSize - 8]; + bucketBuffer.get(chunkData); + + int maxCompressedLength = this.compressor.maxCompressedLength(chunkData.length); + byte[] compressed = new byte[maxCompressedLength]; + int compressedLength = this.compressor.compress(chunkData, 0, chunkData.length, compressed, 0, maxCompressedLength); + byte[] finalCompressed = new byte[compressedLength]; + System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength); + + if (chunkX == cx && chunkZ == cz) { + this.buffer[chunkIndex] = finalCompressed; + this.bufferUncompressedSize[chunkIndex] = chunkData.length; + return; + } + this.buffer[chunkIndex] = finalCompressed; + this.bufferUncompressedSize[chunkIndex] = chunkData.length; + } + } + } + } catch (IOException ex) { + LOGGER.error("Region file corrupted: {} bucket: {}", regionFile, idx); + MinecraftServer.getServer().safeShutdown(true, false); + } + bucketBuffers[idx] = null; + } + } + + private synchronized void openRegionFile() { + if (regionFileOpen) return; + regionFileOpen = true; + + File regionFile = new File(this.regionFile.toString()); + + if(!regionFile.canRead()) { + this.bindThread.start(); + return; + } + + try { + byte[] fileContent = Files.readAllBytes(this.regionFile); + ByteBuffer buffer = ByteBuffer.wrap(fileContent); + + long superBlock = buffer.getLong(); + if (superBlock != SUPERBLOCK) + throw new RuntimeException("Invalid superblock: " + superBlock + " file " + this.regionFile); + + byte version = buffer.get(); + if (version == 1 || version == 2) { + parseLinearV1(buffer); + } else if (version == 3) { + parseLinearV2(buffer); + } else { + throw new RuntimeException("Invalid version: " + version + " file " + this.regionFile); + } + + this.bindThread.start(); + } catch (IOException e) { + throw new RuntimeException("Failed to open region file " + this.regionFile, e); + } + } + + private void parseLinearV1(ByteBuffer buffer) throws IOException { + final int HEADER_SIZE = 32; + final int FOOTER_SIZE = 8; + + // Skip newestTimestamp (Long) + Compression level (Byte) + Chunk count (Short): Unused. + buffer.position(buffer.position() + 11); + + int dataCount = buffer.getInt(); + long fileLength = this.regionFile.toFile().length(); + if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) { + throw new IOException("Invalid file length: " + this.regionFile + " " + fileLength + " " + (HEADER_SIZE + dataCount + FOOTER_SIZE)); + } + + buffer.position(buffer.position() + 8); // Skip data hash (Long): Unused. + + byte[] rawCompressed = new byte[dataCount]; + buffer.get(rawCompressed); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(rawCompressed); + ZstdInputStream zstdInputStream = new ZstdInputStream(byteArrayInputStream); + ByteBuffer decompressedBuffer = ByteBuffer.wrap(zstdInputStream.readAllBytes()); + + int[] starts = new int[1024]; + for (int i = 0; i < 1024; i++) { + starts[i] = decompressedBuffer.getInt(); + decompressedBuffer.getInt(); // Skip timestamps (Int): Unused. + } + + for (int i = 0; i < 1024; i++) { + if (starts[i] > 0) { + int size = starts[i]; + byte[] chunkData = new byte[size]; + decompressedBuffer.get(chunkData); + + int maxCompressedLength = this.compressor.maxCompressedLength(size); + byte[] compressed = new byte[maxCompressedLength]; + int compressedLength = this.compressor.compress(chunkData, 0, size, compressed, 0, maxCompressedLength); + byte[] finalCompressed = new byte[compressedLength]; + System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength); + + this.buffer[i] = finalCompressed; + this.bufferUncompressedSize[i] = size; + this.chunkTimestamps[i] = getTimestamp(); // Use current timestamp as we don't have the original + } + } + } + + private void parseLinearV2(ByteBuffer buffer) throws IOException { + buffer.getLong(); // Skip newestTimestamp (Long) + gridSize = buffer.get(); + if (gridSize != 1 && gridSize != 2 && gridSize != 4 && gridSize != 8 && gridSize != 16 && gridSize != 32) + throw new RuntimeException("Invalid grid size: " + gridSize + " file " + this.regionFile); + bucketSize = 32 / gridSize; + + buffer.getInt(); // Skip region_x (Int) + buffer.getInt(); // Skip region_z (Int) + + boolean[] chunkExistenceBitmap = deserializeExistenceBitmap(buffer); + + while (true) { + byte featureNameLength = buffer.get(); + if (featureNameLength == 0) break; + byte[] featureNameBytes = new byte[featureNameLength]; + buffer.get(featureNameBytes); + String featureName = new String(featureNameBytes); + int featureValue = buffer.getInt(); + // System.out.println("NBT Feature: " + featureName + " = " + featureValue); + } + + int[] bucketSizes = new int[gridSize * gridSize]; + byte[] bucketCompressionLevels = new byte[gridSize * gridSize]; + long[] bucketHashes = new long[gridSize * gridSize]; + for (int i = 0; i < gridSize * gridSize; i++) { + bucketSizes[i] = buffer.getInt(); + bucketCompressionLevels[i] = buffer.get(); + bucketHashes[i] = buffer.getLong(); + } + + bucketBuffers = new byte[gridSize * gridSize][]; + for (int i = 0; i < gridSize * gridSize; i++) { + if (bucketSizes[i] > 0) { + bucketBuffers[i] = new byte[bucketSizes[i]]; + buffer.get(bucketBuffers[i]); + long rawHash = LongHashFunction.xx().hashBytes(bucketBuffers[i]); + if (rawHash != bucketHashes[i]) throw new IOException("Region file hash incorrect " + this.regionFile); + } + } + + long footerSuperBlock = buffer.getLong(); + if (footerSuperBlock != SUPERBLOCK) + throw new IOException("Footer superblock invalid " + this.regionFile); + } + + @Override + public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) throws IOException { + final DataOutputStream out = this.getChunkDataOutputStream(pos); + + return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData( + data, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE, + out, regionFile -> out.close() + ); + } + + private synchronized void markToSave() { + synchronized(markedToSaveLock) { + markedToSave = true; + } + } + + private synchronized boolean isMarkedToSave() { + synchronized(markedToSaveLock) { + if(markedToSave) { + markedToSave = false; + return true; + } + return false; + } + } + + public synchronized boolean doesChunkExist(ChunkPos pos) throws Exception { + openRegionFile(); + throw new Exception("doesChunkExist is a stub"); + } + + public synchronized boolean hasChunk(ChunkPos pos) { + openRegionFile(); + openBucket(pos.x, pos.z); + return this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] > 0; + } + + public synchronized void write(ChunkPos pos, ByteBuffer buffer) { + openRegionFile(); + openBucket(pos.x, pos.z); + try { + byte[] b = toByteArray(new ByteArrayInputStream(buffer.array())); + int uncompressedSize = b.length; + + if (uncompressedSize > MAX_CHUNK_SIZE) { + LOGGER.error("Chunk dupe attempt {}", this.regionFile); + clear(pos); + } else { + int maxCompressedLength = this.compressor.maxCompressedLength(b.length); + byte[] compressed = new byte[maxCompressedLength]; + int compressedLength = this.compressor.compress(b, 0, b.length, compressed, 0, maxCompressedLength); + b = new byte[compressedLength]; + System.arraycopy(compressed, 0, b, 0, compressedLength); + + int index = getChunkIndex(pos.x, pos.z); + this.buffer[index] = b; + this.chunkTimestamps[index] = getTimestamp(); + this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize; + } + } catch (IOException e) { + LOGGER.error("Chunk write IOException {} {}", e, this.regionFile); + } + markToSave(); + } + + public DataOutputStream getChunkDataOutputStream(ChunkPos pos) { + openRegionFile(); + openBucket(pos.x, pos.z); + return new DataOutputStream(new BufferedOutputStream(new LinearRegionFile.ChunkBuffer(pos))); + } + + @Nullable + public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) { + openRegionFile(); + openBucket(pos.x, pos.z); + + if(this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) { + byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]]; + this.decompressor.decompress(this.buffer[getChunkIndex(pos.x, pos.z)], 0, content, 0, bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]); + return new DataInputStream(new ByteArrayInputStream(content)); + } + return null; + } + + public synchronized void clear(ChunkPos pos) { + openRegionFile(); + openBucket(pos.x, pos.z); + int i = getChunkIndex(pos.x, pos.z); + this.buffer[i] = null; + this.bufferUncompressedSize[i] = 0; + this.chunkTimestamps[i] = 0; + markToSave(); + } + + public synchronized void close() throws IOException { + openRegionFile(); + close = true; + try { + flush(); + } catch(IOException e) { + throw new IOException("Region flush IOException " + e + " " + this.regionFile); + } + } + + public synchronized void flush() throws IOException { + if (!isMarkedToSave()) return; + + openRegionFile(); + + long timestamp = getTimestamp(); + + long writeStart = System.nanoTime(); + File tempFile = new File(regionFile.toString() + ".tmp"); + FileOutputStream fileStream = new FileOutputStream(tempFile); + DataOutputStream dataStream = new DataOutputStream(fileStream); + + dataStream.writeLong(SUPERBLOCK); + dataStream.writeByte(VERSION); + dataStream.writeLong(timestamp); + dataStream.writeByte(gridSize); + + String fileName = regionFile.getFileName().toString(); + String[] parts = fileName.split("\\."); + int regionX = 0; + int regionZ = 0; + try { + if (parts.length >= 4) { + regionX = Integer.parseInt(parts[1]); + regionZ = Integer.parseInt(parts[2]); + } else { + LOGGER.warn("Unexpected file name format: {}", fileName); + } + } catch (NumberFormatException e) { + LOGGER.error("Failed to parse region coordinates from file name: {}", fileName, e); + } + + dataStream.writeInt(regionX); + dataStream.writeInt(regionZ); + + boolean[] chunkExistenceBitmap = new boolean[1024]; + for (int i = 0; i < 1024; i++) { + chunkExistenceBitmap[i] = (this.bufferUncompressedSize[i] > 0); + } + writeSerializedExistenceBitmap(dataStream, chunkExistenceBitmap); + + writeNBTFeatures(dataStream); + + int bucketMisses = 0; + byte[][] buckets = new byte[gridSize * gridSize][]; + for (int bx = 0; bx < gridSize; bx++) { + for (int bz = 0; bz < gridSize; bz++) { + if (bucketBuffers != null && bucketBuffers[bx * gridSize + bz] != null) { + buckets[bx * gridSize + bz] = bucketBuffers[bx * gridSize + bz]; + continue; + } + bucketMisses++; + + ByteArrayOutputStream bucketStream = new ByteArrayOutputStream(); + ZstdOutputStream zstdStream = new ZstdOutputStream(bucketStream, this.compressionLevel); + DataOutputStream bucketDataStream = new DataOutputStream(zstdStream); + + boolean hasData = false; + for (int cx = 0; cx < 32 / gridSize; cx++) { + for (int cz = 0; cz < 32 / gridSize; cz++) { + int chunkIndex = (bx * 32 / gridSize + cx) + (bz * 32 / gridSize + cz) * 32; + if (this.bufferUncompressedSize[chunkIndex] > 0) { + hasData = true; + byte[] chunkData = new byte[this.bufferUncompressedSize[chunkIndex]]; + this.decompressor.decompress(this.buffer[chunkIndex], 0, chunkData, 0, this.bufferUncompressedSize[chunkIndex]); + bucketDataStream.writeInt(chunkData.length + 8); + bucketDataStream.writeLong(this.chunkTimestamps[chunkIndex]); + bucketDataStream.write(chunkData); + } else { + bucketDataStream.writeInt(0); + bucketDataStream.writeLong(this.chunkTimestamps[chunkIndex]); + } + } + } + bucketDataStream.close(); + + if (hasData) { + buckets[bx * gridSize + bz] = bucketStream.toByteArray(); + } + } + } + + for (int i = 0; i < gridSize * gridSize; i++) { + dataStream.writeInt(buckets[i] != null ? buckets[i].length : 0); + dataStream.writeByte(this.compressionLevel); + long rawHash = 0; + if (buckets[i] != null) { + rawHash = LongHashFunction.xx().hashBytes(buckets[i]); + } + dataStream.writeLong(rawHash); + } + + for (int i = 0; i < gridSize * gridSize; i++) { + if (buckets[i] != null) { + dataStream.write(buckets[i]); + } + } + + dataStream.writeLong(SUPERBLOCK); + + dataStream.flush(); + fileStream.getFD().sync(); + fileStream.getChannel().force(true); // Ensure atomicity on Btrfs + dataStream.close(); + + fileStream.close(); + Files.move(tempFile.toPath(), this.regionFile, StandardCopyOption.REPLACE_EXISTING); + } + + private void writeNBTFeatures(DataOutputStream dataStream) throws IOException { + // writeNBTFeature(dataStream, "example", 1); + dataStream.writeByte(0); // End of NBT features + } + + private void writeNBTFeature(DataOutputStream dataStream, String featureName, int featureValue) throws IOException { + byte[] featureNameBytes = featureName.getBytes(); + dataStream.writeByte(featureNameBytes.length); + dataStream.write(featureNameBytes); + dataStream.writeInt(featureValue); + } + + private boolean[] deserializeExistenceBitmap(ByteBuffer buffer) { + boolean[] result = new boolean[1024]; + for (int i = 0; i < 128; i++) { + byte b = buffer.get(); + for (int j = 0; j < 8; j++) { + result[i * 8 + j] = ((b >> (7 - j)) & 1) == 1; + } + } + return result; + } + + private void writeSerializedExistenceBitmap(DataOutputStream out, boolean[] bitmap) throws IOException { + for (int i = 0; i < 128; i++) { + byte b = 0; + for (int j = 0; j < 8; j++) { + if (bitmap[i * 8 + j]) { + b |= (1 << (7 - j)); + } + } + out.writeByte(b); + } + } + + private byte[] toByteArray(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] tempBuffer = new byte[4096]; + + int length; + while ((length = in.read(tempBuffer)) >= 0) { + out.write(tempBuffer, 0, length); + } + + return out.toByteArray(); + } + + private static int getChunkIndex(int x, int z) { + return (x & 31) + ((z & 31) << 5); + } + + private static int getTimestamp() { + return (int) (System.currentTimeMillis() / 1000L); + } + + public void setOversized(int x, int z, boolean something) { } + + public CompoundTag getOversizedData(int x, int z) throws IOException { + throw new IOException("getOversizedData is a stub " + this.regionFile); + } + + public boolean isOversized(int x, int z) { + return false; + } + + private class ChunkBuffer extends ByteArrayOutputStream { + private final ChunkPos pos; + + public ChunkBuffer(ChunkPos chunkcoordintpair) { + super(); + this.pos = chunkcoordintpair; + } + + public void close() throws IOException { + ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); + LinearRegionFile.this.write(this.pos, bytebuffer); + } + } +} From 6e46113429263845e59fbcfa228e114df1340ea0 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 13 Jul 2025 01:26:03 +0300 Subject: [PATCH 38/67] update culling worker --- .../java/dev/tr7zw/entityculling/CullTask.java | 16 ++-------------- .../org/bxteam/divinemc/config/DivineConfig.java | 12 ++++++++++-- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java b/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java index b1d5551..93cb42b 100644 --- a/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java +++ b/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java @@ -10,7 +10,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.bxteam.divinemc.config.DivineConfig; -import org.bxteam.divinemc.spark.ThreadDumperRegistry; +import org.bxteam.divinemc.util.NamedAgnosticThreadFactory; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -33,19 +33,7 @@ public class CullTask implements Runnable { private final Vec3d aabbMin = new Vec3d(0, 0, 0); private final Vec3d aabbMax = new Vec3d(0, 0, 0); - private static final Executor backgroundWorker = Executors.newCachedThreadPool(task -> { - final TickThread worker = new TickThread("Raytrace Entity Tracker Thread") { - @Override - public void run() { - task.run(); - } - }; - - worker.setDaemon(true); - ThreadDumperRegistry.REGISTRY.add(worker.getName()); - - return worker; - }); + private static final Executor backgroundWorker = Executors.newFixedThreadPool(DivineConfig.MiscCategory.retThreads, new NamedAgnosticThreadFactory<>("Raytrace Entity Tracker Thread", TickThread::new, DivineConfig.MiscCategory.retThreadsPriority)); private final Executor worker; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 7fd8e16..27ba37f 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -612,6 +612,8 @@ public class DivineConfig { // Raytrace Entity Tracker @Experimental("Raytrace Entity Tracker") public static boolean retEnabled = false; + public static int retThreads = 2; + public static int retThreadsPriority = Thread.NORM_PRIORITY + 2; public static boolean retSkipMarkerArmorStands = true; public static int retCheckIntervalMs = 10; public static int retTracingDistance = 48; @@ -702,6 +704,12 @@ public class DivineConfig { private static void ret() { retEnabled = getBoolean(ConfigCategory.MISC.key("raytrace-entity-tracker.enabled"), retEnabled, "Raytrace Entity Tracker uses async ray-tracing to untrack entities players cannot see. Implementation of EntityCulling mod by tr7zw."); + retThreads = getInt(ConfigCategory.MISC.key("raytrace-entity-tracker.threads"), retThreads, + "The number of threads to use for raytrace entity tracker."); + retThreadsPriority = getInt(ConfigCategory.MISC.key("raytrace-entity-tracker.threads-priority"), retThreadsPriority, + "The priority of the threads used for raytrace entity tracker.", + "0 - lowest, 10 - highest, 5 - normal"); + retSkipMarkerArmorStands = getBoolean(ConfigCategory.MISC.key("raytrace-entity-tracker.skip-marker-armor-stands"), retSkipMarkerArmorStands, "Whether to skip tracing entities with marker armor stand"); retCheckIntervalMs = getInt(ConfigCategory.MISC.key("raytrace-entity-tracker.check-interval-ms"), retCheckIntervalMs, @@ -755,8 +763,8 @@ public class DivineConfig { private static void networkSettings() { optimizeNonFlushPacketSending = getBoolean(ConfigCategory.NETWORK.key("general.optimize-non-flush-packet-sending"), optimizeNonFlushPacketSending, "Optimizes non-flush packet sending by using Netty's lazyExecute method to avoid expensive thread wakeup calls when scheduling packet operations.", - "", - "NOTE: This option is NOT compatible with ProtocolLib and may cause issues with other plugins that modify packet handling!"); + "", + "NOTE: This option is NOT compatible with ProtocolLib and may cause issues with other plugins that modify packet handling!"); disableDisconnectSpam = getBoolean(ConfigCategory.NETWORK.key("general.disable-disconnect-spam"), disableDisconnectSpam, "Prevents players being disconnected by 'disconnect.spam' when sending too many chat packets"); dontRespondPingBeforeStart = getBoolean(ConfigCategory.NETWORK.key("general.dont-respond-ping-before-start"), dontRespondPingBeforeStart, From 219f954694dc5935f8fe8693349e95fc8992ed8c Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 13 Jul 2025 01:29:07 +0300 Subject: [PATCH 39/67] add hyphen to ServerLevel Tick Worker --- .../divinemc/server/ServerLevelTickExecutorThreadFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java b/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java index 20e49f5..d7d2785 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java @@ -9,12 +9,12 @@ public class ServerLevelTickExecutorThreadFactory implements ThreadFactory { public ServerLevelTickExecutorThreadFactory(String worldName) { this.worldName = worldName; - ThreadDumperRegistry.REGISTRY.add(worldName + "ServerLevel Tick Worker"); + ThreadDumperRegistry.REGISTRY.add(worldName + " - ServerLevel Tick Worker"); } @Override public Thread newThread(Runnable runnable) { - TickThread.ServerLevelTickThread tickThread = new TickThread.ServerLevelTickThread(runnable, this.worldName + "ServerLevel Tick Worker"); + TickThread.ServerLevelTickThread tickThread = new TickThread.ServerLevelTickThread(runnable, this.worldName + " - ServerLevel Tick Worker"); if (tickThread.isDaemon()) { tickThread.setDaemon(false); From 3e9177755a1ebb76118e06d66e8d9a1fd2314dfb Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 13 Jul 2025 17:54:22 +0300 Subject: [PATCH 40/67] rebuild --- .../features/0003-Completely-remove-Mojang-profiler.patch | 6 +++--- .../minecraft-patches/features/0017-Fix-MC-119417.patch | 4 ++-- .../0078-SparklyPaper-Parallel-world-ticking.patch | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch index 6e13845..f4d490c 100644 --- a/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch +++ b/divinemc-server/minecraft-patches/features/0003-Completely-remove-Mojang-profiler.patch @@ -1479,7 +1479,7 @@ index 3c7159d0981c948e71a5612ba4083accb5849ed4..5f2c27800f047f128857044493a6d932 for (Entity entity : passengerEntity.getPassengers()) { this.tickPassenger(passengerEntity, entity, isActive); // Paper - EAR 2 diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index ba9e1f5963aeda8b5ed52c7daaa2a9fe62006d3b..9a296776480af489561eb19c6ed18d9558ee746a 100644 +index f17f54c93d3a10dbae9e2316849667e647904777..6362a448b19af256b8e5f6c2ffecb1687f1bc3e2 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -106,8 +106,6 @@ import net.minecraft.util.HashOps; @@ -1491,7 +1491,7 @@ index ba9e1f5963aeda8b5ed52c7daaa2a9fe62006d3b..9a296776480af489561eb19c6ed18d95 import net.minecraft.world.Container; import net.minecraft.world.Difficulty; import net.minecraft.world.InteractionHand; -@@ -1437,14 +1435,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -1446,14 +1444,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc this.unsetRemoved(); */ // CraftBukkit end @@ -1506,7 +1506,7 @@ index ba9e1f5963aeda8b5ed52c7daaa2a9fe62006d3b..9a296776480af489561eb19c6ed18d95 // CraftBukkit start this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds LevelData worlddata = level.getLevelData(); -@@ -1462,7 +1456,6 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -1471,7 +1465,6 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc this.connection.internalTeleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); // CraftBukkit - use internal teleport without event this.connection.resetPosition(); level.addDuringTeleport(this); diff --git a/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch b/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch index f333219..4a6caa9 100644 --- a/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch +++ b/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Fix MC-119417 Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-119417 diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 8a8d72fa46f4eff31e06e8b1756d286f7f1b07a6..b75d2d2746c3e7b12f65b0bcb559cd7e0ce7ebf8 100644 +index f5ef04f2f9324f8b7168bafb02acc74629df6086..1431a2e386bee22ec10365a38ead349a398d551f 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -2218,6 +2218,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -2227,6 +2227,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, gameMode.getId())); if (gameMode == GameType.SPECTATOR) { this.removeEntitiesOnShoulder(); diff --git a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch index 87881bb..a71535f 100644 --- a/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0078-SparklyPaper-Parallel-world-ticking.patch @@ -460,7 +460,7 @@ index 3c1795eb56900cd80cfec38bd1d922d566463ecb..07b9a2529be69bf8158528e996e7ddb9 // Paper start - extra debug info if (entity.valid) { diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index c33dbe22a74576935c1a18450502c4ec8d83a4c3..86470728c2d03063c4eb0c43cfe323e809cac846 100644 +index 1431a2e386bee22ec10365a38ead349a398d551f..77d1cab278a13e08ba8096af2c683b5042cc1574 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -431,6 +431,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc @@ -479,7 +479,7 @@ index c33dbe22a74576935c1a18450502c4ec8d83a4c3..86470728c2d03063c4eb0c43cfe323e8 // CraftBukkit start if (this.joining) { this.joining = false; -@@ -1425,6 +1427,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -1434,6 +1436,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc return this; } else { // CraftBukkit start @@ -487,7 +487,7 @@ index c33dbe22a74576935c1a18450502c4ec8d83a4c3..86470728c2d03063c4eb0c43cfe323e8 /* this.isChangingDimension = true; LevelData levelData = level.getLevelData(); -@@ -1770,6 +1773,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -1779,6 +1782,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc return OptionalInt.empty(); } else { // CraftBukkit start @@ -500,7 +500,7 @@ index c33dbe22a74576935c1a18450502c4ec8d83a4c3..86470728c2d03063c4eb0c43cfe323e8 this.containerMenu = abstractContainerMenu; // Moved up if (!this.isImmobile()) this.connection -@@ -1834,6 +1843,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -1843,6 +1852,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc } @Override public void closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { From 309a337698428e7518f2587486e59df88c47a92f Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 13 Jul 2025 18:02:02 +0300 Subject: [PATCH 41/67] add jd for buffered --- .../divinemc/region/type/BufferedRegionFile.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java index 5f773dd..45b7b93 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java @@ -20,6 +20,22 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.atomic.AtomicInteger; +/** + * A buffered region file implementation that provides efficient chunk storage and retrieval + * with compression, checksums, and automatic compaction capabilities. + * + *

This implementation includes: + *

    + *
  • Zstandard compression for chunk data
  • + *
  • XXHash32 checksums for data integrity verification
  • + *
  • Automatic file compaction when fragmentation exceeds thresholds
  • + *
  • Thread-safe operations with read-write locks
  • + *
  • Direct ByteBuffer usage for memory efficiency
  • + *
+ * + *

For conversion tools between MCA and buffered region file formats, see: + * LinearRegionFileFormatTools + */ public class BufferedRegionFile implements IRegionFile { private static final double AUTO_COMPACT_PERCENT = 3.0 / 5.0; // 60% private static final long AUTO_COMPACT_SIZE = 1024 * 1024; // 1 MiB From 99374ee560e542c5bb046159f0d24eccdbb4ead4 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 13 Jul 2025 19:58:40 +0300 Subject: [PATCH 42/67] dump pwt threads only if enabled --- ...-SparklyPaper-Parallel-world-ticking.patch | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/divinemc-server/paper-patches/features/0020-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/paper-patches/features/0020-SparklyPaper-Parallel-world-ticking.patch index 2ccad76..ed685e9 100644 --- a/divinemc-server/paper-patches/features/0020-SparklyPaper-Parallel-world-ticking.patch +++ b/divinemc-server/paper-patches/features/0020-SparklyPaper-Parallel-world-ticking.patch @@ -627,26 +627,28 @@ index e4e2e42d0ca25df7fe9f2dd4275610e45fcb2c84..93bf7beab3b00973a19e51d48a9dfb26 // Paper start - name threads according to running plugin final String nameBefore = thread.getName(); diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java -index dffff76bf6df39dd26892edc2b4988fafab282e7..26659624c5fcad5f4e05fd9174dab89118ab7be7 100644 +index dffff76bf6df39dd26892edc2b4988fafab282e7..1a26dac92cb48bf892f7524a58e1031e5f83bcfb 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -112,6 +112,21 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre +@@ -112,6 +112,23 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.threadId(), Integer.MAX_VALUE), logger); logger.log(Level.SEVERE, "------------------------------"); + // DivineMC start - Dump Parallel World Ticking thread -+ logger.log(Level.SEVERE, "Parallel world ticking thread dump"); -+ for (Thread thread : org.apache.commons.lang3.ThreadUtils.getAllThreads()) { -+ if (MinecraftServer.getServer().serverThread == thread || thread instanceof WatchdogThread) { -+ continue; -+ } -+ if (thread instanceof ca.spottedleaf.moonrise.common.util.TickThread tickThread) { -+ if (tickThread instanceof ServerLevelTickThread tickThread1) { -+ WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(tickThread1.threadId(), Integer.MAX_VALUE), logger); ++ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableParallelWorldTicking) { ++ logger.log(Level.SEVERE, "Parallel world ticking thread dump"); ++ for (Thread thread : org.apache.commons.lang3.ThreadUtils.getAllThreads()) { ++ if (MinecraftServer.getServer().serverThread == thread || thread instanceof WatchdogThread) { ++ continue; ++ } ++ if (thread instanceof ca.spottedleaf.moonrise.common.util.TickThread tickThread) { ++ if (tickThread instanceof ServerLevelTickThread tickThread1) { ++ WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(tickThread1.threadId(), Integer.MAX_VALUE), logger); ++ } + } + } ++ logger.log(Level.SEVERE, "------------------------------"); + } -+ logger.log(Level.SEVERE, "------------------------------"); + // DivineMC end - Dump Parallel World Ticking thread + // Paper start - Only print full dump on long timeouts From 947cd13ee872c6b48908bb74b060170e4b8eb48d Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 13 Jul 2025 20:04:36 +0300 Subject: [PATCH 43/67] Cleanup dead code from Paper --- .../0097-Cleanup-dead-code-from-Paper.patch | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 divinemc-server/minecraft-patches/features/0097-Cleanup-dead-code-from-Paper.patch diff --git a/divinemc-server/minecraft-patches/features/0097-Cleanup-dead-code-from-Paper.patch b/divinemc-server/minecraft-patches/features/0097-Cleanup-dead-code-from-Paper.patch new file mode 100644 index 0000000..9144521 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0097-Cleanup-dead-code-from-Paper.patch @@ -0,0 +1,174 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 13 Jul 2025 20:03:51 +0300 +Subject: [PATCH] Cleanup dead code from Paper + + +diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java +index 8bb7d9f2bce06880164f0ae36e1674e9dc380809..04d47ef66f17daf3dfc9223c9f382e058d09a10b 100644 +--- a/net/minecraft/network/Connection.java ++++ b/net/minecraft/network/Connection.java +@@ -609,13 +609,7 @@ public class Connection extends SimpleChannelInboundHandler> { + if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) + || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING + || Connection.joinAttemptsThisTick++ < MAX_PER_TICK) { +- // Paper start - detailed watchdog information +- net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener); +- try { +- tickablePacketListener.tick(); +- } finally { +- net.minecraft.network.protocol.PacketUtils.packetProcessing.pop(); +- } // Paper end - detailed watchdog information ++ tickablePacketListener.tick(); + } // Paper end - Buffer joins to world + } + +diff --git a/net/minecraft/network/protocol/PacketUtils.java b/net/minecraft/network/protocol/PacketUtils.java +index aa4dd7517e8be167aef1eaf7aa907e3ce7cc0e62..e3d3b062e273fee4a9d3ba3cadc212787096dc54 100644 +--- a/net/minecraft/network/protocol/PacketUtils.java ++++ b/net/minecraft/network/protocol/PacketUtils.java +@@ -21,8 +21,6 @@ public class PacketUtils { + public static void ensureRunningOnSameThread(Packet packet, T processor, BlockableEventLoop executor) throws RunningOnDifferentThreadException { + if (!executor.isSameThread()) { + executor.executeIfPossible(() -> { +- packetProcessing.push(processor); // Paper - detailed watchdog information +- try { // Paper - detailed watchdog information + if (processor instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // Paper - Don't handle sync packets for kicked players + if (processor.shouldHandleMessage(packet)) { + try { +@@ -41,12 +39,6 @@ public class PacketUtils { + } else { + LOGGER.debug("Ignoring packet due to disconnection: {}", packet); + } +- // Paper start - detailed watchdog information +- } finally { +- totalMainThreadPacketsProcessed.getAndIncrement(); +- packetProcessing.pop(); +- } +- // Paper end - detailed watchdog information + }); + throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD; + } +@@ -73,22 +65,4 @@ public class PacketUtils { + + packetListener.fillCrashReport(crashReport); + } +- +- // Paper start - detailed watchdog information +- public static final java.util.concurrent.ConcurrentLinkedDeque packetProcessing = new java.util.concurrent.ConcurrentLinkedDeque<>(); +- static final java.util.concurrent.atomic.AtomicLong totalMainThreadPacketsProcessed = new java.util.concurrent.atomic.AtomicLong(); +- +- public static long getTotalProcessedPackets() { +- return totalMainThreadPacketsProcessed.get(); +- } +- +- public static java.util.List getCurrentPacketProcessors() { +- java.util.List listeners = new java.util.ArrayList<>(4); +- for (PacketListener listener : packetProcessing) { +- listeners.add(listener); +- } +- +- return listeners; +- } +- // Paper end - detailed watchdog information + } +diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java +index d4841095157106c3c69501ac2cd09511f62cfea0..e68d857b59c3e3320221dd995b29cf7aa09aafc2 100644 +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -1349,13 +1349,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // Paper end - log detailed entity tick information + + public void tickNonPassenger(Entity entity) { +- // Paper start - log detailed entity tick information + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot tick an entity off-main"); +- try { +- if (currentlyTickingEntity.get() == null) { +- currentlyTickingEntity.lazySet(entity); +- } +- // Paper end - log detailed entity tick information + entity.setOldPosAndRot(); + entity.tickCount++; + entity.totalEntityAge++; // Paper - age-like counter for all entities +@@ -1368,13 +1362,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + for (Entity entity1 : entity.getPassengers()) { + this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 + } +- // Paper start - log detailed entity tick information +- } finally { +- if (currentlyTickingEntity.get() == entity) { +- currentlyTickingEntity.lazySet(null); +- } +- } +- // Paper end - log detailed entity tick information + } + + private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2 +diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java +index c1c8e235b9c096cd36c3e83b0831af7cb722cad2..7e6e5d5962de14d064321ed7e4f5254046c15d0b 100644 +--- a/net/minecraft/world/entity/Entity.java ++++ b/net/minecraft/world/entity/Entity.java +@@ -1111,29 +1111,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return this.onGround; + } + +- // Paper start - detailed watchdog information +- public final Object posLock = new Object(); // Paper - log detailed entity tick information +- +- @Nullable +- private Vec3 moveVector; +- private double moveStartX; +- private double moveStartY; +- private double moveStartZ; +- // Paper end - detailed watchdog information +- + public void move(MoverType type, Vec3 movement) { + if (!this.boundingBoxChanged && movement.equals(Vec3.ZERO)) return; // DivineMC - VMP: skip entity move if movement is zero + final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity +- // Paper start - detailed watchdog information + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); +- synchronized (this.posLock) { +- this.moveStartX = this.getX(); +- this.moveStartY = this.getY(); +- this.moveStartZ = this.getZ(); +- this.moveVector = movement; +- } +- try { +- // Paper end - detailed watchdog information + if (this.noPhysics) { + this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); + } else { +@@ -1248,13 +1229,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.setDeltaMovement(this.getDeltaMovement().multiply(blockSpeedFactor, 1.0, blockSpeedFactor)); + } + } +- // Paper start - detailed watchdog information +- } finally { +- synchronized (this.posLock) { // Paper +- this.moveVector = null; +- } // Paper +- } +- // Paper end - detailed watchdog information + } + + private void applyMovementEmissionAndPlaySound(Entity.MovementEmission movementEmission, Vec3 movement, BlockPos pos, BlockState state) { +@@ -4948,9 +4922,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public void setDeltaMovement(Vec3 deltaMovement) { +- synchronized (this.posLock) { // Paper - detailed watchdog information + this.deltaMovement = deltaMovement; +- } // Paper - detailed watchdog information + } + + public void addDeltaMovement(Vec3 addend) { +@@ -5048,9 +5020,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + // Paper end - Block invalid positions and bounding box + if (this.position.x != x || this.position.y != y || this.position.z != z) { +- synchronized (this.posLock) { // Paper - detailed watchdog information + this.position = new Vec3(x, y, z); +- } // Paper - detailed watchdog information + int floor = Mth.floor(x); + int floor1 = Mth.floor(y); + int floor2 = Mth.floor(z); From 3a44a916e1ea71ad2d21c572d291434dace672f9 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 13 Jul 2025 21:46:13 +0300 Subject: [PATCH 44/67] update readme --- README.md | 61 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 0a79714..11fb2fd 100644 --- a/README.md +++ b/README.md @@ -7,25 +7,28 @@ [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/BX-Team/DivineMC/build-1217.yml?logo=GoogleAnalytics&logoColor=ffffff&style=for-the-badge)](https://github.com/BX-Team/DivineMC/actions) [![Discord](https://img.shields.io/discord/931595732752953375?color=5865F2&label=discord&style=for-the-badge)](https://discord.gg/qNyybSSPm5) -DivineMC is a high-performance [Purpur](https://github.com/PurpurMC/Purpur) fork focused on maximizing server performance while maintaining plugin compatibility. - +DivineMC is a multi-functional fork of [Purpur](https://github.com/PurpurMC/Purpur), which focuses on the flexibility of your server and its optimization -> [!WARNING] -> DivineMC is a performance-oriented fork. Make sure to take backups **before** switching to it. We also welcome a new contributor to help us improve the fork. - ## ⚙️ Features -- **Based on [Purpur](https://github.com/PurpurMC/Purpur)** that adds a high customization level to the server. -- **Regionized Chunk Ticking** feature that allows to tick chunks in parallel, similar to how Folia does it. -- Implemented **Parallel world ticking** feature, that allows to server take advantage of multiple CPU cores to tick worlds. -- Implemented **Secure Seed** mod that changes default 64-bit seed to a 1024-bit seed, making it almost impossible to crack the seed. -- **Optimized chunk generation** that can generate chunks up to 70% faster than vanilla. -- **Async** pathfinding, entity tracker, mob spawning and chunk sending. -- Implemented **Linear region file format** -- **Fully compatible** with Bukkit, Spigot and Paper plugins -- **Fixes** some Minecraft bugs -- Integrated with [Sentry](https://sentry.io/welcome/) to easy track all errors coming from your server in excruciating detail (original by [Pufferfish](https://github.com/pufferfish-gg/Pufferfish)) -- and more... + +### 🚀 Core Performance +- **Based on [Purpur](https://github.com/PurpurMC/Purpur)** - Adds a high customization level to your server +- **Regionized Chunk Ticking** - Tick chunks in parallel, similar to how Folia does it +- **Parallel World Ticking** - Leverage multiple CPU cores for world processing +- **Async Operations** - Pathfinding, entity tracker, mob spawning, joining and chunk sending + +### 🔧 Advanced Features +- **Secure Seed** - Enhanced 1024-bit seed system (vs standard 64-bit) for maximum security +- **Linear Region File Format** - Optimize your world with the old V1/V2 linear format and the new Buffered format +- **Mod Protocols Support** - Compatible with Syncmatica, Apple Skin, Jade and Xaero's Map + +### 🔌 Compatibility & Reliability +- **Fully Compatible** - Works seamlessly with Bukkit, Spigot and Paper plugins +- **Bug Fixes** - Resolves various Minecraft issues (~10) +- **Sentry Integration** - Detailed error tracking and monitoring (original by [Pufferfish](https://github.com/pufferfish-gg/Pufferfish)) + +*...and much more!* ## 📥 Downloading & Installing If you want to install DivineMC, you can read our [installation documentation](https://bxteam.org/docs/divinemc/getting-started/installation). @@ -81,21 +84,19 @@ We also have a [Javadoc](https://repo.bxteam.org/javadoc/snapshots/org/bxteam/di DivineMC is licensed under the GNU General Public License v3.0. You can find the license [here](LICENSE). ## 📜 Credits -DivineMC includes patches from other forks, and without these forks, DivineMC wouldn't exist today. Here are the list of these forks: +DivineMC includes patches from other projects, and without these projects, DivineMC wouldn't exist today. Here is a small list of projects that DivineMC takes patches from: - [Purpur](https://github.com/PurpurMC/Purpur) --

- 📜 Expand to see forks that DivineMC takes patches from. -

- • Petal
- • Carpet Fixes
- • Parchment
- • Leaves
- • SparklyPaper
- • Matter
- • Canvas
- • Leaf
-

-
+- [Petal](https://github.com/Bloom-host/Petal) +- [carpet-fixes](https://github.com/fxmorin/carpet-fixes) +- [Parchment](https://github.com/ProjectEdenGG/Parchment) +- [Leaves](https://github.com/LeavesMC/Leaves) +- [SparklyPaper](https://github.com/SparklyPower/SparklyPaper) +- [matter](https://github.com/plasmoapp/matter) +- [Leaf](https://github.com/Winds-Studio/Leaf) +- [C2ME](https://github.com/RelativityMC/C2ME-fabric) +- [VMP](https://github.com/RelativityMC/VMP-fabric) +- [EntityCulling](https://github.com/tr7zw/EntityCulling) +- ... and others If you want to know more about other forks and see other Minecraft projects, you can go to our [list of different Minecraft server Software](https://gist.github.com/NONPLAYT/48742353af8ae36bcef5d1c36de9730a). From f7515542734c84b89600d6005e4d34f0d34d5337 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:43:52 +0300 Subject: [PATCH 45/67] implement shuttle --- .github/workflows/build-1217.yml | 4 +- .github/workflows/build-pr.yml | 6 +- README.md | 2 +- build.gradle.kts | 72 +++++ .../features/0001-Rebrand.patch | 24 +- .../paper-patches/features/0001-Rebrand.patch | 110 +++++++- .../features/0002-Configuration.patch | 4 +- ...loading-plugins-from-external-folder.patch | 4 +- .../org/bxteam/divinemc/DivineBootstrap.java | 91 +++++-- gradle.properties | 2 +- scripts/releaseInfo.sh | 2 +- settings.gradle.kts | 2 +- shuttle/build.gradle.kts | 57 ++++ .../main/java/org/bxteam/shuttle/Shuttle.java | 169 ++++++++++++ .../org/bxteam/shuttle/logger/Logger.java | 73 +++++ .../shuttle/patch/InstrumentationManager.java | 39 +++ .../bxteam/shuttle/patch/LibraryLoader.java | 255 ++++++++++++++++++ .../bxteam/shuttle/patch/PatchBuilder.java | 248 +++++++++++++++++ 18 files changed, 1118 insertions(+), 46 deletions(-) create mode 100644 shuttle/build.gradle.kts create mode 100644 shuttle/src/main/java/org/bxteam/shuttle/Shuttle.java create mode 100644 shuttle/src/main/java/org/bxteam/shuttle/logger/Logger.java create mode 100644 shuttle/src/main/java/org/bxteam/shuttle/patch/InstrumentationManager.java create mode 100644 shuttle/src/main/java/org/bxteam/shuttle/patch/LibraryLoader.java create mode 100644 shuttle/src/main/java/org/bxteam/shuttle/patch/PatchBuilder.java diff --git a/.github/workflows/build-1217.yml b/.github/workflows/build-1217.yml index 9b41d68..e1452c5 100644 --- a/.github/workflows/build-1217.yml +++ b/.github/workflows/build-1217.yml @@ -62,8 +62,8 @@ jobs: PARALLELISM=$(($(nproc) * 2)) ./gradlew applyAllPatches --stacktrace --parallel --max-workers=$PARALLELISM --build-cache --no-daemon - - name: Build Paperclip Jar - run: ./gradlew createMojmapPaperclipJar --stacktrace --parallel --no-daemon + - name: Build Shuttle Jar + run: ./gradlew createMojmapShuttleJar --stacktrace --parallel --no-daemon - name: Prepare Release Info run: bash scripts/releaseInfo.sh diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index c074c43..68df3c0 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -26,11 +26,11 @@ jobs: - name: Apply Patches run: ./gradlew applyAllPatches --stacktrace --no-daemon - - name: Build Paperclip Jar - run: ./gradlew createMojmapPaperclipJar --stacktrace --no-daemon + - name: Build Shuttle Jar + run: ./gradlew createMojmapShuttleJar --stacktrace --no-daemon - name: Upload Artifacts uses: actions/upload-artifact@main with: name: DivineMC - path: divinemc-server/build/libs/divinemc-paperclip-*-mojmap.jar + path: divinemc-server/build/libs/divinemc-shuttle-*-mojmap.jar diff --git a/README.md b/README.md index 11fb2fd..eec2e34 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Run the following commands in the root directory: ```bash > ./gradlew applyAllPatches # apply all patches -> ./gradlew createMojmapPaperclipJar # build the server jar +> ./gradlew createMojmapShuttleJar # build the server jar ``` For anything else you can refer to our [contribution guide](https://bxteam.org/docs/divinemc/development/contributing). diff --git a/build.gradle.kts b/build.gradle.kts index 758fe0e..5821d2b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent +import kotlin.system.measureTimeMillis plugins { java @@ -91,6 +92,7 @@ subprojects { mavenCentral() maven(paperMavenPublicUrl) maven("https://jitpack.io") + maven("https://s01.oss.sonatype.org/content/repositories/snapshots") } extensions.configure { @@ -105,6 +107,76 @@ subprojects { } } +tasks.register("createMojmapShuttleJar") { + dependsOn(":divinemc-server:createMojmapPaperclipJar", "shuttle:shadowJar") + + outputs.upToDateWhen { false } + + val paperclipJarTask = project(":divinemc-server").tasks.getByName("createMojmapPaperclipJar") + val shuttleJarTask = project(":shuttle").tasks.getByName("shadowJar") + + val paperclipJar = paperclipJarTask.outputs.files.singleFile + val shuttleJar = shuttleJarTask.outputs.files.singleFile + val outputDir = paperclipJar.parentFile + val tempDir = File(outputDir, "tempJarWork") + val newJarName = "divinemc-shuttle-${properties["version"]}-mojmap.jar" + + doFirst { + val time = measureTimeMillis { + println("Recompiling Paperclip with Shuttle sources...") + + tempDir.deleteRecursively() + tempDir.mkdirs() + + copy { + from(zipTree(paperclipJar)) + into(tempDir) + } + + val oldPackagePath = "io/papermc/paperclip/" + tempDir.walkTopDown() + .filter { it.isFile && it.relativeTo(tempDir).path.startsWith(oldPackagePath) } + .forEach { it.delete() } + + val shuttlePackagePath = "org/bxteam/shuttle/" + copy { + from(zipTree(shuttleJar)) + include("$shuttlePackagePath**") + into(tempDir) + } + + tempDir.walkBottomUp() + .filter { it.isDirectory && it.listFiles().isNullOrEmpty() } + .forEach { it.delete() } + + val metaInfDir = File(tempDir, "META-INF") + metaInfDir.mkdirs() + File(metaInfDir, "main-class").writeText("net.minecraft.server.Main") + } + println("Finished build in ${time}ms") + } + + archiveFileName.set(newJarName) + destinationDirectory.set(outputDir) + from(tempDir) + + manifest { + attributes( + "Main-Class" to "org.bxteam.shuttle.Shuttle", + "Enable-Native-Access" to "ALL-UNNAMED", + "Premain-Class" to "org.bxteam.shuttle.patch.InstrumentationManager", + "Agent-Class" to "org.bxteam.shuttle.patch.InstrumentationManager", + "Launcher-Agent-Class" to "org.bxteam.shuttle.patch.InstrumentationManager", + "Can-Redefine-Classes" to true, + "Can-Retransform-Classes" to true + ) + } + + doLast { + tempDir.deleteRecursively() + } +} + tasks.register("printMinecraftVersion") { doLast { println(providers.gradleProperty("mcVersion").get().trim()) diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index 1b985a5..334fb12 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -18,10 +18,28 @@ index 394443d00e661715439be1e56dddc129947699a4..480ad57a6b7b74e6b83e9c6ceb69ea1f public CrashReport(String title, Throwable exception) { io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java -index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..a476b53e0c5b18d9b0abceb4ffeb5ab4c5d7d6d9 100644 +index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..9d89af099c6e0f50c73a9372e1ef7f1b0ef932c5 100644 --- a/net/minecraft/server/Main.java +++ b/net/minecraft/server/Main.java -@@ -125,7 +125,6 @@ public class Main { +@@ -64,6 +64,17 @@ import org.slf4j.Logger; + public class Main { + private static final Logger LOGGER = LogUtils.getLogger(); + ++ public static void main(String[] arguments) { ++ OptionSet optionSet = org.bxteam.divinemc.DivineBootstrap.bootstrap(arguments); ++ ++ io.papermc.paper.ServerBuildInfo info = io.papermc.paper.ServerBuildInfo.buildInfo(); ++ if (io.papermc.paper.ServerBuildInfoImpl.IS_EXPERIMENTAL) { ++ LOGGER.warn("Running an experimental version of {}, please proceed with caution.", info.brandName()); ++ } ++ ++ main(optionSet); ++ } ++ + @SuppressForbidden( + reason = "System.out needed before bootstrap" + ) +@@ -125,7 +136,6 @@ public class Main { dedicatedServerSettings.forceSave(); RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression); Path path2 = Paths.get("eula.txt"); @@ -29,7 +47,7 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..a476b53e0c5b18d9b0abceb4ffeb5ab4 // Paper start - load config files early for access below if needed 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")); -@@ -148,19 +147,6 @@ public class Main { +@@ -148,19 +158,6 @@ public class Main { return; } diff --git a/divinemc-server/paper-patches/features/0001-Rebrand.patch b/divinemc-server/paper-patches/features/0001-Rebrand.patch index b2b5f4e..3272a05 100644 --- a/divinemc-server/paper-patches/features/0001-Rebrand.patch +++ b/divinemc-server/paper-patches/features/0001-Rebrand.patch @@ -231,18 +231,112 @@ index 62e2d5704c348955bc8284dc2d54c933b7bcdd06..341f13e57896f03058ea3ec68e69b7cb public void executeAsync(final Runnable runnable) { MCUtil.scheduleAsyncTask(this.catching(runnable, "asynchronous")); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index c92ae5af5186a7c36f685272a13cfcfad21e8e69..24013949b6646016267132396e61d6cd4af8e374 100644 +index 748bd9650da4a209743b7a5dde584b2e19c5a578..7e90142cb65937103aa99fd011540086449c45c8 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -247,7 +247,7 @@ public class Main { - System.setProperty("library.jansi.version", "Paper"); // Paper - set meaningless jansi version to prevent git builds from crashing on Windows - System.setProperty("jdk.console", "java.base"); // Paper - revert default console provider back to java.base so we can have our own jline +@@ -1,14 +1,8 @@ + package org.bukkit.craftbukkit; -- io.papermc.paper.PaperBootstrap.boot(options); -+ org.bxteam.divinemc.DivineBootstrap.boot(options); // DivineMC - Replace with DivineBootstrap - } catch (Throwable t) { - t.printStackTrace(); + import java.io.File; +-import java.io.IOException; + import java.text.SimpleDateFormat; +-import java.util.Calendar; +-import java.util.Date; +-import java.util.logging.Level; +-import java.util.logging.Logger; + import joptsimple.OptionParser; +-import joptsimple.OptionSet; + import joptsimple.util.PathConverter; + + import static java.util.Arrays.asList; +@@ -24,7 +18,7 @@ public class Main { + } + // Paper end - Reset loggers after shutdown + +- public static void main(String[] args) { ++ public static OptionParser main(String[] args) { // DivineMC - Rebrand + if (System.getProperty("jdk.nio.maxCachedBufferSize") == null) System.setProperty("jdk.nio.maxCachedBufferSize", "262144"); // Paper - cap per-thread NIO cache size; https://www.evanjones.ca/java-bytebuffer-leak.html + OptionParser parser = new OptionParser() { + { +@@ -180,77 +174,6 @@ public class Main { } + }; + +- OptionSet options = null; +- +- try { +- options = parser.parse(args); +- } catch (joptsimple.OptionException ex) { +- Logger.getLogger(Main.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage()); +- } +- +- if ((options == null) || (options.has("?"))) { +- try { +- parser.printHelpOn(System.out); +- } catch (IOException ex) { +- Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); +- } +- } else if (options.has("v")) { +- System.out.println(CraftServer.class.getPackage().getImplementationVersion()); +- } else { +- // Do you love Java using + and ! as string based identifiers? I sure do! +- String path = new File(".").getAbsolutePath(); +- if (path.contains("!") || path.contains("+")) { +- System.err.println("Cannot run server in a directory with ! or + in the pathname. Please rename the affected folders and try again."); +- return; +- } +- +- // Paper start - Improve java version check +- boolean skip = Boolean.getBoolean("Paper.IgnoreJavaVersion"); +- String javaVersionName = System.getProperty("java.version"); +- // J2SE SDK/JRE Version String Naming Convention +- boolean isPreRelease = javaVersionName.contains("-"); +- if (isPreRelease) { +- if (!skip) { +- System.err.println("Unsupported Java detected (" + javaVersionName + "). You are running an unsupported, non official, version. Only general availability versions of Java are supported. Please update your Java version. See https://docs.papermc.io/paper/faq#unsupported-java-detected-what-do-i-do for more information."); +- return; +- } +- +- System.err.println("Unsupported Java detected ("+ javaVersionName + "), but the check was skipped. Proceed with caution! "); +- } +- // Paper end - Improve java version check +- +- try { +- if (options.has("nojline")) { +- System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); +- useJline = false; +- } +- +- if (options.has("noconsole")) { +- Main.useConsole = false; +- useJline = false; // Paper +- System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper +- } +- +- if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) { // Purpur - Disable outdated build check +- Date buildDate = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse(Main.class.getPackage().getImplementationVendor()); // Paper +- +- Calendar deadline = Calendar.getInstance(); +- deadline.add(Calendar.DAY_OF_YEAR, -14); +- if (buildDate.before(deadline.getTime())) { +- // Paper start - This is some stupid bullshit +- System.err.println("*** Warning, you've not updated in a while! ***"); +- System.err.println("*** Please download a new build from https://papermc.io/downloads/paper ***"); +- // Paper end +- } +- } +- +- System.setProperty("library.jansi.version", "Paper"); // Paper - set meaningless jansi version to prevent git builds from crashing on Windows +- System.setProperty("jdk.console", "java.base"); // Paper - revert default console provider back to java.base so we can have our own jline +- +- io.papermc.paper.PaperBootstrap.boot(options); +- } catch (Throwable t) { +- t.printStackTrace(); +- } +- } ++ return parser; // DivineMC - Rebrand + } + } diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java index 2e7c3d4befeb6256ce81ecaa9ed4e8fbcb21651e..a839dbbb72f48b8f8736d9f4693c528686570732 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java diff --git a/divinemc-server/paper-patches/features/0002-Configuration.patch b/divinemc-server/paper-patches/features/0002-Configuration.patch index 2060404..ff40032 100644 --- a/divinemc-server/paper-patches/features/0002-Configuration.patch +++ b/divinemc-server/paper-patches/features/0002-Configuration.patch @@ -31,10 +31,10 @@ index 592e8a4c04ef5acda9fdfd1405d8ff4952396ada..c8c7fa0304e8eaf0d444fc0c9a36c00b Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index cc4f4fbbe1cacce5f0f5500a8dda199aa0bcdf31..03fe7d98252b93f4625359f50552e3cf60e82b9c 100644 +index 7e90142cb65937103aa99fd011540086449c45c8..7653ba0259ddc930dc4e2af84636641d3dba6e7f 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -172,6 +172,14 @@ public class Main { +@@ -166,6 +166,14 @@ public class Main { .describedAs("Yml file"); // Purpur end - Purpur config files diff --git a/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch b/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch index be8bd84..dfe2382 100644 --- a/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch +++ b/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch @@ -30,10 +30,10 @@ index 70413fddd23ca1165cb5090cce4fddcb1bbca93f..ae70b84e6473fa2ed94416bf4bef8849 @SuppressWarnings("unchecked") java.util.List files = ((java.util.List) optionSet.valuesOf("add-plugin")).stream().map(File::toPath).toList(); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 03fe7d98252b93f4625359f50552e3cf60e82b9c..ff350b5744b586cad7c2f5e0a04770e76f039d39 100644 +index 7653ba0259ddc930dc4e2af84636641d3dba6e7f..1a3a5e8a9119af8ed9d13a61bc5dc7b3ee0b7a65 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -180,6 +180,14 @@ public class Main { +@@ -174,6 +174,14 @@ public class Main { .describedAs("Yml file"); // DivineMC end - Configuration diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java index cc9e5dd..52b7f04 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java @@ -1,45 +1,92 @@ package org.bxteam.divinemc; import io.papermc.paper.ServerBuildInfo; +import joptsimple.OptionParser; import joptsimple.OptionSet; import net.minecraft.SharedConstants; import net.minecraft.server.Eula; -import net.minecraft.server.Main; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.Main; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.IOException; import java.lang.management.ManagementFactory; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; +@SuppressWarnings("DuplicatedCode") public class DivineBootstrap { private static final Logger LOGGER = LoggerFactory.getLogger("DivineBootstrap"); - public static void boot(final OptionSet options) { - SharedConstants.tryDetectVersion(); + public static OptionSet bootstrap(String[] args) { + OptionParser parser = Main.main(args); + OptionSet options = parser.parse(args); - io.papermc.paper.ServerBuildInfo info = io.papermc.paper.ServerBuildInfo.buildInfo(); - if (io.papermc.paper.ServerBuildInfoImpl.IS_EXPERIMENTAL) { - LOGGER.warn("Running an experimental version of {}, please proceed with caution.", info.brandName()); - } + if ((options == null) || (options.has("?"))) { + try { + parser.printHelpOn(System.out); + } catch (IOException ex) { + LOGGER.warn(ex.getMessage()); + } + } else if (options.has("v")) { + System.out.println(CraftServer.class.getPackage().getImplementationVersion()); + } else { + String path = new File(".").getAbsolutePath(); + if (path.contains("!") || path.contains("+")) { + System.err.println("Cannot run server in a directory with ! or + in the pathname. Please rename the affected folders and try again."); + System.exit(70); + } - Path path2 = Paths.get("eula.txt"); - Eula eula = new Eula(path2); - boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree"); - if (eulaAgreed) { - LOGGER.error("You have used the Spigot command line EULA agreement flag."); - LOGGER.error("By using this setting you are indicating your agreement to Mojang's EULA (https://aka.ms/MinecraftEULA)."); - LOGGER.error("If you do not agree to the above EULA please stop your server and remove this flag immediately."); - } - if (!eula.hasAgreedToEULA() && !eulaAgreed) { - LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info."); - return; - } - System.out.println("Loading libraries, please wait..."); // Restore CraftBukkit log - getStartupVersionMessages().forEach(LOGGER::info); + boolean skip = Boolean.getBoolean("Paper.IgnoreJavaVersion"); + String javaVersionName = System.getProperty("java.version"); + boolean isPreRelease = javaVersionName.contains("-"); + if (isPreRelease) { + if (!skip) { + System.err.println("Unsupported Java detected (" + javaVersionName + "). You are running an unsupported, non official, version. Only general availability versions of Java are supported. Please update your Java version. See https://docs.papermc.io/paper/faq#unsupported-java-detected-what-do-i-do for more information."); + System.exit(70); + } - Main.main(options); + System.err.println("Unsupported Java detected ("+ javaVersionName + "), but the check was skipped. Proceed with caution! "); + } + + try { + if (options.has("nojline")) { + System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); + Main.useJline = false; + } + + if (options.has("noconsole")) { + Main.useConsole = false; + Main.useJline = false; + System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper + } + + System.setProperty("library.jansi.version", "Paper"); + System.setProperty("jdk.console", "java.base"); + + SharedConstants.tryDetectVersion(); + Path path2 = Paths.get("eula.txt"); + Eula eula = new Eula(path2); + boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree"); + if (eulaAgreed) { + LOGGER.error("You have used the Spigot command line EULA agreement flag."); + LOGGER.error("By using this setting you are indicating your agreement to Mojang's EULA (https://aka.ms/MinecraftEULA)."); + LOGGER.error("If you do not agree to the above EULA please stop your server and remove this flag immediately."); + } + if (!eula.hasAgreedToEULA() && !eulaAgreed) { + LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info."); + System.exit(0); + } + + getStartupVersionMessages().forEach(LOGGER::info); + } catch (Throwable t) { + t.printStackTrace(); + } + } + return options; } private static List getStartupVersionMessages() { diff --git a/gradle.properties b/gradle.properties index 5a829c5..424615a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ mcVersion=1.21.7 purpurRef=c4e5604ca8e4a36d24f4eaa90de7fee768fb60b7 experimental=false -org.gradle.configuration-cache=true +#org.gradle.configuration-cache=true org.gradle.caching = true org.gradle.parallel = true org.gradle.vfs.watch = false diff --git a/scripts/releaseInfo.sh b/scripts/releaseInfo.sh index 3a8fb53..a2ad3a5 100644 --- a/scripts/releaseInfo.sh +++ b/scripts/releaseInfo.sh @@ -28,7 +28,7 @@ make_latest=$([ "$experimental" = "true" ] && echo "false" || echo "true") rm -f $changelog -mv divinemc-server/build/libs/divinemc-paperclip-"$version"-mojmap.jar "$jarName" +mv divinemc-server/build/libs/divinemc-shuttle-"$version"-mojmap.jar "$jarName" { echo "name=$divinemcid" echo "tag=$tagid" diff --git a/settings.gradle.kts b/settings.gradle.kts index 67c5e4d..474fed7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,7 +35,7 @@ if (!file(".git").exists()) { rootProject.name = "DivineMC" -for (name in listOf("divinemc-api", "divinemc-server")) { +for (name in listOf("divinemc-api", "divinemc-server", "shuttle")) { val projName = name.lowercase(Locale.ENGLISH) include(projName) findProject(":$projName")!!.projectDir = file(name) diff --git a/shuttle/build.gradle.kts b/shuttle/build.gradle.kts new file mode 100644 index 0000000..b6ecb04 --- /dev/null +++ b/shuttle/build.gradle.kts @@ -0,0 +1,57 @@ +plugins { + id("java") + id("application") + id("maven-publish") + id("com.gradleup.shadow") version "8.3.8" +} + +val mainClass = "org.bxteam.shuttle.Shuttle" + +repositories { + mavenCentral() +} + +dependencies { + implementation("io.sigpipe:jbsdiff:1.0") +} + +java { + toolchain.languageVersion.set(JavaLanguageVersion.of(21)) + withSourcesJar() +} + +tasks.withType().configureEach { + options.encoding = "UTF-8" + options.release = 21 +} + +tasks.jar { + val jar = tasks.named("shadowJar") + dependsOn(jar) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from(zipTree(jar.map { it.outputs.files.singleFile })) + + manifest { + attributes( + "Main-Class" to mainClass, + "Enable-Native-Access" to "ALL-UNNAMED", + "Premain-Class" to "org.bxteam.shuttle.patch.InstrumentationManager", + "Agent-Class" to "org.bxteam.shuttle.patch.InstrumentationManager", + "Launcher-Agent-Class" to "org.bxteam.shuttle.patch.InstrumentationManager", + "Can-Redefine-Classes" to true, + "Can-Retransform-Classes" to true + ) + } +} + +project.setProperty("mainClassName", mainClass) + +tasks.shadowJar { + val prefix = "paperclip.libs" + listOf("org.apache", "org.tukaani", "io.sigpipe").forEach { pack -> + relocate(pack, "$prefix.$pack") + } + + exclude("META-INF/LICENSE.txt") + exclude("META-INF/NOTICE.txt") +} diff --git a/shuttle/src/main/java/org/bxteam/shuttle/Shuttle.java b/shuttle/src/main/java/org/bxteam/shuttle/Shuttle.java new file mode 100644 index 0000000..b6358cd --- /dev/null +++ b/shuttle/src/main/java/org/bxteam/shuttle/Shuttle.java @@ -0,0 +1,169 @@ +package org.bxteam.shuttle; + +import org.bxteam.shuttle.logger.Logger; +import org.bxteam.shuttle.patch.LibraryLoader; +import org.bxteam.shuttle.patch.PatchBuilder; + +import java.io.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public final class Shuttle { + private static final String MAIN_CLASS_RESOURCE = "/META-INF/main-class"; + private static final String VERSION_RESOURCE = "/version.json"; + private static final String PATCH_ONLY_PROPERTY = "paperclip.patchonly"; + private static final String BUNDLER_MAIN_CLASS_PROPERTY = "bundlerMainClass"; + private static final String BUNDLER_REPO_DIR_PROPERTY = "bundlerRepoDir"; + private static final String MAIN_THREAD_NAME = "main"; + + public static void main(String[] arguments) { + new Shuttle().run(arguments); + } + + private void run(String[] arguments) { + try { + String defaultMainClassName = readMainClass(); + String mainClassName = System.getProperty(BUNDLER_MAIN_CLASS_PROPERTY, defaultMainClassName); + String repoDir = System.getProperty(BUNDLER_REPO_DIR_PROPERTY, ""); + + setupDirectories(repoDir); + + Provider versionProvider = this::readVersionFromResource; + + executePatchingPhase(versionProvider); + + if (shouldExitAfterPatching()) { + System.exit(0); + } + + executeLibraryLoadingPhase(versionProvider); + + startTargetApplication(mainClassName, arguments); + } catch (Exception e) { + Logger.error("Failed to extract server libraries, exiting", e); + System.exit(1); + } + } + + private String readMainClass() throws IOException { + return readResourceContent(MAIN_CLASS_RESOURCE, BufferedReader::readLine); + } + + private String readVersionFromResource() throws IOException { + String jsonContent = readResourceContent(VERSION_RESOURCE, this::readAllLines); + return extractVersionFromJson(jsonContent); + } + + private T readResourceContent(String resourcePath, ResourceParser parser) throws IOException { + try (InputStream inputStream = getClass().getResourceAsStream(resourcePath)) { + if (inputStream == null) { + throw new IOException("Resource not found: " + resourcePath); + } + + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + return parser.parse(reader); + } + } + } + + private String readAllLines(BufferedReader reader) throws IOException { + StringBuilder content = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + content.append(line); + } + return content.toString(); + } + + private String extractVersionFromJson(String jsonContent) throws IOException { + String prefix = "\"id\": \""; + int startIndex = jsonContent.indexOf(prefix); + + if (startIndex == -1) { + throw new IOException("Version ID not found in JSON content"); + } + + startIndex += prefix.length(); + int endIndex = jsonContent.indexOf("\"", startIndex); + + if (endIndex == -1) { + throw new IOException("Malformed version ID in JSON content"); + } + + return jsonContent.substring(startIndex, endIndex); + } + + private void setupDirectories(String repoDir) throws IOException { + if (!repoDir.isEmpty()) { + Path outputDir = Paths.get(repoDir); + Files.createDirectories(outputDir); + } + } + private void executePatchingPhase(Provider versionProvider) throws IOException { + new PatchBuilder().start(versionProvider); + } + + private boolean shouldExitAfterPatching() { + return Boolean.getBoolean(PATCH_ONLY_PROPERTY); + } + + private void executeLibraryLoadingPhase(Provider versionProvider) throws IOException { + new LibraryLoader().start(versionProvider); + } + + private void startTargetApplication(String mainClassName, String[] arguments) { + if (mainClassName == null || mainClassName.trim().isEmpty()) { + Logger.warn("No main class specified, exiting"); + return; + } + + Logger.info("Starting " + mainClassName); + + Thread applicationThread = new Thread(() -> { + try { + invokeMainMethod(mainClassName, arguments); + } catch (Throwable e) { + ExceptionHandler.INSTANCE.rethrow(e); + } + }, MAIN_THREAD_NAME); + + applicationThread.start(); + } + + private void invokeMainMethod(String mainClassName, String[] arguments) throws Throwable { + Class mainClass = Class.forName(mainClassName); + MethodHandle mainHandle = MethodHandles.lookup() + .findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)) + .asFixedArity(); + + mainHandle.invoke((Object) arguments); + } + + @FunctionalInterface + private interface ResourceParser { + T parse(BufferedReader reader) throws IOException; + } + + @FunctionalInterface + public interface Provider { + T get() throws IOException; + } + + private static final class ExceptionHandler { + static final ExceptionHandler INSTANCE = new ExceptionHandler(); + + private ExceptionHandler() { + throw new UnsupportedOperationException("Utility class cannot be instantiated"); + } + + void rethrow(Throwable exception) { + throw new RuntimeException("Exception in target application", exception); + } + } +} diff --git a/shuttle/src/main/java/org/bxteam/shuttle/logger/Logger.java b/shuttle/src/main/java/org/bxteam/shuttle/logger/Logger.java new file mode 100644 index 0000000..fc2765b --- /dev/null +++ b/shuttle/src/main/java/org/bxteam/shuttle/logger/Logger.java @@ -0,0 +1,73 @@ +package org.bxteam.shuttle.logger; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.ConsoleHandler; +import java.util.logging.Formatter; + +public class Logger { + private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger("Shuttle"); + private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); + + static { + LOGGER.setUseParentHandlers(false); + + ConsoleHandler consoleHandler = new ConsoleHandler(); + consoleHandler.setFormatter(new ShuttleFormatter()); + consoleHandler.setLevel(Level.ALL); + LOGGER.addHandler(consoleHandler); + + LOGGER.setLevel(Level.INFO); + } + + public static void info(String message) { + LOGGER.info(message); + } + + public static void warn(String message) { + LOGGER.warning(message); + } + + public static void error(String message) { + LOGGER.severe(message); + } + + public static void error(String message, Throwable throwable) { + LOGGER.log(Level.SEVERE, message, throwable); + } + + public static void debug(String message) { + LOGGER.fine(message); + } + + public static void setLevel(Level level) { + LOGGER.setLevel(level); + LOGGER.getHandlers()[0].setLevel(level); + } + + private static class ShuttleFormatter extends Formatter { + @Override + public String format(LogRecord record) { + String time = LocalTime.now().format(TIME_FORMATTER); + String level = record.getLevel().getName(); + String message = record.getMessage(); + + StringBuilder sb = new StringBuilder(); + sb.append("[").append(time).append(" ").append(level).append("]: "); + sb.append("[Shuttle] "); + sb.append(message); + sb.append(System.lineSeparator()); + + if (record.getThrown() != null) { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + record.getThrown().printStackTrace(pw); + sb.append(sw.toString()); + } + + return sb.toString(); + } + } +} diff --git a/shuttle/src/main/java/org/bxteam/shuttle/patch/InstrumentationManager.java b/shuttle/src/main/java/org/bxteam/shuttle/patch/InstrumentationManager.java new file mode 100644 index 0000000..6671d5f --- /dev/null +++ b/shuttle/src/main/java/org/bxteam/shuttle/patch/InstrumentationManager.java @@ -0,0 +1,39 @@ +package org.bxteam.shuttle.patch; + +import java.lang.instrument.Instrumentation; + +public final class InstrumentationManager { + private static volatile Instrumentation instrumentation; + private static final Object LOCK = new Object(); + + private InstrumentationManager() { + throw new UnsupportedOperationException("Utility class cannot be instantiated"); + } + + public static void premain(final String agentArgs, final Instrumentation inst) { + agentmain(agentArgs, inst); + } + + public static void agentmain(final String agentArgs, final Instrumentation inst) { + if (inst == null) { + throw new IllegalArgumentException("Instrumentation instance cannot be null"); + } + + synchronized (LOCK) { + if (instrumentation == null) { + instrumentation = inst; + } + } + } + + public static Instrumentation getInstrumentation() { + final Instrumentation inst = instrumentation; + if (inst == null) { + throw new IllegalStateException( + "Instrumentation has not been initialized. " + + "Ensure the agent is properly loaded via -javaagent or attach mechanism." + ); + } + return inst; + } +} diff --git a/shuttle/src/main/java/org/bxteam/shuttle/patch/LibraryLoader.java b/shuttle/src/main/java/org/bxteam/shuttle/patch/LibraryLoader.java new file mode 100644 index 0000000..d466496 --- /dev/null +++ b/shuttle/src/main/java/org/bxteam/shuttle/patch/LibraryLoader.java @@ -0,0 +1,255 @@ +package org.bxteam.shuttle.patch; + +import org.bxteam.shuttle.Shuttle; +import org.bxteam.shuttle.logger.Logger; + +import java.io.*; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class LibraryLoader { + private static final String LIBRARIES_DIR = "libraries"; + private static final String CACHE_DIR = "cache"; + private static final String LIBRARIES_LIST_RESOURCE = "/META-INF/libraries.list"; + private static final String LIBRARIES_PREFIX = "META-INF/libraries/"; + private static final String PATCH_EXTENSION = ".patch"; + private static final int BUFFER_SIZE = 8192; + + private static final List MAVEN_REPOSITORIES = List.of( + "https://repo.papermc.io/repository/maven-public/", + "https://jitpack.io", + "https://s01.oss.sonatype.org/content/repositories/snapshots/", + "https://repo1.maven.org/maven2/", + "https://libraries.minecraft.net/" + ); + + private static void copyStream(InputStream input, OutputStream output) throws IOException { + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead; + while ((bytesRead = input.read(buffer)) != -1) { + output.write(buffer, 0, bytesRead); + } + } + + public void start(Shuttle.Provider versionProvider) throws IOException { + try { + start(versionProvider.get()); + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new IOException("Error during library loading process", e); + } + } + + public void start(String mcVersion) throws IOException { + if (mcVersion == null || mcVersion.trim().isEmpty()) { + throw new IllegalArgumentException("Minecraft version cannot be null or empty"); + } + + Logger.info("Unpacking and linking library jars"); + + try { + createLibrariesDirectory(); + + Path currentJar = getCurrentJarPath(); + extractLibrariesFromJar(currentJar); + + Path vanillaBundler = Paths.get(CACHE_DIR, "vanilla-bundler-" + mcVersion + ".jar"); + if (Files.exists(vanillaBundler)) { + extractLibrariesFromJar(vanillaBundler); + } + } catch (Exception e) { + throw new IOException("Failed to load libraries for version " + mcVersion, e); + } + } + + private void createLibrariesDirectory() throws IOException { + Path librariesDir = Paths.get(LIBRARIES_DIR); + if (!Files.exists(librariesDir)) { + Files.createDirectories(librariesDir); + } + } + + private Path getCurrentJarPath() throws IOException { + try { + return Paths.get(LibraryLoader.class.getProtectionDomain() + .getCodeSource().getLocation().toURI()); + } catch (URISyntaxException e) { + throw new IOException("Failed to get current JAR path", e); + } + } + + private void extractLibrariesFromJar(Path jarPath) throws IOException { + try (JarFile jarFile = new JarFile(jarPath.toFile())) { + Enumeration entries = jarFile.entries(); + + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + + if (entry.getName().startsWith(LIBRARIES_PREFIX)) { + processLibraryEntry(jarFile, entry); + } + } + } + } + + private void processLibraryEntry(JarFile jarFile, JarEntry entry) throws IOException { + String relativePath = entry.getName().substring(LIBRARIES_PREFIX.length()); + File extractedFile = new File(LIBRARIES_DIR, relativePath); + + if (entry.isDirectory()) { + Files.createDirectories(extractedFile.toPath()); + } else if (entry.getName().endsWith(PATCH_EXTENSION)) { + processPatchEntry(entry); + } else { + extractLibraryFile(jarFile, entry, extractedFile); + } + } + + private void extractLibraryFile(JarFile jarFile, JarEntry entry, File extractedFile) throws IOException { + File parentDir = extractedFile.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); + } + + try (InputStream input = jarFile.getInputStream(entry); + FileOutputStream output = new FileOutputStream(extractedFile)) { + copyStream(input, output); + } + + addToClasspath(extractedFile); + } + + private void processPatchEntry(JarEntry entry) throws IOException { + try (InputStream inputStream = LibraryLoader.class.getResourceAsStream(LIBRARIES_LIST_RESOURCE); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + + if (inputStream == null) { + throw new IOException("Libraries list resource not found: " + LIBRARIES_LIST_RESOURCE); + } + + String entryDirectoryName = extractDirectoryName(entry.getName()); + boolean foundArtifact = false; + String line; + + while ((line = reader.readLine()) != null) { + LibraryInfo libraryInfo = parseLibraryLine(line); + if (libraryInfo == null) continue; + + String libraryDirectoryName = extractDirectoryName(libraryInfo.jarPath); + + if (entryDirectoryName.equalsIgnoreCase(libraryDirectoryName)) { + foundArtifact = true; + handleLibraryFromPatch(libraryInfo); + } + } + + if (!foundArtifact) { + String artifactName = extractArtifactName(entry.getName()); + Logger.error("Unable to find library: " + artifactName); + throw new RuntimeException("Missing library: " + artifactName); + } + } + } + + private String extractDirectoryName(String path) { + return path.replaceFirst("^" + LIBRARIES_PREFIX, "") + .replaceFirst("/[^/]+$", ""); + } + + private String extractArtifactName(String entryName) { + String[] parts = entryName.split("/"); + String fileName = parts[parts.length - 1]; + return fileName.replace(PATCH_EXTENSION, ""); + } + + private LibraryInfo parseLibraryLine(String line) { + if (line == null || line.trim().isEmpty()) { + return null; + } + + String[] parts = line.split("\\s+"); + if (parts.length < 3) { + return null; + } + + return new LibraryInfo(parts[1], parts[2]); + } + + private void handleLibraryFromPatch(LibraryInfo libraryInfo) throws IOException { + File libraryFile = new File(LIBRARIES_DIR, libraryInfo.jarPath); + + if (!libraryFile.exists()) { + File downloadedFile = downloadLibrary(libraryInfo.jarPath); + + if (downloadedFile == null) { + throw new IOException("Failed to download missing library: " + libraryInfo.artifact); + } + + libraryFile = downloadedFile; + } + + addToClasspath(libraryFile); + } + + private File downloadLibrary(String artifactPath) { + for (String repository : MAVEN_REPOSITORIES) { + try { + String downloadUrl = repository + artifactPath; + File downloadedFile = new File(LIBRARIES_DIR, artifactPath); + + if (downloadFile(downloadUrl, downloadedFile)) { + return downloadedFile; + } + } catch (Exception e) { + // Continue trying other repositories + } + } + + return null; + } + + private boolean downloadFile(String urlString, File outputFile) { + try { + File parentDir = outputFile.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); + } + + URL url = new URL(urlString); + URLConnection connection = url.openConnection(); + connection.setConnectTimeout(30000); + connection.setReadTimeout(60000); + + try (InputStream input = connection.getInputStream(); + FileOutputStream output = new FileOutputStream(outputFile)) { + copyStream(input, output); + } + + return outputFile.exists() && outputFile.length() > 0; + + } catch (Exception e) { + if (outputFile.exists()) { + outputFile.delete(); + } + + return false; + } + } + + private void addToClasspath(File jarFile) throws IOException { + try (JarFile jar = new JarFile(jarFile)) { + InstrumentationManager.getInstrumentation().appendToSystemClassLoaderSearch(jar); + } + } + + private record LibraryInfo(String artifact, String jarPath) { } +} diff --git a/shuttle/src/main/java/org/bxteam/shuttle/patch/PatchBuilder.java b/shuttle/src/main/java/org/bxteam/shuttle/patch/PatchBuilder.java new file mode 100644 index 0000000..1a8b74c --- /dev/null +++ b/shuttle/src/main/java/org/bxteam/shuttle/patch/PatchBuilder.java @@ -0,0 +1,248 @@ +package org.bxteam.shuttle.patch; + +import io.sigpipe.jbsdiff.InvalidHeaderException; +import io.sigpipe.jbsdiff.Patch; +import org.apache.commons.compress.compressors.CompressorException; +import org.bxteam.shuttle.Shuttle; +import org.bxteam.shuttle.logger.Logger; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class PatchBuilder { + private static final String CACHE_DIR = "cache"; + private static final String VERSIONS_DIR = "versions"; + private static final String META_INF_PREFIX = "/META-INF/"; + private static final int BUFFER_SIZE = 8192; + + private static String readResourceField(int index, String resourceName) { + final String resourcePath = META_INF_PREFIX + resourceName; + + try (InputStream inputStream = PatchBuilder.class.getResourceAsStream(resourcePath); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + + if (inputStream == null) { + throw new IOException("Resource not found: " + resourcePath); + } + + String line = reader.readLine(); + if (line == null) { + throw new IOException("Empty resource file: " + resourcePath); + } + + String[] parts = line.split("\\s+"); + if (parts.length <= index) { + throw new IOException("Invalid resource format or index out of bounds: " + resourcePath); + } + + return parts[index].trim(); + + } catch (IOException e) { + throw new RuntimeException("Unable to read " + resourceName + " at index " + index, e); + } + } + + public static String computeFileSha256(File file) throws NoSuchAlgorithmException, IOException { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + + try (FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis)) { + + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead; + + while ((bytesRead = bis.read(buffer)) != -1) { + digest.update(buffer, 0, bytesRead); + } + } + + byte[] hashBytes = digest.digest(); + StringBuilder hexString = new StringBuilder(); + for (byte b : hashBytes) { + hexString.append(String.format("%02x", b)); + } + + return hexString.toString(); + } + + public void start(Shuttle.Provider versionProvider) throws IOException { + try { + start(versionProvider.get()); + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new IOException("Error during patch building process", e); + } + } + + public void start(String mcVersion) throws IOException { + if (mcVersion == null || mcVersion.trim().isEmpty()) { + throw new IllegalArgumentException("Minecraft version cannot be null or empty"); + } + + Logger.info("Loading Minecraft version " + mcVersion); + + try { + createDirectories(); + + String sha256Hash = readResourceField(0, "download-context"); + String vanillaUrl = readResourceField(1, "download-context"); + + Path vanillaBundler = downloadVanillaBundler(mcVersion, vanillaUrl, sha256Hash); + String patchedJarName = extractPatchedJarName(); + + applyPatches(mcVersion, vanillaBundler, patchedJarName); + } catch (Exception e) { + throw new IOException("Failed to build patched jar for version " + mcVersion, e); + } + } + + private void createDirectories() throws IOException { + Files.createDirectories(Paths.get(VERSIONS_DIR)); + Files.createDirectories(Paths.get(CACHE_DIR)); + } + + private Path downloadVanillaBundler(String mcVersion, String vanillaUrl, String expectedSha256) throws IOException { + Path vanillaBundler = Paths.get(CACHE_DIR, "vanilla-bundler-" + mcVersion + ".jar"); + + boolean needsDownload = !Files.exists(vanillaBundler); + + if (!needsDownload) { + try { + String actualSha256 = computeFileSha256(vanillaBundler.toFile()); + needsDownload = !expectedSha256.equals(actualSha256); + if (needsDownload) { + Logger.info("SHA-256 mismatch, re-downloading vanilla jar"); + } + } catch (NoSuchAlgorithmException e) { + throw new IOException("SHA-256 algorithm not available", e); + } + } + + if (needsDownload) { + Logger.info("Downloading vanilla jar..."); + downloadFile(vanillaUrl, vanillaBundler); + } + + return vanillaBundler; + } + + /** + * Downloads a file from a URL. + */ + private void downloadFile(String urlString, Path outputPath) throws IOException { + URL url = new URL(urlString); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(30000); + connection.setReadTimeout(60000); + + try (BufferedInputStream in = new BufferedInputStream(connection.getInputStream()); + FileOutputStream fos = new FileOutputStream(outputPath.toFile()); + BufferedOutputStream out = new BufferedOutputStream(fos)) { + + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead; + while ((bytesRead = in.read(buffer)) != -1) { + out.write(buffer, 0, bytesRead); + } + } finally { + connection.disconnect(); + } + } + + private String extractPatchedJarName() { + String versionListEntry = readResourceField(2, "versions.list"); + String[] parts = versionListEntry.split("/"); + if (parts.length < 2) { + throw new RuntimeException("Invalid versions.list format"); + } + return parts[1]; + } + + private void applyPatches(String mcVersion, Path vanillaBundler, String patchedJarName) throws IOException { + Logger.info("Applying patches..."); + + Path vanillaJar = extractVanillaJar(mcVersion, vanillaBundler); + + File patchFile = extractPatchFile(mcVersion); + + Path outputJar = Paths.get(VERSIONS_DIR, mcVersion, patchedJarName); + Files.createDirectories(outputJar.getParent()); + + try { + applyPatch(vanillaJar.toFile(), patchFile, outputJar.toFile()); + addToClasspath(outputJar.toFile()); + } catch (Exception e) { + throw new IOException("Failed to apply patch", e); + } + } + + private Path extractVanillaJar(String mcVersion, Path vanillaBundler) throws IOException { + Path vanillaJar = Paths.get(CACHE_DIR, "vanilla-" + mcVersion + ".jar"); + + try (JarFile jarFile = new JarFile(vanillaBundler.toFile())) { + JarEntry entry = jarFile.getJarEntry("META-INF/versions/" + mcVersion + "/server-" + mcVersion + ".jar"); + + if (entry == null) { + throw new IOException("Vanilla jar entry not found in bundler for version " + mcVersion); + } + + try (InputStream inputStream = jarFile.getInputStream(entry)) { + Files.copy(inputStream, vanillaJar, StandardCopyOption.REPLACE_EXISTING); + } + } + + return vanillaJar; + } + + private File extractPatchFile(String mcVersion) throws IOException { + String resourcePath = "/META-INF/versions/" + mcVersion + "/server-" + mcVersion + ".jar.patch"; + return extractResourceToFile(resourcePath, CACHE_DIR); + } + + private File extractResourceToFile(String resourcePath, String outputDir) throws IOException { + try (InputStream resourceStream = PatchBuilder.class.getResourceAsStream(resourcePath)) { + if (resourceStream == null) { + throw new IOException("Resource not found: " + resourcePath); + } + + Path outputDirectory = Paths.get(outputDir); + Files.createDirectories(outputDirectory); + + String fileName = Paths.get(resourcePath).getFileName().toString(); + Path outputPath = outputDirectory.resolve(fileName); + + Files.copy(resourceStream, outputPath, StandardCopyOption.REPLACE_EXISTING); + return outputPath.toFile(); + } + } + + private void applyPatch(File vanillaJar, File patchFile, File outputJar) throws IOException, CompressorException, InvalidHeaderException { + byte[] vanillaBytes = Files.readAllBytes(vanillaJar.toPath()); + byte[] patchBytes = Files.readAllBytes(patchFile.toPath()); + + try (FileOutputStream outputStream = new FileOutputStream(outputJar)) { + Patch.patch(vanillaBytes, patchBytes, outputStream); + } + + if (!outputJar.exists()) { + throw new IOException("Patched jar was not created successfully"); + } + } + + private void addToClasspath(File jarFile) throws IOException { + try (JarFile jar = new JarFile(jarFile)) { + InstrumentationManager.getInstrumentation().appendToSystemClassLoaderSearch(jar); + } + } +} From cd8ddb5dc6bd06b072eb904223e2173b1be1cf65 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 17 Jul 2025 02:00:55 +0300 Subject: [PATCH 46/67] load it here --- .../features/0001-Rebrand.patch | 28 +++++++++++++++---- .../org/bxteam/divinemc/DivineBootstrap.java | 13 --------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index 334fb12..0e5a5d2 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -18,10 +18,10 @@ index 394443d00e661715439be1e56dddc129947699a4..480ad57a6b7b74e6b83e9c6ceb69ea1f public CrashReport(String title, Throwable exception) { io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java -index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..9d89af099c6e0f50c73a9372e1ef7f1b0ef932c5 100644 +index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..a058ef4d74da29372a894c8a4d619b2d5ba0c74f 100644 --- a/net/minecraft/server/Main.java +++ b/net/minecraft/server/Main.java -@@ -64,6 +64,17 @@ import org.slf4j.Logger; +@@ -64,11 +64,34 @@ import org.slf4j.Logger; public class Main { private static final Logger LOGGER = LogUtils.getLogger(); @@ -39,15 +39,33 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..9d89af099c6e0f50c73a9372e1ef7f1b @SuppressForbidden( reason = "System.out needed before bootstrap" ) -@@ -125,7 +136,6 @@ public class Main { + @DontObfuscate + public static void main(final OptionSet optionSet) { // CraftBukkit - replaces main(String[] args) ++ Path path2 = Paths.get("eula.txt"); ++ Eula eula = new Eula(path2); ++ boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree"); ++ if (eulaAgreed) { ++ LOGGER.error("You have used the Spigot command line EULA agreement flag."); ++ LOGGER.error("By using this setting you are indicating your agreement to Mojang's EULA (https://aka.ms/MinecraftEULA)."); ++ LOGGER.error("If you do not agree to the above EULA please stop your server and remove this flag immediately."); ++ } ++ if (!eula.hasAgreedToEULA() && !eulaAgreed) { ++ LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info."); ++ return; ++ } + io.papermc.paper.util.LogManagerShutdownThread.hook(); // Paper - Improved watchdog support + SharedConstants.tryDetectVersion(); + /* CraftBukkit start - Replace everything +@@ -124,8 +147,6 @@ public class Main { + DedicatedServerSettings dedicatedServerSettings = new DedicatedServerSettings(optionSet); // CraftBukkit - CLI argument support dedicatedServerSettings.forceSave(); RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression); - Path path2 = Paths.get("eula.txt"); +- Path path2 = Paths.get("eula.txt"); - Eula eula = new Eula(path2); // Paper start - load config files early for access below if needed 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")); -@@ -148,19 +158,6 @@ public class Main { +@@ -148,19 +169,6 @@ public class Main { return; } diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java index 52b7f04..4af97d7 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java @@ -68,19 +68,6 @@ public class DivineBootstrap { System.setProperty("jdk.console", "java.base"); SharedConstants.tryDetectVersion(); - Path path2 = Paths.get("eula.txt"); - Eula eula = new Eula(path2); - boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree"); - if (eulaAgreed) { - LOGGER.error("You have used the Spigot command line EULA agreement flag."); - LOGGER.error("By using this setting you are indicating your agreement to Mojang's EULA (https://aka.ms/MinecraftEULA)."); - LOGGER.error("If you do not agree to the above EULA please stop your server and remove this flag immediately."); - } - if (!eula.hasAgreedToEULA() && !eulaAgreed) { - LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info."); - System.exit(0); - } - getStartupVersionMessages().forEach(LOGGER::info); } catch (Throwable t) { t.printStackTrace(); From 939c2389d595f961c3879c8893e596987ce95c44 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:24:36 +0300 Subject: [PATCH 47/67] move small patches back to sources --- .../features/0001-Rebrand.patch | 4 +- .../features/0002-Configuration.patch | 4 +- ...03-Completely-remove-Mojang-profiler.patch | 76 +++++++++---------- ...til.patch => 0010-lithium-fast_util.patch} | 0 ...> 0011-C2ME-Optimize-world-gen-math.patch} | 0 ...7075.patch => 0012-Re-Fix-MC-117075.patch} | 0 ...ast_hand_swing-entity.fast_elytra_ch.patch | 32 -------- ...per-Clear-dirty-stats-after-copying.patch} | 0 ....patch => 0014-Async-locate-command.patch} | 0 .../0014-C2ME-Reduce-Allocations.patch | 24 ------ ...Carpet-Fixes-RecipeManager-Optimize.patch} | 0 ...-lithium-faster-chunk-serialization.patch} | 0 ...0017-C2ME-optimize-noise-generation.patch} | 0 .../features/0017-Fix-MC-119417.patch | 19 ----- .../features/0018-Fix-MC-7569.patch | 20 ----- ...=> 0018-Optimize-block-state-lookup.patch} | 2 +- ...n-t-respond-ping-before-start-fully.patch} | 0 .../features/0019-Fix-MC-110386.patch | 19 ----- ...rs-that-were-dead-on-server-restart.patch} | 2 +- ...67.patch => 0021-Configurable-MC-67.patch} | 0 .../features/0021-Fix-MC-31819.patch | 23 ------ ...patch => 0022-Configurable-MC-59471.patch} | 0 .../features/0022-Fix-MC-172801.patch | 26 ------- ...h => 0023-Use-Java-s-Math-functions.patch} | 0 ...ay.patch => 0024-Disable-leaf-decay.patch} | 0 ...-Fixes-Fix-Slime-Block-Bounce-Logic.patch} | 0 ...patch => 0026-Optimize-entity-brain.patch} | 0 ...-distanceToSqr-call-in-ServerEntity.patch} | 0 ...pet-Fixes-Optimized-getBiome-method.patch} | 0 ...w-throttling-hopper-checks-if-the-t.patch} | 0 ...030-Carpet-Fixes-Sheep-Optimization.patch} | 0 ...S-Addition-Optimized-dragon-respawn.patch} | 0 ... 0032-ModernFix-compact_bit_storage.patch} | 2 +- .../features/0033-Fix-sprint-glitch.patch | 19 ----- ...3-Option-to-disable-disconnect.spam.patch} | 0 ...ble-saving-of-snowball-and-firework.patch} | 0 ... => 0035-Snowball-and-Egg-knockback.patch} | 0 ....patch => 0036-Optimize-suffocation.patch} | 2 +- ...> 0037-Reduce-chunk-loading-lookups.patch} | 0 ...gurable-movement-speed-for-entities.patch} | 0 ...t-dirty-flag-when-loading-maps-from.patch} | 0 ...BlockEntity-ticking-isRemoved-check.patch} | 0 ...eird-movement-and-disable-teleporti.patch} | 2 +- ...-Raids.patch => 0042-Optimize-Raids.patch} | 0 ...SparklyPaper-Optimize-canSee-checks.patch} | 0 ...Small-optimization-to-LinearPalette.patch} | 0 ...=> 0045-Use-switch-for-VarInt-write.patch} | 0 ...luids.patch => 0046-Optimize-Fluids.patch} | 0 ... 0047-Optimize-Structure-Generation.patch} | 0 ...tch => 0048-Implement-NoChatReports.patch} | 4 +- ...tion.patch => 0049-Lag-compensation.patch} | 8 +- ...reads.patch => 0050-Virtual-Threads.patch} | 6 +- ...g.patch => 0051-Async-Chunk-Sending.patch} | 0 ...Command-block-parse-results-caching.patch} | 0 ...> 0053-Player-ProfileResult-caching.patch} | 0 ...patch => 0054-Implement-Secure-Seed.patch} | 0 ...=> 0055-Dynamic-Activation-of-Brain.patch} | 4 +- ...tch => 0056-Petal-Async-Pathfinding.patch} | 0 ...=> 0057-Petal-Multithreaded-Tracker.patch} | 4 +- ...58-Pufferfish-Optimize-mob-spawning.patch} | 2 +- ...r-ShapelessRecipes-comparison-for-V.patch} | 0 ...0060-C2ME-Density-Function-Compiler.patch} | 0 ...patch => 0061-Clump-experience-orbs.patch} | 0 ...SparklyPaper-Parallel-world-ticking.patch} | 14 ++-- ...> 0063-MSPT-Tracking-for-each-world.patch} | 4 +- ...ch => 0064-Catch-update-suppressors.patch} | 4 +- ...ch => 0065-Regionized-Chunk-Ticking.patch} | 0 ....patch => 0066-C2ME-Limit-NBT-cache.patch} | 0 ...2ME-Optimize-Aquifer-and-Beardifier.patch} | 0 ...patch => 0068-Copper-Bulb-1gt-delay.patch} | 0 ...lay.patch => 0069-Crafter-1gt-delay.patch} | 0 ...tch => 0070-Raytrace-Entity-Tracker.patch} | 0 ...ead.patch => 0071-Async-Join-Thread.patch} | 0 ....patch => 0072-Leaves-Protocol-Core.patch} | 4 +- ...=> 0073-Leaves-Xaero-s-Map-Protocol.patch} | 2 +- ... => 0074-Leaves-Syncmatica-Protocol.patch} | 2 +- ...R-Optimise-non-flush-packet-sending.patch} | 0 ...h => 0076-Linear-region-file-format.patch} | 0 ...> 0077-Cleanup-dead-code-from-Paper.patch} | 0 ...-Disable-offline-warn-if-using-proxy.patch | 19 ----- .../ChunkTickConstants.java.patch} | 10 +-- .../advancements/Advancement.java.patch} | 10 +-- .../net/minecraft/core/BlockPos.java.patch} | 13 +--- .../server/MinecraftServer.java.patch} | 10 +-- .../server/PlayerAdvancements.java.patch} | 10 +-- .../dedicated/DedicatedServer.java.patch} | 23 +++--- .../server/level/ServerPlayer.java.patch | 10 +++ .../server/rcon/RconConsoleSource.java.patch | 11 +++ .../minecraft/world/entity/Entity.java.patch} | 19 +---- .../world/entity/LivingEntity.java.patch | 42 ++++++++++ .../goal/target/HurtByTargetGoal.java.patch | 10 +++ .../ai/sensing/SecondaryPoiSensor.java.patch} | 19 +---- .../entity/monster/ZombieVillager.java.patch} | 11 +-- .../world/entity/player/Player.java.patch | 14 ++++ .../level/LocalMobCapCalculator.java.patch} | 15 +--- .../level/levelgen/SurfaceRules.java.patch} | 11 +-- .../levelgen/feature/OreFeature.java.patch | 11 +++ .../features/0003-Delete-timings.patch | 6 +- ...reads.patch => 0012-Virtual-Threads.patch} | 0 ...patch => 0013-Implement-Secure-Seed.patch} | 0 ...=> 0014-Petal-Multithreaded-Tracker.patch} | 2 +- ...ver-getWorlds-ArrayList-with-a-fastu.patch | 21 ----- ...15-Pufferfish-Optimize-mob-spawning.patch} | 0 ...r-ShapelessRecipes-comparison-for-V.patch} | 0 ...SparklyPaper-Parallel-world-ticking.patch} | 0 ...patch => 0018-Rewrite-ReferenceList.patch} | 0 ....patch => 0019-Leaves-Protocol-Core.patch} | 0 .../common/util/MoonriseConstants.java.patch} | 10 +-- .../manager/PaperEventManager.java.patch} | 15 +--- .../bukkit/craftbukkit/CraftServer.java.patch | 11 +++ .../command/CraftCommandMap.java.patch} | 10 +-- 111 files changed, 217 insertions(+), 460 deletions(-) rename divinemc-server/minecraft-patches/features/{0011-lithium-fast_util.patch => 0010-lithium-fast_util.patch} (100%) rename divinemc-server/minecraft-patches/features/{0015-C2ME-Optimize-world-gen-math.patch => 0011-C2ME-Optimize-world-gen-math.patch} (100%) rename divinemc-server/minecraft-patches/features/{0016-Re-Fix-MC-117075.patch => 0012-Re-Fix-MC-117075.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0012-lithium-entity.fast_hand_swing-entity.fast_elytra_ch.patch rename divinemc-server/minecraft-patches/features/{0024-SparklyPaper-Clear-dirty-stats-after-copying.patch => 0013-SparklyPaper-Clear-dirty-stats-after-copying.patch} (100%) rename divinemc-server/minecraft-patches/features/{0025-Async-locate-command.patch => 0014-Async-locate-command.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0014-C2ME-Reduce-Allocations.patch rename divinemc-server/minecraft-patches/features/{0026-Carpet-Fixes-RecipeManager-Optimize.patch => 0015-Carpet-Fixes-RecipeManager-Optimize.patch} (100%) rename divinemc-server/minecraft-patches/features/{0027-lithium-faster-chunk-serialization.patch => 0016-lithium-faster-chunk-serialization.patch} (100%) rename divinemc-server/minecraft-patches/features/{0031-C2ME-optimize-noise-generation.patch => 0017-C2ME-optimize-noise-generation.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch delete mode 100644 divinemc-server/minecraft-patches/features/0018-Fix-MC-7569.patch rename divinemc-server/minecraft-patches/features/{0034-Optimize-block-state-lookup.patch => 0018-Optimize-block-state-lookup.patch} (93%) rename divinemc-server/minecraft-patches/features/{0035-Don-t-respond-ping-before-start-fully.patch => 0019-Don-t-respond-ping-before-start-fully.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0019-Fix-MC-110386.patch rename divinemc-server/minecraft-patches/features/{0036-Respawn-players-that-were-dead-on-server-restart.patch => 0020-Respawn-players-that-were-dead-on-server-restart.patch} (94%) rename divinemc-server/minecraft-patches/features/{0037-Configurable-MC-67.patch => 0021-Configurable-MC-67.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0021-Fix-MC-31819.patch rename divinemc-server/minecraft-patches/features/{0038-Configurable-MC-59471.patch => 0022-Configurable-MC-59471.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0022-Fix-MC-172801.patch rename divinemc-server/minecraft-patches/features/{0039-Use-Java-s-Math-functions.patch => 0023-Use-Java-s-Math-functions.patch} (100%) rename divinemc-server/minecraft-patches/features/{0040-Disable-leaf-decay.patch => 0024-Disable-leaf-decay.patch} (100%) rename divinemc-server/minecraft-patches/features/{0041-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch => 0025-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch} (100%) rename divinemc-server/minecraft-patches/features/{0042-Optimize-entity-brain.patch => 0026-Optimize-entity-brain.patch} (100%) rename divinemc-server/minecraft-patches/features/{0043-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch => 0027-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch} (100%) rename divinemc-server/minecraft-patches/features/{0044-Carpet-Fixes-Optimized-getBiome-method.patch => 0028-Carpet-Fixes-Optimized-getBiome-method.patch} (100%) rename divinemc-server/minecraft-patches/features/{0045-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch => 0029-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch} (100%) rename divinemc-server/minecraft-patches/features/{0046-Carpet-Fixes-Sheep-Optimization.patch => 0030-Carpet-Fixes-Sheep-Optimization.patch} (100%) rename divinemc-server/minecraft-patches/features/{0047-Carpet-AMS-Addition-Optimized-dragon-respawn.patch => 0031-Carpet-AMS-Addition-Optimized-dragon-respawn.patch} (100%) rename divinemc-server/minecraft-patches/features/{0048-ModernFix-compact_bit_storage.patch => 0032-ModernFix-compact_bit_storage.patch} (95%) delete mode 100644 divinemc-server/minecraft-patches/features/0033-Fix-sprint-glitch.patch rename divinemc-server/minecraft-patches/features/{0049-Option-to-disable-disconnect.spam.patch => 0033-Option-to-disable-disconnect.spam.patch} (100%) rename divinemc-server/minecraft-patches/features/{0050-Option-to-disable-saving-of-snowball-and-firework.patch => 0034-Option-to-disable-saving-of-snowball-and-firework.patch} (100%) rename divinemc-server/minecraft-patches/features/{0051-Snowball-and-Egg-knockback.patch => 0035-Snowball-and-Egg-knockback.patch} (100%) rename divinemc-server/minecraft-patches/features/{0052-Optimize-suffocation.patch => 0036-Optimize-suffocation.patch} (95%) rename divinemc-server/minecraft-patches/features/{0053-Reduce-chunk-loading-lookups.patch => 0037-Reduce-chunk-loading-lookups.patch} (100%) rename divinemc-server/minecraft-patches/features/{0054-Configurable-movement-speed-for-entities.patch => 0038-Configurable-movement-speed-for-entities.patch} (100%) rename divinemc-server/minecraft-patches/features/{0055-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch => 0039-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch} (100%) rename divinemc-server/minecraft-patches/features/{0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch => 0040-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch} (100%) rename divinemc-server/minecraft-patches/features/{0057-Option-to-allow-weird-movement-and-disable-teleporti.patch => 0041-Option-to-allow-weird-movement-and-disable-teleporti.patch} (98%) rename divinemc-server/minecraft-patches/features/{0058-Optimize-Raids.patch => 0042-Optimize-Raids.patch} (100%) rename divinemc-server/minecraft-patches/features/{0059-SparklyPaper-Optimize-canSee-checks.patch => 0043-SparklyPaper-Optimize-canSee-checks.patch} (100%) rename divinemc-server/minecraft-patches/features/{0060-Small-optimization-to-LinearPalette.patch => 0044-Small-optimization-to-LinearPalette.patch} (100%) rename divinemc-server/minecraft-patches/features/{0061-Use-switch-for-VarInt-write.patch => 0045-Use-switch-for-VarInt-write.patch} (100%) rename divinemc-server/minecraft-patches/features/{0062-Optimize-Fluids.patch => 0046-Optimize-Fluids.patch} (100%) rename divinemc-server/minecraft-patches/features/{0063-Optimize-Structure-Generation.patch => 0047-Optimize-Structure-Generation.patch} (100%) rename divinemc-server/minecraft-patches/features/{0064-Implement-NoChatReports.patch => 0048-Implement-NoChatReports.patch} (98%) rename divinemc-server/minecraft-patches/features/{0065-Lag-compensation.patch => 0049-Lag-compensation.patch} (98%) rename divinemc-server/minecraft-patches/features/{0066-Virtual-Threads.patch => 0050-Virtual-Threads.patch} (96%) rename divinemc-server/minecraft-patches/features/{0067-Async-Chunk-Sending.patch => 0051-Async-Chunk-Sending.patch} (100%) rename divinemc-server/minecraft-patches/features/{0068-Command-block-parse-results-caching.patch => 0052-Command-block-parse-results-caching.patch} (100%) rename divinemc-server/minecraft-patches/features/{0069-Player-ProfileResult-caching.patch => 0053-Player-ProfileResult-caching.patch} (100%) rename divinemc-server/minecraft-patches/features/{0070-Implement-Secure-Seed.patch => 0054-Implement-Secure-Seed.patch} (100%) rename divinemc-server/minecraft-patches/features/{0071-Dynamic-Activation-of-Brain.patch => 0055-Dynamic-Activation-of-Brain.patch} (99%) rename divinemc-server/minecraft-patches/features/{0072-Petal-Async-Pathfinding.patch => 0056-Petal-Async-Pathfinding.patch} (100%) rename divinemc-server/minecraft-patches/features/{0073-Petal-Multithreaded-Tracker.patch => 0057-Petal-Multithreaded-Tracker.patch} (99%) rename divinemc-server/minecraft-patches/features/{0074-Pufferfish-Optimize-mob-spawning.patch => 0058-Pufferfish-Optimize-mob-spawning.patch} (99%) rename divinemc-server/minecraft-patches/features/{0075-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch => 0059-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch} (100%) rename divinemc-server/minecraft-patches/features/{0076-C2ME-Density-Function-Compiler.patch => 0060-C2ME-Density-Function-Compiler.patch} (100%) rename divinemc-server/minecraft-patches/features/{0077-Clump-experience-orbs.patch => 0061-Clump-experience-orbs.patch} (100%) rename divinemc-server/minecraft-patches/features/{0078-SparklyPaper-Parallel-world-ticking.patch => 0062-SparklyPaper-Parallel-world-ticking.patch} (99%) rename divinemc-server/minecraft-patches/features/{0079-MSPT-Tracking-for-each-world.patch => 0063-MSPT-Tracking-for-each-world.patch} (93%) rename divinemc-server/minecraft-patches/features/{0080-Catch-update-suppressors.patch => 0064-Catch-update-suppressors.patch} (96%) rename divinemc-server/minecraft-patches/features/{0081-Regionized-Chunk-Ticking.patch => 0065-Regionized-Chunk-Ticking.patch} (100%) rename divinemc-server/minecraft-patches/features/{0083-C2ME-Limit-NBT-cache.patch => 0066-C2ME-Limit-NBT-cache.patch} (100%) rename divinemc-server/minecraft-patches/features/{0085-C2ME-Optimize-Aquifer-and-Beardifier.patch => 0067-C2ME-Optimize-Aquifer-and-Beardifier.patch} (100%) rename divinemc-server/minecraft-patches/features/{0087-Copper-Bulb-1gt-delay.patch => 0068-Copper-Bulb-1gt-delay.patch} (100%) rename divinemc-server/minecraft-patches/features/{0088-Crafter-1gt-delay.patch => 0069-Crafter-1gt-delay.patch} (100%) rename divinemc-server/minecraft-patches/features/{0089-Raytrace-Entity-Tracker.patch => 0070-Raytrace-Entity-Tracker.patch} (100%) rename divinemc-server/minecraft-patches/features/{0090-Async-Join-Thread.patch => 0071-Async-Join-Thread.patch} (100%) rename divinemc-server/minecraft-patches/features/{0092-Leaves-Protocol-Core.patch => 0072-Leaves-Protocol-Core.patch} (97%) rename divinemc-server/minecraft-patches/features/{0093-Leaves-Xaero-s-Map-Protocol.patch => 0073-Leaves-Xaero-s-Map-Protocol.patch} (92%) rename divinemc-server/minecraft-patches/features/{0094-Leaves-Syncmatica-Protocol.patch => 0074-Leaves-Syncmatica-Protocol.patch} (95%) rename divinemc-server/minecraft-patches/features/{0095-Paper-PR-Optimise-non-flush-packet-sending.patch => 0075-Paper-PR-Optimise-non-flush-packet-sending.patch} (100%) rename divinemc-server/minecraft-patches/features/{0096-Linear-region-file-format.patch => 0076-Linear-region-file-format.patch} (100%) rename divinemc-server/minecraft-patches/features/{0097-Cleanup-dead-code-from-Paper.patch => 0077-Cleanup-dead-code-from-Paper.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0086-Disable-offline-warn-if-using-proxy.patch rename divinemc-server/minecraft-patches/{features/0084-Configurable-player-spawn-tracking-range.patch => sources/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java.patch} (60%) rename divinemc-server/minecraft-patches/{features/0032-Skip-cloning-advancement-criteria.patch => sources/net/minecraft/advancements/Advancement.java.patch} (56%) rename divinemc-server/minecraft-patches/{features/0013-lithium-cached_iterate_outwards.patch => sources/net/minecraft/core/BlockPos.java.patch} (66%) rename divinemc-server/minecraft-patches/{features/0091-Shutdown-executors.patch => sources/net/minecraft/server/MinecraftServer.java.patch} (51%) rename divinemc-server/minecraft-patches/{features/0082-Use-fastutil-for-criterion-data.patch => sources/net/minecraft/server/PlayerAdvancements.java.patch} (67%) rename divinemc-server/minecraft-patches/{features/0010-Pufferfish-SIMD-support.patch => sources/net/minecraft/server/dedicated/DedicatedServer.java.patch} (67%) create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch rename divinemc-server/minecraft-patches/{features/0029-VMP-skip-entity-move-if-movement-is-zero.patch => sources/net/minecraft/world/entity/Entity.java.patch} (55%) create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch rename divinemc-server/minecraft-patches/{features/0028-lithium-skip-useless-secondary-poi-sensor.patch => sources/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java.patch} (51%) rename divinemc-server/minecraft-patches/{features/0020-Fix-MC-200418.patch => sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch} (56%) create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch rename divinemc-server/minecraft-patches/{features/0030-VMP-store-mob-counts-in-an-array.patch => sources/net/minecraft/world/level/LocalMobCapCalculator.java.patch} (55%) rename divinemc-server/minecraft-patches/{features/0023-Fix-MC-258859.patch => sources/net/minecraft/world/level/levelgen/SurfaceRules.java.patch} (71%) create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/feature/OreFeature.java.patch rename divinemc-server/paper-patches/features/{0015-Virtual-Threads.patch => 0012-Virtual-Threads.patch} (100%) rename divinemc-server/paper-patches/features/{0016-Implement-Secure-Seed.patch => 0013-Implement-Secure-Seed.patch} (100%) rename divinemc-server/paper-patches/features/{0017-Petal-Multithreaded-Tracker.patch => 0014-Petal-Multithreaded-Tracker.patch} (97%) delete mode 100644 divinemc-server/paper-patches/features/0014-Replace-CraftServer-getWorlds-ArrayList-with-a-fastu.patch rename divinemc-server/paper-patches/features/{0018-Pufferfish-Optimize-mob-spawning.patch => 0015-Pufferfish-Optimize-mob-spawning.patch} (100%) rename divinemc-server/paper-patches/features/{0019-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch => 0016-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch} (100%) rename divinemc-server/paper-patches/features/{0020-SparklyPaper-Parallel-world-ticking.patch => 0017-SparklyPaper-Parallel-world-ticking.patch} (100%) rename divinemc-server/paper-patches/features/{0021-Rewrite-ReferenceList.patch => 0018-Rewrite-ReferenceList.patch} (100%) rename divinemc-server/paper-patches/features/{0023-Leaves-Protocol-Core.patch => 0019-Leaves-Protocol-Core.patch} (100%) rename divinemc-server/paper-patches/{features/0022-Configurable-Max-View-Distance.patch => files/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java.patch} (52%) rename divinemc-server/paper-patches/{features/0012-Skip-event-if-no-listeners.patch => files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch} (68%) create mode 100644 divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch rename divinemc-server/paper-patches/{features/0013-Force-Minecraft-command.patch => files/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java.patch} (61%) diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index 0e5a5d2..c76532c 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -86,10 +86,10 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..a058ef4d74da29372a894c8a4d619b2d String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck(); if (awtException != null) { diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 1c064e1d2edcda5d0b10fb3cc3417937ac0b3835..3b6d2cf670caefd42536de896d3e13c96ebf87b1 100644 +index d651ddade8a460c25f4f8d70822d9ef69f1acb4b..8fce263f8cab4e0ff2ee6fe4fd9e46bbd0bbde19 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1176,6 +1176,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && this.tickCount % autosavePeriod == 0; try { this.isSaving = true; -@@ -1592,10 +1556,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop serverPlayer1.connection.suspendFlushing()); this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit // Paper start - optimise Folia entity scheduler -@@ -1709,9 +1665,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Purpur - Ridables @@ -429,7 +429,7 @@ index 3b6d2cf670caefd42536de896d3e13c96ebf87b1..16635681a7ed6c6db8434fc14f9ac7c9 try { serverLevel.tick(hasTimeLeft); } catch (Throwable var7) { -@@ -1766,34 +1715,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 1.0E-7) { movement = movement.multiply(this.stuckSpeedMultiplier); this.stuckSpeedMultiplier = Vec3.ZERO; -@@ -1160,7 +1152,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1162,7 +1154,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess // Paper start - ignore movement changes while inactive. if (isTemporarilyActive && !(this instanceof ItemEntity) && movement == getDeltaMovement() && type == MoverType.SELF) { setDeltaMovement(Vec3.ZERO); @@ -4053,7 +4053,7 @@ index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894 return; } // Paper end -@@ -1185,8 +1176,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1187,8 +1178,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.setPos(vec32); } @@ -4062,7 +4062,7 @@ index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894 boolean flag = !Mth.equal(movement.x, vec3.x); boolean flag1 = !Mth.equal(movement.z, vec3.z); this.horizontalCollision = flag || flag1; -@@ -1209,7 +1198,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1211,7 +1200,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } if (this.isRemoved()) { @@ -4071,7 +4071,7 @@ index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894 } else { if (this.horizontalCollision) { Vec3 deltaMovement = this.getDeltaMovement(); -@@ -1253,7 +1242,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1255,7 +1244,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess float blockSpeedFactor = this.getBlockSpeedFactor(); this.setDeltaMovement(this.getDeltaMovement().multiply(blockSpeedFactor, 1.0, blockSpeedFactor)); @@ -4079,7 +4079,7 @@ index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894 } } // Paper start - detailed watchdog information -@@ -3466,8 +3454,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3468,8 +3456,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.processPortalCooldown(); if (this.portalProcess != null) { if (this.portalProcess.processPortalTeleportation(serverLevel, this, this.canUsePortal(false))) { @@ -4088,7 +4088,7 @@ index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894 this.setPortalCooldown(); TeleportTransition portalDestination = this.portalProcess.getPortalDestination(serverLevel, this); if (portalDestination != null) { -@@ -3477,8 +3463,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3479,8 +3465,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.teleport(portalDestination); } } @@ -4097,7 +4097,7 @@ index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894 } else if (this.portalProcess.hasExpired()) { this.portalProcess = null; } -@@ -4045,15 +4029,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4047,15 +4031,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess entity.teleport(this.calculatePassengerTransition(teleportTransition, entity)); } @@ -4113,7 +4113,7 @@ index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894 return this; } -@@ -4069,11 +4050,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4071,11 +4052,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } @@ -4125,7 +4125,7 @@ index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894 return null; } else { // Paper start - Fix item duplication and teleport issues -@@ -4093,7 +4071,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4095,7 +4073,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess newLevel.resetEmptyTime(); teleportTransition.postTeleportTransition().onTransition(entityx); this.teleportSpectators(teleportTransition, oldLevel); @@ -4134,7 +4134,7 @@ index fa829d84cd47b68426bb30f662de6e05b608cc69..02f39e3dc420a5bd49cd6e247c9b1894 } } diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index ddd3acbc804cbc07eaccf578349d3f9e0e00b6fc..0c0144679c9d44d50af153c792d7e5da175365d8 100644 +index 590ccc9d181d401abd1154ae1f16b1230e8195f1..8df6ceea1536b12d87755c8a69e1b652d280600c 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java @@ -69,8 +69,6 @@ import net.minecraft.tags.FluidTags; @@ -4163,7 +4163,7 @@ index ddd3acbc804cbc07eaccf578349d3f9e0e00b6fc..0c0144679c9d44d50af153c792d7e5da } @Override -@@ -3364,11 +3359,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin +@@ -3371,11 +3366,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin f1 = this.getYRot(); } @@ -4175,7 +4175,7 @@ index ddd3acbc804cbc07eaccf578349d3f9e0e00b6fc..0c0144679c9d44d50af153c792d7e5da // Paper start - stop large pitch and yaw changes from crashing the server this.yRotO += Math.round((this.getYRot() - this.yRotO) / 360.0F) * 360.0F; -@@ -3380,7 +3371,6 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin +@@ -3387,7 +3378,6 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin this.yHeadRotO += Math.round((this.yHeadRot - this.yHeadRotO) / 360.0F) * 360.0F; // Paper end - stop large pitch and yaw changes from crashing the server @@ -4183,7 +4183,7 @@ index ddd3acbc804cbc07eaccf578349d3f9e0e00b6fc..0c0144679c9d44d50af153c792d7e5da if (this.isFallFlying()) { this.fallFlyTicks++; } else { -@@ -3556,21 +3546,15 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin +@@ -3563,21 +3553,15 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin } this.setDeltaMovement(d, d1, d2); @@ -4205,7 +4205,7 @@ index ddd3acbc804cbc07eaccf578349d3f9e0e00b6fc..0c0144679c9d44d50af153c792d7e5da if (this.jumping && this.isAffectedByFluids()) { double fluidHeight; if (this.isInLava()) { -@@ -3599,8 +3583,6 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin +@@ -3606,8 +3590,6 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin this.noJumpDelay = 0; } @@ -4214,7 +4214,7 @@ index ddd3acbc804cbc07eaccf578349d3f9e0e00b6fc..0c0144679c9d44d50af153c792d7e5da if (this.isFallFlying()) { this.updateFallFlying(); } -@@ -3625,9 +3607,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin +@@ -3632,9 +3614,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin this.calculateEntityAnimation(this instanceof FlyingAnimal); } @@ -4224,7 +4224,7 @@ index ddd3acbc804cbc07eaccf578349d3f9e0e00b6fc..0c0144679c9d44d50af153c792d7e5da if ((!this.isInPowderSnow || !this.canFreeze()) && !this.freezeLocked) { // Paper - Freeze Tick Lock API this.setTicksFrozen(Math.max(0, this.getTicksFrozen() - 2)); } -@@ -3637,18 +3617,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin +@@ -3644,18 +3624,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin if (this.tickCount % 40 == 0 && this.isFullyFrozen() && this.canFreeze()) { this.hurtServer(serverLevel, this.damageSources().freeze(), 1.0F); } diff --git a/divinemc-server/minecraft-patches/features/0011-lithium-fast_util.patch b/divinemc-server/minecraft-patches/features/0010-lithium-fast_util.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0011-lithium-fast_util.patch rename to divinemc-server/minecraft-patches/features/0010-lithium-fast_util.patch diff --git a/divinemc-server/minecraft-patches/features/0015-C2ME-Optimize-world-gen-math.patch b/divinemc-server/minecraft-patches/features/0011-C2ME-Optimize-world-gen-math.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0015-C2ME-Optimize-world-gen-math.patch rename to divinemc-server/minecraft-patches/features/0011-C2ME-Optimize-world-gen-math.patch diff --git a/divinemc-server/minecraft-patches/features/0016-Re-Fix-MC-117075.patch b/divinemc-server/minecraft-patches/features/0012-Re-Fix-MC-117075.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0016-Re-Fix-MC-117075.patch rename to divinemc-server/minecraft-patches/features/0012-Re-Fix-MC-117075.patch diff --git a/divinemc-server/minecraft-patches/features/0012-lithium-entity.fast_hand_swing-entity.fast_elytra_ch.patch b/divinemc-server/minecraft-patches/features/0012-lithium-entity.fast_hand_swing-entity.fast_elytra_ch.patch deleted file mode 100644 index 48c6d33..0000000 --- a/divinemc-server/minecraft-patches/features/0012-lithium-entity.fast_hand_swing-entity.fast_elytra_ch.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 01:51:12 +0300 -Subject: [PATCH] lithium: entity.fast_hand_swing + entity.fast_elytra_check - -This patch is based on the following mixins: -* "net/caffeinemc/mods/lithium/mixin/entity/fast_elytra_check/LivingEntityMixin.java" -* "net/caffeinemc/mods/lithium/mixin/entity/fast_hand_swing/LivingEntityMixin.java" -By: 2No2Name <2No2Name@web.de> -As part of: Lithium (https://github.com/CaffeineMC/lithium-fabric) -Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html) - -diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index a086c44afc5b3cb04641b4b9cfe28690f6ca2d7e..ab2bfe5589547a5e1b7f26ff100609c4464b61c7 100644 ---- a/net/minecraft/world/entity/LivingEntity.java -+++ b/net/minecraft/world/entity/LivingEntity.java -@@ -2757,6 +2757,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin - } - - protected void updateSwingTime() { -+ if (!this.swinging && this.swingTime == 0) return; // DivineMC - lithium: entity.fast_hand_swing - int currentSwingDuration = this.getCurrentSwingDuration(); - if (this.swinging) { - this.swingTime++; -@@ -3703,6 +3704,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin - protected void updateFallFlying() { - this.checkFallDistanceAccumulation(); - if (!this.level().isClientSide) { -+ if (!this.isFallFlying() && this.fallFlyTicks == 0) return; // DivineMC - lithium: entity.fast_elytra_check - if (!this.canGlide()) { - if (this.getSharedFlag(7) != false && !CraftEventFactory.callToggleGlideEvent(this, false).isCancelled()) // CraftBukkit - this.setSharedFlag(7, false); diff --git a/divinemc-server/minecraft-patches/features/0024-SparklyPaper-Clear-dirty-stats-after-copying.patch b/divinemc-server/minecraft-patches/features/0013-SparklyPaper-Clear-dirty-stats-after-copying.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0024-SparklyPaper-Clear-dirty-stats-after-copying.patch rename to divinemc-server/minecraft-patches/features/0013-SparklyPaper-Clear-dirty-stats-after-copying.patch diff --git a/divinemc-server/minecraft-patches/features/0025-Async-locate-command.patch b/divinemc-server/minecraft-patches/features/0014-Async-locate-command.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0025-Async-locate-command.patch rename to divinemc-server/minecraft-patches/features/0014-Async-locate-command.patch diff --git a/divinemc-server/minecraft-patches/features/0014-C2ME-Reduce-Allocations.patch b/divinemc-server/minecraft-patches/features/0014-C2ME-Reduce-Allocations.patch deleted file mode 100644 index c1550b7..0000000 --- a/divinemc-server/minecraft-patches/features/0014-C2ME-Reduce-Allocations.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 01:53:38 +0300 -Subject: [PATCH] C2ME: Reduce Allocations - -This patch is based on the following mixin: -"com/ishland/c2me/opts/allocs/mixin/object_pooling_caching/MixinOreFeature.java" -By: ishland -As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric) -Licensed under: MIT (https://opensource.org/licenses/MIT) - -diff --git a/net/minecraft/world/level/levelgen/feature/OreFeature.java b/net/minecraft/world/level/levelgen/feature/OreFeature.java -index c7b46efd4f08067e2c9c5c8b0e8b71a94a79823d..45d43707909685d2494f054d4b9e6451af6c2f72 100644 ---- a/net/minecraft/world/level/levelgen/feature/OreFeature.java -+++ b/net/minecraft/world/level/levelgen/feature/OreFeature.java -@@ -69,7 +69,7 @@ public class OreFeature extends Feature { - int height - ) { - int i = 0; -- BitSet bitSet = new BitSet(width * height * width); -+ BitSet bitSet = org.bxteam.divinemc.util.cache.CachedOrNewBitsGetter.getCachedOrNewBitSet(width * height * width); // DivineMC - C2ME: Reduce Allocations - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); - int i1 = config.size; - double[] doubles = new double[i1 * 4]; diff --git a/divinemc-server/minecraft-patches/features/0026-Carpet-Fixes-RecipeManager-Optimize.patch b/divinemc-server/minecraft-patches/features/0015-Carpet-Fixes-RecipeManager-Optimize.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0026-Carpet-Fixes-RecipeManager-Optimize.patch rename to divinemc-server/minecraft-patches/features/0015-Carpet-Fixes-RecipeManager-Optimize.patch diff --git a/divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch b/divinemc-server/minecraft-patches/features/0016-lithium-faster-chunk-serialization.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0027-lithium-faster-chunk-serialization.patch rename to divinemc-server/minecraft-patches/features/0016-lithium-faster-chunk-serialization.patch diff --git a/divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch b/divinemc-server/minecraft-patches/features/0017-C2ME-optimize-noise-generation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0031-C2ME-optimize-noise-generation.patch rename to divinemc-server/minecraft-patches/features/0017-C2ME-optimize-noise-generation.patch diff --git a/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch b/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch deleted file mode 100644 index 4a6caa9..0000000 --- a/divinemc-server/minecraft-patches/features/0017-Fix-MC-119417.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 01:58:51 +0300 -Subject: [PATCH] Fix MC-119417 - -Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-119417 - -diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index f5ef04f2f9324f8b7168bafb02acc74629df6086..1431a2e386bee22ec10365a38ead349a398d551f 100644 ---- a/net/minecraft/server/level/ServerPlayer.java -+++ b/net/minecraft/server/level/ServerPlayer.java -@@ -2227,6 +2227,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc - this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, gameMode.getId())); - if (gameMode == GameType.SPECTATOR) { - this.removeEntitiesOnShoulder(); -+ this.stopSleeping(); // DivineMC - Fix MC-119417 - this.stopRiding(); - EnchantmentHelper.stopLocationBasedEffects(this); - } else { diff --git a/divinemc-server/minecraft-patches/features/0018-Fix-MC-7569.patch b/divinemc-server/minecraft-patches/features/0018-Fix-MC-7569.patch deleted file mode 100644 index 9f8ffc1..0000000 --- a/divinemc-server/minecraft-patches/features/0018-Fix-MC-7569.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 01:59:43 +0300 -Subject: [PATCH] Fix MC-7569 - -Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-7569 - -diff --git a/net/minecraft/server/rcon/RconConsoleSource.java b/net/minecraft/server/rcon/RconConsoleSource.java -index 1fddeb10c5947c52840e55ca66c50dd4ad5425b9..f50d87c5c4c0c3daa38a70213b8a8af963fff312 100644 ---- a/net/minecraft/server/rcon/RconConsoleSource.java -+++ b/net/minecraft/server/rcon/RconConsoleSource.java -@@ -51,7 +51,7 @@ public class RconConsoleSource implements CommandSource { - - @Override - public void sendSystemMessage(Component component) { -- this.buffer.append(component.getString()); -+ this.buffer.append(component.getString()).append(System.lineSeparator()); // DivineMC - Fix MC-7569 - } - - @Override diff --git a/divinemc-server/minecraft-patches/features/0034-Optimize-block-state-lookup.patch b/divinemc-server/minecraft-patches/features/0018-Optimize-block-state-lookup.patch similarity index 93% rename from divinemc-server/minecraft-patches/features/0034-Optimize-block-state-lookup.patch rename to divinemc-server/minecraft-patches/features/0018-Optimize-block-state-lookup.patch index 09ca985..b64344c 100644 --- a/divinemc-server/minecraft-patches/features/0034-Optimize-block-state-lookup.patch +++ b/divinemc-server/minecraft-patches/features/0018-Optimize-block-state-lookup.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Optimize block state lookup diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index d11373d6a88f7b3baaf0e04d4f6e0d3837e2ba3b..6d9274f0da9507d0152611d6b7785e0524dedb2d 100644 +index b88254fb3c12b99684c6ede1ae8a6671ffbe9ad6..dbb4142ea38cdf484e74c81103cebb024ae8813d 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -270,11 +270,18 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p diff --git a/divinemc-server/minecraft-patches/features/0035-Don-t-respond-ping-before-start-fully.patch b/divinemc-server/minecraft-patches/features/0019-Don-t-respond-ping-before-start-fully.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0035-Don-t-respond-ping-before-start-fully.patch rename to divinemc-server/minecraft-patches/features/0019-Don-t-respond-ping-before-start-fully.patch diff --git a/divinemc-server/minecraft-patches/features/0019-Fix-MC-110386.patch b/divinemc-server/minecraft-patches/features/0019-Fix-MC-110386.patch deleted file mode 100644 index 69ce25c..0000000 --- a/divinemc-server/minecraft-patches/features/0019-Fix-MC-110386.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:01:33 +0300 -Subject: [PATCH] Fix MC-110386 - -Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-110386 - -diff --git a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java -index a8ec1d5f4b0fb0ff26a234235b7d8d9c4b4a2a98..6251cfface8d4bedd58271ace3947a1631e61b66 100644 ---- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java -+++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java -@@ -114,6 +114,7 @@ public class HurtByTargetGoal extends TargetGoal { - } - - protected void alertOther(Mob mob, LivingEntity target) { -+ if (mob == target) return; // DivineMC - Fix MC-110386 - mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY); // CraftBukkit - reason - } - } diff --git a/divinemc-server/minecraft-patches/features/0036-Respawn-players-that-were-dead-on-server-restart.patch b/divinemc-server/minecraft-patches/features/0020-Respawn-players-that-were-dead-on-server-restart.patch similarity index 94% rename from divinemc-server/minecraft-patches/features/0036-Respawn-players-that-were-dead-on-server-restart.patch rename to divinemc-server/minecraft-patches/features/0020-Respawn-players-that-were-dead-on-server-restart.patch index bd66eda..4d5e987 100644 --- a/divinemc-server/minecraft-patches/features/0036-Respawn-players-that-were-dead-on-server-restart.patch +++ b/divinemc-server/minecraft-patches/features/0020-Respawn-players-that-were-dead-on-server-restart.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Respawn players that were dead on server restart diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index ace14db7bfd154b8a9b27af4a6c57630a3868ac0..abfecaf4467092f7baa02e0f5bbfd23d087f2aa3 100644 +index 6498455c4c2838cbee743f016d8be1fe2fb61f6d..141c19eb290080f762da1e2090dae0609f2e3575 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -971,6 +971,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Sun, 6 Jul 2025 02:03:37 +0300 -Subject: [PATCH] Fix MC-31819 - -Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-31819 - -diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java -index d72e338232b95826b63d784ac0731f5a20bf8dcb..05634e09200fa613b69aafe9b2505dbc9b5c54eb 100644 ---- a/net/minecraft/world/entity/player/Player.java -+++ b/net/minecraft/world/entity/player/Player.java -@@ -1817,6 +1817,11 @@ public abstract class Player extends LivingEntity { - } - - public void causeFoodExhaustion(float exhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason reason) { -+ // DivineMC start - Fix MC-31819 -+ if (this.level().getDifficulty() == Difficulty.PEACEFUL) { -+ return; -+ } -+ // DivineMC end - Fix MC-31819 - // CraftBukkit end - if (!this.abilities.invulnerable) { - if (!this.level().isClientSide) { diff --git a/divinemc-server/minecraft-patches/features/0038-Configurable-MC-59471.patch b/divinemc-server/minecraft-patches/features/0022-Configurable-MC-59471.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0038-Configurable-MC-59471.patch rename to divinemc-server/minecraft-patches/features/0022-Configurable-MC-59471.patch diff --git a/divinemc-server/minecraft-patches/features/0022-Fix-MC-172801.patch b/divinemc-server/minecraft-patches/features/0022-Fix-MC-172801.patch deleted file mode 100644 index e9bde40..0000000 --- a/divinemc-server/minecraft-patches/features/0022-Fix-MC-172801.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:04:33 +0300 -Subject: [PATCH] Fix MC-172801 - -Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-172801 - -diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index ab2bfe5589547a5e1b7f26ff100609c4464b61c7..4149e7eb6f583d80ed179b190dcc02acf1144bef 100644 ---- a/net/minecraft/world/entity/LivingEntity.java -+++ b/net/minecraft/world/entity/LivingEntity.java -@@ -3274,7 +3274,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin - } - - protected float getFlyingSpeed() { -- return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : 0.02F; -+ // DivineMC start - Fix MC-172801 -+ float flyingSpeed = 0.02F; -+ if (this.getAttributes().hasAttribute(Attributes.FLYING_SPEED)) { -+ flyingSpeed = (float) (this.getAttribute(Attributes.FLYING_SPEED).getValue() * 0.049999999254942D); -+ } -+ return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : flyingSpeed; -+ // DivineMC end - Fix MC-172801 - } - - public float getSpeed() { diff --git a/divinemc-server/minecraft-patches/features/0039-Use-Java-s-Math-functions.patch b/divinemc-server/minecraft-patches/features/0023-Use-Java-s-Math-functions.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0039-Use-Java-s-Math-functions.patch rename to divinemc-server/minecraft-patches/features/0023-Use-Java-s-Math-functions.patch diff --git a/divinemc-server/minecraft-patches/features/0040-Disable-leaf-decay.patch b/divinemc-server/minecraft-patches/features/0024-Disable-leaf-decay.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0040-Disable-leaf-decay.patch rename to divinemc-server/minecraft-patches/features/0024-Disable-leaf-decay.patch diff --git a/divinemc-server/minecraft-patches/features/0041-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch b/divinemc-server/minecraft-patches/features/0025-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0041-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch rename to divinemc-server/minecraft-patches/features/0025-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch diff --git a/divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch b/divinemc-server/minecraft-patches/features/0026-Optimize-entity-brain.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0042-Optimize-entity-brain.patch rename to divinemc-server/minecraft-patches/features/0026-Optimize-entity-brain.patch diff --git a/divinemc-server/minecraft-patches/features/0043-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch b/divinemc-server/minecraft-patches/features/0027-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0043-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch rename to divinemc-server/minecraft-patches/features/0027-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch diff --git a/divinemc-server/minecraft-patches/features/0044-Carpet-Fixes-Optimized-getBiome-method.patch b/divinemc-server/minecraft-patches/features/0028-Carpet-Fixes-Optimized-getBiome-method.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0044-Carpet-Fixes-Optimized-getBiome-method.patch rename to divinemc-server/minecraft-patches/features/0028-Carpet-Fixes-Optimized-getBiome-method.patch diff --git a/divinemc-server/minecraft-patches/features/0045-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch b/divinemc-server/minecraft-patches/features/0029-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0045-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch rename to divinemc-server/minecraft-patches/features/0029-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch diff --git a/divinemc-server/minecraft-patches/features/0046-Carpet-Fixes-Sheep-Optimization.patch b/divinemc-server/minecraft-patches/features/0030-Carpet-Fixes-Sheep-Optimization.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0046-Carpet-Fixes-Sheep-Optimization.patch rename to divinemc-server/minecraft-patches/features/0030-Carpet-Fixes-Sheep-Optimization.patch diff --git a/divinemc-server/minecraft-patches/features/0047-Carpet-AMS-Addition-Optimized-dragon-respawn.patch b/divinemc-server/minecraft-patches/features/0031-Carpet-AMS-Addition-Optimized-dragon-respawn.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0047-Carpet-AMS-Addition-Optimized-dragon-respawn.patch rename to divinemc-server/minecraft-patches/features/0031-Carpet-AMS-Addition-Optimized-dragon-respawn.patch diff --git a/divinemc-server/minecraft-patches/features/0048-ModernFix-compact_bit_storage.patch b/divinemc-server/minecraft-patches/features/0032-ModernFix-compact_bit_storage.patch similarity index 95% rename from divinemc-server/minecraft-patches/features/0048-ModernFix-compact_bit_storage.patch rename to divinemc-server/minecraft-patches/features/0032-ModernFix-compact_bit_storage.patch index eb9ec79..29cd187 100644 --- a/divinemc-server/minecraft-patches/features/0048-ModernFix-compact_bit_storage.patch +++ b/divinemc-server/minecraft-patches/features/0032-ModernFix-compact_bit_storage.patch @@ -10,7 +10,7 @@ As part of: ModernFix (https://github.com/embeddedt/ModernFix) Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java -index be11a87ab1badca64219d74bc7a4f5d51b818a8c..a87689919a5fd4774eaff534ca85243feb505e84 100644 +index 9d892c1c3890e0aaf13fd5cd7b7d138afeaad260..ca3fab804e464a5db2b47495ecb588a96044265d 100644 --- a/net/minecraft/world/level/chunk/PalettedContainer.java +++ b/net/minecraft/world/level/chunk/PalettedContainer.java @@ -291,6 +291,28 @@ public class PalettedContainer implements PaletteResize, PalettedContainer diff --git a/divinemc-server/minecraft-patches/features/0033-Fix-sprint-glitch.patch b/divinemc-server/minecraft-patches/features/0033-Fix-sprint-glitch.patch deleted file mode 100644 index a6746ed..0000000 --- a/divinemc-server/minecraft-patches/features/0033-Fix-sprint-glitch.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:43:50 +0300 -Subject: [PATCH] Fix sprint glitch - - -diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index 4149e7eb6f583d80ed179b190dcc02acf1144bef..9a000a4df5df6e36ae25e6d54bfe7cd725df51dd 100644 ---- a/net/minecraft/world/entity/LivingEntity.java -+++ b/net/minecraft/world/entity/LivingEntity.java -@@ -1420,7 +1420,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin - player.setRealHealth(health); - } - -- player.updateScaledHealth(false); -+ this.entityData.set(LivingEntity.DATA_HEALTH_ID, player.getScaledHealth()); // DivineMC - Fix sprint glitch - return; - } - // CraftBukkit end diff --git a/divinemc-server/minecraft-patches/features/0049-Option-to-disable-disconnect.spam.patch b/divinemc-server/minecraft-patches/features/0033-Option-to-disable-disconnect.spam.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0049-Option-to-disable-disconnect.spam.patch rename to divinemc-server/minecraft-patches/features/0033-Option-to-disable-disconnect.spam.patch diff --git a/divinemc-server/minecraft-patches/features/0050-Option-to-disable-saving-of-snowball-and-firework.patch b/divinemc-server/minecraft-patches/features/0034-Option-to-disable-saving-of-snowball-and-firework.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0050-Option-to-disable-saving-of-snowball-and-firework.patch rename to divinemc-server/minecraft-patches/features/0034-Option-to-disable-saving-of-snowball-and-firework.patch diff --git a/divinemc-server/minecraft-patches/features/0051-Snowball-and-Egg-knockback.patch b/divinemc-server/minecraft-patches/features/0035-Snowball-and-Egg-knockback.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0051-Snowball-and-Egg-knockback.patch rename to divinemc-server/minecraft-patches/features/0035-Snowball-and-Egg-knockback.patch diff --git a/divinemc-server/minecraft-patches/features/0052-Optimize-suffocation.patch b/divinemc-server/minecraft-patches/features/0036-Optimize-suffocation.patch similarity index 95% rename from divinemc-server/minecraft-patches/features/0052-Optimize-suffocation.patch rename to divinemc-server/minecraft-patches/features/0036-Optimize-suffocation.patch index 13dfed4..45e229d 100644 --- a/divinemc-server/minecraft-patches/features/0052-Optimize-suffocation.patch +++ b/divinemc-server/minecraft-patches/features/0036-Optimize-suffocation.patch @@ -7,7 +7,7 @@ Original license: GPL v3 Original project: https://github.com/pufferfish-gg/Pufferfish diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index d382a9760c0379f3d1c3bc65303d1de250858343..49cb64c6dd0941eab8f7531e0c182a79e4ec1da6 100644 +index 8df6ceea1536b12d87755c8a69e1b652d280600c..33f33a51a7016e214bca1aec8e6cc3910ec3bb42 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java @@ -420,6 +420,12 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin diff --git a/divinemc-server/minecraft-patches/features/0053-Reduce-chunk-loading-lookups.patch b/divinemc-server/minecraft-patches/features/0037-Reduce-chunk-loading-lookups.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0053-Reduce-chunk-loading-lookups.patch rename to divinemc-server/minecraft-patches/features/0037-Reduce-chunk-loading-lookups.patch diff --git a/divinemc-server/minecraft-patches/features/0054-Configurable-movement-speed-for-entities.patch b/divinemc-server/minecraft-patches/features/0038-Configurable-movement-speed-for-entities.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0054-Configurable-movement-speed-for-entities.patch rename to divinemc-server/minecraft-patches/features/0038-Configurable-movement-speed-for-entities.patch diff --git a/divinemc-server/minecraft-patches/features/0055-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch b/divinemc-server/minecraft-patches/features/0039-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0055-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch rename to divinemc-server/minecraft-patches/features/0039-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch diff --git a/divinemc-server/minecraft-patches/features/0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch b/divinemc-server/minecraft-patches/features/0040-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0056-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch rename to divinemc-server/minecraft-patches/features/0040-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch diff --git a/divinemc-server/minecraft-patches/features/0057-Option-to-allow-weird-movement-and-disable-teleporti.patch b/divinemc-server/minecraft-patches/features/0041-Option-to-allow-weird-movement-and-disable-teleporti.patch similarity index 98% rename from divinemc-server/minecraft-patches/features/0057-Option-to-allow-weird-movement-and-disable-teleporti.patch rename to divinemc-server/minecraft-patches/features/0041-Option-to-allow-weird-movement-and-disable-teleporti.patch index b73178f..bbe95e9 100644 --- a/divinemc-server/minecraft-patches/features/0057-Option-to-allow-weird-movement-and-disable-teleporti.patch +++ b/divinemc-server/minecraft-patches/features/0041-Option-to-allow-weird-movement-and-disable-teleporti.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Option to allow weird movement and disable teleporting diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 8f4bca6a99b35e869e34f0fa216c13189cd7b384..3ba558634558b4524245a2b29786237f5e38ef42 100644 +index fe7d68f3947bf55a389c73ef301fae8e396bf1da..39b95d3736d5acd3b71675410469727be6405cd3 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -607,7 +607,7 @@ public class ServerGamePacketListenerImpl diff --git a/divinemc-server/minecraft-patches/features/0058-Optimize-Raids.patch b/divinemc-server/minecraft-patches/features/0042-Optimize-Raids.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0058-Optimize-Raids.patch rename to divinemc-server/minecraft-patches/features/0042-Optimize-Raids.patch diff --git a/divinemc-server/minecraft-patches/features/0059-SparklyPaper-Optimize-canSee-checks.patch b/divinemc-server/minecraft-patches/features/0043-SparklyPaper-Optimize-canSee-checks.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0059-SparklyPaper-Optimize-canSee-checks.patch rename to divinemc-server/minecraft-patches/features/0043-SparklyPaper-Optimize-canSee-checks.patch diff --git a/divinemc-server/minecraft-patches/features/0060-Small-optimization-to-LinearPalette.patch b/divinemc-server/minecraft-patches/features/0044-Small-optimization-to-LinearPalette.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0060-Small-optimization-to-LinearPalette.patch rename to divinemc-server/minecraft-patches/features/0044-Small-optimization-to-LinearPalette.patch diff --git a/divinemc-server/minecraft-patches/features/0061-Use-switch-for-VarInt-write.patch b/divinemc-server/minecraft-patches/features/0045-Use-switch-for-VarInt-write.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0061-Use-switch-for-VarInt-write.patch rename to divinemc-server/minecraft-patches/features/0045-Use-switch-for-VarInt-write.patch diff --git a/divinemc-server/minecraft-patches/features/0062-Optimize-Fluids.patch b/divinemc-server/minecraft-patches/features/0046-Optimize-Fluids.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0062-Optimize-Fluids.patch rename to divinemc-server/minecraft-patches/features/0046-Optimize-Fluids.patch diff --git a/divinemc-server/minecraft-patches/features/0063-Optimize-Structure-Generation.patch b/divinemc-server/minecraft-patches/features/0047-Optimize-Structure-Generation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0063-Optimize-Structure-Generation.patch rename to divinemc-server/minecraft-patches/features/0047-Optimize-Structure-Generation.patch diff --git a/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch b/divinemc-server/minecraft-patches/features/0048-Implement-NoChatReports.patch similarity index 98% rename from divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch rename to divinemc-server/minecraft-patches/features/0048-Implement-NoChatReports.patch index 7c2fc7a..16db10b 100644 --- a/divinemc-server/minecraft-patches/features/0064-Implement-NoChatReports.patch +++ b/divinemc-server/minecraft-patches/features/0048-Implement-NoChatReports.patch @@ -206,7 +206,7 @@ index a491be4250de3199c3e1aa9e5482b568692bd2f5..c88826db76c28c536e6c36c5592d69c1 private static final String PREFIX = "data:image/png;base64,"; public static final Codec CODEC = Codec.STRING.comapFlatMap(string -> { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index a947fc31f6261531b6f28e5af577e74ca84f2132..021e1cb762d23ebe885a3f190ba2431e1db99bb8 100644 +index ac35fc08574a72be356c48fb6e1cfafe36cd0860..dcd004749846aa9e650be438b0f097e414c2ec76 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java @@ -623,6 +623,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @@ -287,7 +287,7 @@ index 667ef5b2ab50eeb0491f7fe0bc8913ec29a4603a..a7c4fad2b1cb0cbac742a18d37d688bb if (packet == null || this.processedDisconnect) { // Spigot return; diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index fb1b9f75cffeb15875e6690a0e030f8a4fd8b276..6713eb83b36f115e72fa5999c413e59e4f634f9f 100644 +index 7ed75ef10e3d4504cebb0ad544e05d9544642c9e..3165fd57f8f04251f220716beab49f6f43736eeb 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java @@ -276,7 +276,7 @@ public abstract class PlayerList { diff --git a/divinemc-server/minecraft-patches/features/0065-Lag-compensation.patch b/divinemc-server/minecraft-patches/features/0049-Lag-compensation.patch similarity index 98% rename from divinemc-server/minecraft-patches/features/0065-Lag-compensation.patch rename to divinemc-server/minecraft-patches/features/0049-Lag-compensation.patch index 4805345..3e277d2 100644 --- a/divinemc-server/minecraft-patches/features/0065-Lag-compensation.patch +++ b/divinemc-server/minecraft-patches/features/0049-Lag-compensation.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Lag compensation diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 7a3775185d5c80f43456a595f22a9ebf19760bd6..23144971acc04bbeacd719dafe2363d1618153b9 100644 +index 141c19eb290080f762da1e2090dae0609f2e3575..5a7cb4cffa218a17300c74ee4d95b08b705324ea 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -288,6 +288,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function threadFunction) { ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system -@@ -1534,6 +1535,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop(), new com.google.common.util.concurrent.ThreadFactoryBuilder() diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 23144971acc04bbeacd719dafe2363d1618153b9..7dbefd83d164a7d97a56b02862fef3b2f17d5aab 100644 +index 5a7cb4cffa218a17300c74ee4d95b08b705324ea..4a53105e46e338a52bc5ad22d51688a9a261d9e5 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -2639,8 +2639,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop states = new java.util.ArrayList<>(level.capturedBlockStates.values()); level.capturedBlockStates.clear(); diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 985a5168f7f81fb934e791618362b7c6e71ff893..acbae905cd22511be417600c68c6944b80acd2d7 100644 +index ed4a722c0fa458a0977366b92561d6a16827da56..9f5beb74d8b0198aebf7cad40def52d12a4a9b3d 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -290,6 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop serverPlayer1.connection.suspendFlushing()); this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit -@@ -1705,28 +1730,43 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop, ServerLevel> oldLevels = this.levels; Map, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels); newLevels.remove(level.dimension()); @@ -233,7 +233,7 @@ index 985a5168f7f81fb934e791618362b7c6e71ff893..acbae905cd22511be417600c68c6944b } // CraftBukkit end diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java -index 10e5469df1800bcdfb3f8cb4045ee25a4bafc58c..8efed0ffdc906b6c1ba054831e481f53c11f102d 100644 +index 3836d60ce84fb26f30a609486a5755d3fd1c94f1..1aab02441e4dfa7703963855d77bb918dee7a6fc 100644 --- a/net/minecraft/server/PlayerAdvancements.java +++ b/net/minecraft/server/PlayerAdvancements.java @@ -54,6 +54,7 @@ public class PlayerAdvancements { @@ -333,7 +333,7 @@ index 10e5469df1800bcdfb3f8cb4045ee25a4bafc58c..8efed0ffdc906b6c1ba054831e481f53 } } else if (this.visible.remove(advancementHolder)) { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 021e1cb762d23ebe885a3f190ba2431e1db99bb8..8820d1789192247c52b4d821abf2dd23c0bf1b62 100644 +index dcd004749846aa9e650be438b0f097e414c2ec76..5a2b9632a1e46b512a1379923765c1b8a28250b9 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java @@ -218,6 +218,13 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @@ -513,7 +513,7 @@ index 1431a2e386bee22ec10365a38ead349a398d551f..77d1cab278a13e08ba8096af2c683b50 // Paper end - Inventory close reason this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 6713eb83b36f115e72fa5999c413e59e4f634f9f..08e337ae96c444da2e50240c808c76a548cd4c12 100644 +index 3165fd57f8f04251f220716beab49f6f43736eeb..df47a3dc31a01464088eba21f4139f63d69895e5 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java @@ -149,6 +149,7 @@ public abstract class PlayerList { diff --git a/divinemc-server/minecraft-patches/features/0079-MSPT-Tracking-for-each-world.patch b/divinemc-server/minecraft-patches/features/0063-MSPT-Tracking-for-each-world.patch similarity index 93% rename from divinemc-server/minecraft-patches/features/0079-MSPT-Tracking-for-each-world.patch rename to divinemc-server/minecraft-patches/features/0063-MSPT-Tracking-for-each-world.patch index b04c8ab..a47025b 100644 --- a/divinemc-server/minecraft-patches/features/0079-MSPT-Tracking-for-each-world.patch +++ b/divinemc-server/minecraft-patches/features/0063-MSPT-Tracking-for-each-world.patch @@ -5,10 +5,10 @@ Subject: [PATCH] MSPT Tracking for each world diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 101dce7741f74dd79b333fd6cf38a97cb0c832f8..c0a272285e244e0267e6ef776aef14524e63c076 100644 +index 9f5beb74d8b0198aebf7cad40def52d12a4a9b3d..4bbb9b8701e4f5a411a12b8fd977e6de19a22b26 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1676,7 +1676,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Thu, 10 Jul 2025 04:21:08 +0300 -Subject: [PATCH] Disable offline warn if using proxy - - -diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 8820d1789192247c52b4d821abf2dd23c0bf1b62..5a2b9632a1e46b512a1379923765c1b8a28250b9 100644 ---- a/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -305,7 +305,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord"; - String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/"; - // Paper end - Add Velocity IP Forwarding Support -- if (!this.usesAuthentication()) { -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()) { // DivineMC - Disable offline warn if using proxy - LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); - LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); - // Spigot start diff --git a/divinemc-server/minecraft-patches/features/0084-Configurable-player-spawn-tracking-range.patch b/divinemc-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java.patch similarity index 60% rename from divinemc-server/minecraft-patches/features/0084-Configurable-player-spawn-tracking-range.patch rename to divinemc-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java.patch index aa79ad8..71edb35 100644 --- a/divinemc-server/minecraft-patches/features/0084-Configurable-player-spawn-tracking-range.patch +++ b/divinemc-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java.patch @@ -1,14 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Wed, 9 Jul 2025 04:40:45 +0300 -Subject: [PATCH] Configurable player spawn tracking range - - -diff --git a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java -index 6d1fe8028739145b11fce98ad62b2f8044299548..9f086ded18d1fc8850877c6be113d88074427526 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java +++ b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java -@@ -2,7 +2,7 @@ package ca.spottedleaf.moonrise.patches.chunk_tick_iteration; +@@ -2,7 +_,7 @@ public final class ChunkTickConstants { diff --git a/divinemc-server/minecraft-patches/features/0032-Skip-cloning-advancement-criteria.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/advancements/Advancement.java.patch similarity index 56% rename from divinemc-server/minecraft-patches/features/0032-Skip-cloning-advancement-criteria.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/advancements/Advancement.java.patch index ed20d09..fc813cb 100644 --- a/divinemc-server/minecraft-patches/features/0032-Skip-cloning-advancement-criteria.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/advancements/Advancement.java.patch @@ -1,14 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:42:57 +0300 -Subject: [PATCH] Skip cloning advancement criteria - - -diff --git a/net/minecraft/advancements/Advancement.java b/net/minecraft/advancements/Advancement.java -index ac6a85ddf6eb326b3fd53341a4a5db7bd00b7ce2..52a285db9557b2e44d2dcae9fabdb0d78d3e7ec6 100644 --- a/net/minecraft/advancements/Advancement.java +++ b/net/minecraft/advancements/Advancement.java -@@ -61,7 +61,7 @@ public record Advancement( +@@ -61,7 +_,7 @@ AdvancementRequirements requirements, boolean sendsTelemetryEvent ) { diff --git a/divinemc-server/minecraft-patches/features/0013-lithium-cached_iterate_outwards.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch similarity index 66% rename from divinemc-server/minecraft-patches/features/0013-lithium-cached_iterate_outwards.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch index c531d35..fb2c309 100644 --- a/divinemc-server/minecraft-patches/features/0013-lithium-cached_iterate_outwards.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch @@ -1,17 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 01:52:18 +0300 -Subject: [PATCH] lithium: cached_iterate_outwards - -By: 2No2Name <2No2Name@web.de> -As part of: Lithium (https://github.com/CaffeineMC/lithium-fabric) -Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html) - -diff --git a/net/minecraft/core/BlockPos.java b/net/minecraft/core/BlockPos.java -index 6518d3fff6daf331b24a7bf5b39fa1920b73711d..0dc73d76c2d86e05bedb3eb4f51d638c17390277 100644 --- a/net/minecraft/core/BlockPos.java +++ b/net/minecraft/core/BlockPos.java -@@ -347,7 +347,18 @@ public class BlockPos extends Vec3i { +@@ -347,7 +_,18 @@ }; } diff --git a/divinemc-server/minecraft-patches/features/0091-Shutdown-executors.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch similarity index 51% rename from divinemc-server/minecraft-patches/features/0091-Shutdown-executors.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch index cd6e003..6cd07b9 100644 --- a/divinemc-server/minecraft-patches/features/0091-Shutdown-executors.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -1,14 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Thu, 10 Jul 2025 17:39:29 +0300 -Subject: [PATCH] Shutdown executors - - -diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 6361d8abdeb045923e8ce64f02cbb7a9ed949d1e..b31a4edee0616a63026f7a4335205f2d99d2f641 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1081,6 +1081,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Wed, 9 Jul 2025 03:41:32 +0300 -Subject: [PATCH] Use fastutil for criterion data - - -diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java -index 8efed0ffdc906b6c1ba054831e481f53c11f102d..1aab02441e4dfa7703963855d77bb918dee7a6fc 100644 --- a/net/minecraft/server/PlayerAdvancements.java +++ b/net/minecraft/server/PlayerAdvancements.java -@@ -61,7 +61,7 @@ public class PlayerAdvancements { +@@ -60,7 +_,7 @@ private AdvancementHolder lastSelectedTab; private boolean isFirstPacket = true; private final Codec codec; diff --git a/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch similarity index 67% rename from divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch index b7094ad..34470f9 100644 --- a/divinemc-server/minecraft-patches/features/0010-Pufferfish-SIMD-support.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -1,17 +1,7 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:55:43 +0300 -Subject: [PATCH] Pufferfish: SIMD support - -Original license: GPL v3 -Original project: https://github.com/pufferfish-gg/Pufferfish - -diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 06657a0fbf65dd095519d706dd5a8e1d8b6b381a..a947fc31f6261531b6f28e5af577e74ca84f2132 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -198,6 +198,26 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - org.bxteam.divinemc.command.DivineCommands.registerCommands(this); // DivineMC - Configuration +@@ -195,6 +_,26 @@ + // Purpur end - Purpur config files com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now + // DivineMC start - Pufferfish SIMD @@ -37,3 +27,12 @@ index 06657a0fbf65dd095519d706dd5a8e1d8b6b381a..a947fc31f6261531b6f28e5af577e74c this.setPvpAllowed(properties.pvp); this.setFlightAllowed(properties.allowFlight); this.setMotd(properties.motd); +@@ -275,7 +_,7 @@ + String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord"; + String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/"; + // Paper end - Add Velocity IP Forwarding Support +- if (!this.usesAuthentication()) { ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()) { // DivineMC - Disable offline warn if using proxy + LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); + LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); + // Spigot start diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch new file mode 100644 index 0000000..8c8ed02 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -2233,6 +_,7 @@ + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, gameMode.getId())); + if (gameMode == GameType.SPECTATOR) { + this.removeEntitiesOnShoulder(); ++ this.stopSleeping(); // DivineMC - Fix MC-119417 + this.stopRiding(); + EnchantmentHelper.stopLocationBasedEffects(this); + } else { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch new file mode 100644 index 0000000..8711080 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/server/rcon/RconConsoleSource.java ++++ b/net/minecraft/server/rcon/RconConsoleSource.java +@@ -51,7 +_,7 @@ + + @Override + public void sendSystemMessage(Component component) { +- this.buffer.append(component.getString()); ++ this.buffer.append(component.getString()).append(System.lineSeparator()); // DivineMC - Fix MC-7569 + } + + @Override diff --git a/divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch similarity index 55% rename from divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch index 6a3d39e..61cf3bd 100644 --- a/divinemc-server/minecraft-patches/features/0029-VMP-skip-entity-move-if-movement-is-zero.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -1,19 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:30:53 +0300 -Subject: [PATCH] VMP: skip entity move if movement is zero - -This patch is based on the following mixin: -"com/ishland/vmp/mixins/entity/move_zero_velocity/MixinEntity.java" -By: ishland -As part of: VMP (https://github.com/RelativityMC/VMP-fabric) -Licensed under: MIT (https://opensource.org/licenses/MIT) - -diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 02f39e3dc420a5bd49cd6e247c9b1894dc49d303..0171befef713e89d9241c7735d5d285b23373e8f 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -372,6 +372,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -374,6 +_,7 @@ public boolean isTemporarilyActive; public long activatedImmunityTick = Integer.MIN_VALUE; public @Nullable Boolean immuneToFire = null; // Purpur - Fire immune API @@ -21,7 +8,7 @@ index 02f39e3dc420a5bd49cd6e247c9b1894dc49d303..0171befef713e89d9241c7735d5d285b public void inactiveTick() { } -@@ -1119,6 +1120,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1125,6 +_,7 @@ // Paper end - detailed watchdog information public void move(MoverType type, Vec3 movement) { @@ -29,7 +16,7 @@ index 02f39e3dc420a5bd49cd6e247c9b1894dc49d303..0171befef713e89d9241c7735d5d285b final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity // Paper start - detailed watchdog information ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); -@@ -4425,6 +4427,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4448,6 +_,7 @@ } public final void setBoundingBox(AABB bb) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch new file mode 100644 index 0000000..27fed65 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -0,0 +1,42 @@ +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -1425,7 +_,7 @@ + player.setRealHealth(health); + } + +- player.updateScaledHealth(false); ++ this.entityData.set(LivingEntity.DATA_HEALTH_ID, player.getScaledHealth()); // DivineMC - Fix sprint glitch + return; + } + // CraftBukkit end +@@ -2762,6 +_,7 @@ + } + + protected void updateSwingTime() { ++ if (!this.swinging && this.swingTime == 0) return; // DivineMC - lithium: entity.fast_hand_swing + int currentSwingDuration = this.getCurrentSwingDuration(); + if (this.swinging) { + this.swingTime++; +@@ -3278,7 +_,13 @@ + } + + protected float getFlyingSpeed() { +- return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : 0.02F; ++ // DivineMC start - Fix MC-172801 ++ float flyingSpeed = 0.02F; ++ if (this.getAttributes().hasAttribute(Attributes.FLYING_SPEED)) { ++ flyingSpeed = (float) (this.getAttribute(Attributes.FLYING_SPEED).getValue() * 0.049999999254942D); ++ } ++ return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : flyingSpeed; ++ // DivineMC end - Fix MC-172801 + } + + public float getSpeed() { +@@ -3727,6 +_,7 @@ + protected void updateFallFlying() { + this.checkFallDistanceAccumulation(); + if (!this.level().isClientSide) { ++ if (!this.isFallFlying() && this.fallFlyTicks == 0) return; // DivineMC - lithium: entity.fast_elytra_check + if (!this.canGlide()) { + if (this.getSharedFlag(7) != false && !CraftEventFactory.callToggleGlideEvent(this, false).isCancelled()) // CraftBukkit + this.setSharedFlag(7, false); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch new file mode 100644 index 0000000..e825eb7 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java ++++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java +@@ -114,6 +_,7 @@ + } + + protected void alertOther(Mob mob, LivingEntity target) { ++ if (mob == target) return; // DivineMC - Fix MC-110386 + mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY); // CraftBukkit - reason + } + } diff --git a/divinemc-server/minecraft-patches/features/0028-lithium-skip-useless-secondary-poi-sensor.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java.patch similarity index 51% rename from divinemc-server/minecraft-patches/features/0028-lithium-skip-useless-secondary-poi-sensor.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java.patch index f128993..7bca1f5 100644 --- a/divinemc-server/minecraft-patches/features/0028-lithium-skip-useless-secondary-poi-sensor.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java.patch @@ -1,23 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:26:11 +0300 -Subject: [PATCH] lithium: skip useless secondary poi sensor - -This patch is based on the following mixin: -"net/caffeinemc/mods/lithium/mixin/ai/sensor/secondary_poi/SecondaryPoiSensorMixin.java" -By: 2No2Name <2No2Name@web.de> -As part of: Lithium (https://github.com/CaffeineMC/lithium-fabric) -Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html) - -Lithium description: - -villagers that have no secondary POI (farmland) do not search for it - -diff --git a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java -index dc4a9ddb8479e9d0c4895b19d7d677cdd8ad3faa..c3911232667ae9e1f70397f6ff5e7608694248fa 100644 --- a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java +++ b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java -@@ -22,6 +22,12 @@ public class SecondaryPoiSensor extends Sensor { +@@ -22,6 +_,12 @@ @Override protected void doTick(ServerLevel level, Villager entity) { diff --git a/divinemc-server/minecraft-patches/features/0020-Fix-MC-200418.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch similarity index 56% rename from divinemc-server/minecraft-patches/features/0020-Fix-MC-200418.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch index 28eb299..1927ea1 100644 --- a/divinemc-server/minecraft-patches/features/0020-Fix-MC-200418.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch @@ -1,15 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:02:47 +0300 -Subject: [PATCH] Fix MC-200418 - -Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-200418 - -diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java -index e218e5d5f146ec996a6f5ce7e76b1d6506ac1cb9..00af89717bf2459b315baf70a515a0e68267fb9f 100644 --- a/net/minecraft/world/entity/monster/ZombieVillager.java +++ b/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -292,6 +292,12 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { +@@ -292,6 +_,12 @@ if (!this.isSilent()) { level.levelEvent(null, 1027, this.blockPosition(), 0); } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch new file mode 100644 index 0000000..6fa3074 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -1817,6 +_,11 @@ + } + + public void causeFoodExhaustion(float exhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason reason) { ++ // DivineMC start - Fix MC-31819 ++ if (this.level().getDifficulty() == Difficulty.PEACEFUL) { ++ return; ++ } ++ // DivineMC end - Fix MC-31819 + // CraftBukkit end + if (!this.abilities.invulnerable) { + if (!this.level().isClientSide) { diff --git a/divinemc-server/minecraft-patches/features/0030-VMP-store-mob-counts-in-an-array.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/LocalMobCapCalculator.java.patch similarity index 55% rename from divinemc-server/minecraft-patches/features/0030-VMP-store-mob-counts-in-an-array.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/world/level/LocalMobCapCalculator.java.patch index aa8fb34..d24f9dd 100644 --- a/divinemc-server/minecraft-patches/features/0030-VMP-store-mob-counts-in-an-array.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/LocalMobCapCalculator.java.patch @@ -1,19 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:33:29 +0300 -Subject: [PATCH] VMP: store mob counts in an array - -This patch is based on the following mixin: -"com/ishland/vmp/mixins/general/spawn_density_cap/MixinSpawnDensityCapperDensityCap.java" -By: ishland -As part of: VMP (https://github.com/RelativityMC/VMP-fabric) -Licensed under: MIT (https://opensource.org/licenses/MIT) - -diff --git a/net/minecraft/world/level/LocalMobCapCalculator.java b/net/minecraft/world/level/LocalMobCapCalculator.java -index 9641219c190261dea0db5f95f040a705ba0a3ff9..d9fe183dbf072f82afae63792967d6e7953d7151 100644 --- a/net/minecraft/world/level/LocalMobCapCalculator.java +++ b/net/minecraft/world/level/LocalMobCapCalculator.java -@@ -42,14 +42,14 @@ public class LocalMobCapCalculator { +@@ -42,14 +_,14 @@ } static class MobCounts { diff --git a/divinemc-server/minecraft-patches/features/0023-Fix-MC-258859.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/SurfaceRules.java.patch similarity index 71% rename from divinemc-server/minecraft-patches/features/0023-Fix-MC-258859.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/SurfaceRules.java.patch index 7c01f8c..4dcf4ce 100644 --- a/divinemc-server/minecraft-patches/features/0023-Fix-MC-258859.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/SurfaceRules.java.patch @@ -1,15 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:08:04 +0300 -Subject: [PATCH] Fix MC-258859 - -Issue on Mojira: https://bugs.mojang.com/browse/MC/issues/MC-258859 - -diff --git a/net/minecraft/world/level/levelgen/SurfaceRules.java b/net/minecraft/world/level/levelgen/SurfaceRules.java -index 0948c8db90605a15a043b5c5bc74edecd7f9db1b..32757c6847cf77862a2f1b38cc53e7166e6be492 100644 --- a/net/minecraft/world/level/levelgen/SurfaceRules.java +++ b/net/minecraft/world/level/levelgen/SurfaceRules.java -@@ -397,6 +397,22 @@ public class SurfaceRules { +@@ -397,6 +_,22 @@ @Override protected boolean compute() { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/feature/OreFeature.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/feature/OreFeature.java.patch new file mode 100644 index 0000000..73ccba3 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/feature/OreFeature.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/levelgen/feature/OreFeature.java ++++ b/net/minecraft/world/level/levelgen/feature/OreFeature.java +@@ -69,7 +_,7 @@ + int height + ) { + int i = 0; +- BitSet bitSet = new BitSet(width * height * width); ++ BitSet bitSet = org.bxteam.divinemc.util.cache.CachedOrNewBitsGetter.getCachedOrNewBitSet(width * height * width); // DivineMC - C2ME: Reduce Allocations + BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + int i1 = config.size; + double[] doubles = new double[i1 * 4]; diff --git a/divinemc-server/paper-patches/features/0003-Delete-timings.patch b/divinemc-server/paper-patches/features/0003-Delete-timings.patch index 986ad86..95875e7 100644 --- a/divinemc-server/paper-patches/features/0003-Delete-timings.patch +++ b/divinemc-server/paper-patches/features/0003-Delete-timings.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Delete timings diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java -index 7ce9ebba8ce304d1f3f21d4f15ee5f3560d7700b..11e5b9ebafa562e5a93643d954839e86d0b731f0 100644 +index e989053b703fddfbffc3e4ed9381594aaaa0df41..d7398b1ecf2660c29fb7d106b48fe02d3736603e 100644 --- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java @@ -1,6 +1,5 @@ @@ -15,7 +15,7 @@ index 7ce9ebba8ce304d1f3f21d4f15ee5f3560d7700b..11e5b9ebafa562e5a93643d954839e86 import com.destroystokyo.paper.event.server.ServerExceptionEvent; import com.destroystokyo.paper.exception.ServerEventException; import com.google.common.collect.Sets; -@@ -95,7 +94,6 @@ class PaperEventManager { +@@ -96,7 +95,6 @@ class PaperEventManager { throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled"); } @@ -23,7 +23,7 @@ index 7ce9ebba8ce304d1f3f21d4f15ee5f3560d7700b..11e5b9ebafa562e5a93643d954839e86 this.getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled)); } -@@ -182,7 +180,7 @@ class PaperEventManager { +@@ -183,7 +181,7 @@ class PaperEventManager { } } diff --git a/divinemc-server/paper-patches/features/0015-Virtual-Threads.patch b/divinemc-server/paper-patches/features/0012-Virtual-Threads.patch similarity index 100% rename from divinemc-server/paper-patches/features/0015-Virtual-Threads.patch rename to divinemc-server/paper-patches/features/0012-Virtual-Threads.patch diff --git a/divinemc-server/paper-patches/features/0016-Implement-Secure-Seed.patch b/divinemc-server/paper-patches/features/0013-Implement-Secure-Seed.patch similarity index 100% rename from divinemc-server/paper-patches/features/0016-Implement-Secure-Seed.patch rename to divinemc-server/paper-patches/features/0013-Implement-Secure-Seed.patch diff --git a/divinemc-server/paper-patches/features/0017-Petal-Multithreaded-Tracker.patch b/divinemc-server/paper-patches/features/0014-Petal-Multithreaded-Tracker.patch similarity index 97% rename from divinemc-server/paper-patches/features/0017-Petal-Multithreaded-Tracker.patch rename to divinemc-server/paper-patches/features/0014-Petal-Multithreaded-Tracker.patch index b78e3ec..3577d80 100644 --- a/divinemc-server/paper-patches/features/0017-Petal-Multithreaded-Tracker.patch +++ b/divinemc-server/paper-patches/features/0014-Petal-Multithreaded-Tracker.patch @@ -45,7 +45,7 @@ index 4913ac7d0426025689c8aee3790d87f7ac0131fd..d4d3aeae964d9a64805ddc5862e46fff break; } diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index d10ee84ed2f6b1c81667b968984f3ebf5c39e445..83c6cf3cb062c8a6508728822e37d52a543415a3 100644 +index 67d25c18b1d13da3294572ea4ec17f2d18cba43c..87d9228e7ec8688e7949c4472224c6b920bb83c4 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -1808,6 +1808,26 @@ public class CraftEventFactory { diff --git a/divinemc-server/paper-patches/features/0014-Replace-CraftServer-getWorlds-ArrayList-with-a-fastu.patch b/divinemc-server/paper-patches/features/0014-Replace-CraftServer-getWorlds-ArrayList-with-a-fastu.patch deleted file mode 100644 index 7038f60..0000000 --- a/divinemc-server/paper-patches/features/0014-Replace-CraftServer-getWorlds-ArrayList-with-a-fastu.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Mon, 7 Jul 2025 04:06:32 +0300 -Subject: [PATCH] Replace CraftServer#getWorlds ArrayList with a fastutil - ObjectArrayList - -CraftServer#getWorlds is frequently used in some plugins, so replacing ArrayList with fastutil ObjectArrayList will give some performance boost - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 17022a57cb06b0ddd0df94075c0d92b68137d901..414fdc6ca7a2979124a7fbf529bff60f993c005a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -974,7 +974,7 @@ public final class CraftServer implements Server { - - @Override - public List getWorlds() { -- return new ArrayList(this.worlds.values()); -+ return new it.unimi.dsi.fastutil.objects.ObjectArrayList(this.worlds.values()); // DivineMC - Replace CraftServer#getWorlds ArrayList with a fastutil ObjectArrayList - } - - @Override diff --git a/divinemc-server/paper-patches/features/0018-Pufferfish-Optimize-mob-spawning.patch b/divinemc-server/paper-patches/features/0015-Pufferfish-Optimize-mob-spawning.patch similarity index 100% rename from divinemc-server/paper-patches/features/0018-Pufferfish-Optimize-mob-spawning.patch rename to divinemc-server/paper-patches/features/0015-Pufferfish-Optimize-mob-spawning.patch diff --git a/divinemc-server/paper-patches/features/0019-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch b/divinemc-server/paper-patches/features/0016-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch similarity index 100% rename from divinemc-server/paper-patches/features/0019-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch rename to divinemc-server/paper-patches/features/0016-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch diff --git a/divinemc-server/paper-patches/features/0020-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/paper-patches/features/0017-SparklyPaper-Parallel-world-ticking.patch similarity index 100% rename from divinemc-server/paper-patches/features/0020-SparklyPaper-Parallel-world-ticking.patch rename to divinemc-server/paper-patches/features/0017-SparklyPaper-Parallel-world-ticking.patch diff --git a/divinemc-server/paper-patches/features/0021-Rewrite-ReferenceList.patch b/divinemc-server/paper-patches/features/0018-Rewrite-ReferenceList.patch similarity index 100% rename from divinemc-server/paper-patches/features/0021-Rewrite-ReferenceList.patch rename to divinemc-server/paper-patches/features/0018-Rewrite-ReferenceList.patch diff --git a/divinemc-server/paper-patches/features/0023-Leaves-Protocol-Core.patch b/divinemc-server/paper-patches/features/0019-Leaves-Protocol-Core.patch similarity index 100% rename from divinemc-server/paper-patches/features/0023-Leaves-Protocol-Core.patch rename to divinemc-server/paper-patches/features/0019-Leaves-Protocol-Core.patch diff --git a/divinemc-server/paper-patches/features/0022-Configurable-Max-View-Distance.patch b/divinemc-server/paper-patches/files/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java.patch similarity index 52% rename from divinemc-server/paper-patches/features/0022-Configurable-Max-View-Distance.patch rename to divinemc-server/paper-patches/files/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java.patch index fdc3795..d8f4677 100644 --- a/divinemc-server/paper-patches/features/0022-Configurable-Max-View-Distance.patch +++ b/divinemc-server/paper-patches/files/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java.patch @@ -1,14 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Wed, 9 Jul 2025 04:40:05 +0300 -Subject: [PATCH] Configurable Max View Distance - - -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java -index 559c959aff3c9deef867b9e425fba3e2e669cac6..00aac7b5b610746f619b07502ceea5dd87e36ff7 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java -@@ -4,7 +4,7 @@ import ca.spottedleaf.moonrise.common.PlatformHooks; +@@ -4,7 +_,7 @@ public final class MoonriseConstants { diff --git a/divinemc-server/paper-patches/features/0012-Skip-event-if-no-listeners.patch b/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch similarity index 68% rename from divinemc-server/paper-patches/features/0012-Skip-event-if-no-listeners.patch rename to divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch index 6cf7bfc..9138b72 100644 --- a/divinemc-server/paper-patches/features/0012-Skip-event-if-no-listeners.patch +++ b/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch @@ -1,14 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Mon, 7 Jul 2025 04:04:20 +0300 -Subject: [PATCH] Skip event if no listeners - - -diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java -index 11e5b9ebafa562e5a93643d954839e86d0b731f0..d7398b1ecf2660c29fb7d106b48fe02d3736603e 100644 --- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java -@@ -35,15 +35,16 @@ class PaperEventManager { +@@ -36,14 +_,15 @@ // SimplePluginManager public void callEvent(@NotNull Event event) { @@ -21,10 +13,9 @@ index 11e5b9ebafa562e5a93643d954839e86d0b731f0..d7398b1ecf2660c29fb7d106b48fe02d } else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) { throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); } - +- - HandlerList handlers = event.getHandlers(); - RegisteredListener[] listeners = handlers.getRegisteredListeners(); -- + for (RegisteredListener registration : listeners) { if (!registration.getPlugin().isEnabled()) { - continue; diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch new file mode 100644 index 0000000..2c9b388 --- /dev/null +++ b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -974,7 +_,7 @@ + + @Override + public List getWorlds() { +- return new ArrayList(this.worlds.values()); ++ return new it.unimi.dsi.fastutil.objects.ObjectArrayList(this.worlds.values()); // DivineMC - Replace CraftServer#getWorlds ArrayList with a fastutil ObjectArrayList + } + + @Override diff --git a/divinemc-server/paper-patches/features/0013-Force-Minecraft-command.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java.patch similarity index 61% rename from divinemc-server/paper-patches/features/0013-Force-Minecraft-command.patch rename to divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java.patch index c3c3276..b7b1a06 100644 --- a/divinemc-server/paper-patches/features/0013-Force-Minecraft-command.patch +++ b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java.patch @@ -1,14 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Mon, 7 Jul 2025 04:05:08 +0300 -Subject: [PATCH] Force Minecraft command - - -diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java b/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java -index 90ed57a7fbcd0625b64084347460e9864216f610..138f37bf12f39152af97b14515007e9ca485967f 100644 --- a/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java +++ b/src/main/java/org/bukkit/craftbukkit/command/CraftCommandMap.java -@@ -14,4 +14,18 @@ public class CraftCommandMap extends SimpleCommandMap { +@@ -14,4 +_,18 @@ public Map getKnownCommands() { return this.knownCommands; } From 227fd30f7f812ecbe02319f2d25d797115d58ed3 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 17 Jul 2025 19:27:03 +0300 Subject: [PATCH 48/67] add option to skip entities in ret; set config version to 7 --- .../bxteam/divinemc/config/DivineConfig.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 27ba37f..70cbcc0 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -42,7 +42,7 @@ public class DivineConfig { Downloads: https://github.com/BX-Team/DivineMC/releases"""; public static final Logger LOGGER = LogManager.getLogger(DivineConfig.class.getSimpleName()); - public static final int CONFIG_VERSION = 6; + public static final int CONFIG_VERSION = 7; private static File configFile; public static final YamlFile config = new YamlFile(); @@ -618,6 +618,8 @@ public class DivineConfig { public static int retCheckIntervalMs = 10; public static int retTracingDistance = 48; public static int retHitboxLimit = 50; + public static List retSkippedEntities = List.of(); + public static boolean retInvertSkippedEntities = false; // Old features public static boolean copperBulb1gt = false; @@ -718,6 +720,28 @@ public class DivineConfig { "The distance in blocks to track entities in the raytrace entity tracker."); retHitboxLimit = getInt(ConfigCategory.MISC.key("raytrace-entity-tracker.hitbox-limit"), retHitboxLimit, "The maximum size of bounding box to trace."); + + retSkippedEntities = getStringList(ConfigCategory.MISC.key("raytrace-entity-tracker.skipped-entities"), retSkippedEntities, + "List of entity types to skip in raytrace entity tracker."); + retInvertSkippedEntities = getBoolean(ConfigCategory.MISC.key("raytrace-entity-tracker.invert-skipped-entities"), retInvertSkippedEntities, + "If true, the entities in the skipped list will be tracked, and all other entities will be untracked.", + "If false, the entities in the skipped list will be untracked, and all other entities will be tracked."); + + for (EntityType entityType : BuiltInRegistries.ENTITY_TYPE) { + entityType.skipRaytracingCheck = retInvertSkippedEntities; + } + + final String DEFAULT_PREFIX = ResourceLocation.DEFAULT_NAMESPACE + ResourceLocation.NAMESPACE_SEPARATOR; + + for (String name : retSkippedEntities) { + String lowerName = name.toLowerCase(Locale.ROOT); + String typeId = lowerName.startsWith(DEFAULT_PREFIX) ? lowerName : DEFAULT_PREFIX + lowerName; + + EntityType.byString(typeId).ifPresentOrElse(entityType -> + entityType.skipRaytracingCheck = !retInvertSkippedEntities, + () -> LOGGER.warn("Skipped unknown entity {} in {}", name, ConfigCategory.MISC.key("raytrace-entity-tracker.skipped-entities")) + ); + } } private static void oldFeatures() { From 14bec3717148b37407955a39849a5cc551346040 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:31:43 +0300 Subject: [PATCH 49/67] remove useless deque clear --- .../net/minecraft/world/ticks/LevelTicks.java.patch | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/ticks/LevelTicks.java.patch diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/ticks/LevelTicks.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/ticks/LevelTicks.java.patch new file mode 100644 index 0000000..32f1ee6 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/ticks/LevelTicks.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/ticks/LevelTicks.java ++++ b/net/minecraft/world/ticks/LevelTicks.java +@@ -191,7 +_,6 @@ + } + + private void cleanupAfterTick() { +- this.toRunThisTick.clear(); + this.containersToTick.clear(); + this.alreadyRunThisTick.clear(); + this.toRunThisTickSet.clear(); From be5a07876ca82b8e23e2f6ee065f44095c8f3cf8 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:44:04 +0300 Subject: [PATCH 50/67] sort classes --- .../0056-Petal-Async-Pathfinding.patch | 58 ++++++------- .../0057-Petal-Multithreaded-Tracker.patch | 4 +- ...058-Pufferfish-Optimize-mob-spawning.patch | 4 +- .../0060-C2ME-Density-Function-Compiler.patch | 82 +++++++++---------- ...-SparklyPaper-Parallel-world-ticking.patch | 24 +++--- .../0063-MSPT-Tracking-for-each-world.patch | 4 +- .../0064-Catch-update-suppressors.patch | 2 +- ...C2ME-Optimize-Aquifer-and-Beardifier.patch | 6 +- .../features/0071-Async-Join-Thread.patch | 8 +- .../features/0072-Leaves-Protocol-Core.patch | 2 +- .../0076-Linear-region-file-format.patch | 2 +- .../0014-Petal-Multithreaded-Tracker.patch | 4 +- .../common/IDensityFunctionsCaveScaler.java | 2 +- .../c2me/opts}/dfc/common/ast/AstNode.java | 4 +- .../opts}/dfc/common/ast/AstTransformer.java | 2 +- .../c2me/opts}/dfc/common/ast/EvalType.java | 4 +- .../c2me/opts}/dfc/common/ast/McToAst.java | 54 ++++++------ .../common/ast/binary/AbstractBinaryNode.java | 10 +-- .../opts}/dfc/common/ast/binary/AddNode.java | 8 +- .../opts}/dfc/common/ast/binary/MaxNode.java | 8 +- .../dfc/common/ast/binary/MaxShortNode.java | 8 +- .../opts}/dfc/common/ast/binary/MinNode.java | 8 +- .../dfc/common/ast/binary/MinShortNode.java | 8 +- .../opts}/dfc/common/ast/binary/MulNode.java | 8 +- .../common/ast/dfvisitor/StripBlending.java | 2 +- .../dfc/common/ast/misc/CacheLikeNode.java | 18 ++-- .../dfc/common/ast/misc/ConstantNode.java | 10 +-- .../dfc/common/ast/misc/DelegateNode.java | 16 ++-- .../dfc/common/ast/misc/RangeChoiceNode.java | 12 +-- .../opts}/dfc/common/ast/misc/RootNode.java | 10 +-- .../common/ast/misc/YClampedGradientNode.java | 10 +-- .../dfc/common/ast/noise/DFTNoiseNode.java | 10 +-- .../dfc/common/ast/noise/DFTShiftANode.java | 10 +-- .../dfc/common/ast/noise/DFTShiftBNode.java | 10 +-- .../dfc/common/ast/noise/DFTShiftNode.java | 10 +-- .../ast/noise/DFTWeirdScaledSamplerNode.java | 12 +-- .../common/ast/noise/ShiftedNoiseNode.java | 12 +-- .../dfc/common/ast/spline/SplineAstNode.java | 16 ++-- .../dfc/common/ast/spline/SplineSupport.java | 2 +- .../opts}/dfc/common/ast/unary/AbsNode.java | 8 +- .../common/ast/unary/AbstractUnaryNode.java | 8 +- .../opts}/dfc/common/ast/unary/CubeNode.java | 8 +- .../dfc/common/ast/unary/NegMulNode.java | 8 +- .../dfc/common/ast/unary/SquareNode.java | 8 +- .../dfc/common/ast/unary/SqueezeNode.java | 8 +- .../dfc/common/ducks/IArrayCacheCapable.java | 7 ++ .../common/ducks/IBlendingAwareVisitor.java | 2 +- .../dfc/common/ducks/ICoordinatesFilling.java | 2 +- .../dfc/common/ducks/IEqualityOverriding.java | 2 +- .../dfc/common/ducks/IFastCacheLike.java | 4 +- .../opts}/dfc/common/gen/BytecodeGen.java | 20 ++--- .../common/gen/CompiledDensityFunction.java | 6 +- .../opts}/dfc/common/gen/CompiledEntry.java | 6 +- .../gen/DelegatingBlendingAwareVisitor.java | 4 +- .../opts}/dfc/common/gen/IMultiMethod.java | 6 +- .../opts}/dfc/common/gen/ISingleMethod.java | 4 +- .../gen/SubCompiledDensityFunction.java | 14 ++-- .../opts}/dfc/common/util/ArrayCache.java | 2 +- .../dfc/common/vif/AstVanillaInterface.java | 12 +-- .../vif/EachApplierVanillaInterface.java | 8 +- .../common/vif/NoisePosVanillaInterface.java | 4 +- .../ishland/c2me/opts/dfc}/util/Files.java | 2 +- .../common/random_instances/RandomUtils.java} | 32 ++++---- .../ishland/flowsched}/util/Assertions.java | 2 +- .../pufferfish/util/AsyncExecutor.java} | 8 +- .../org/bxteam/divinemc/DivineBootstrap.java | 4 - .../network => async}/AsyncJoinHandler.java | 22 +---- .../pathfinding/AsyncPath.java | 2 +- .../pathfinding/AsyncPathProcessor.java | 2 +- .../pathfinding/NodeEvaluatorCache.java | 2 +- .../pathfinding/NodeEvaluatorFeatures.java | 2 +- .../pathfinding/NodeEvaluatorGenerator.java | 2 +- .../pathfinding/NodeEvaluatorType.java | 2 +- .../pathfinding/PathProcessState.java | 2 +- .../pathfinding/PathfindTaskRejectPolicy.java | 2 +- .../tracking/MultithreadedTracker.java | 2 +- .../world/ServerLevelTickThreadFactory.java} | 7 +- .../divinemc/async/world/TeleportState.java | 7 ++ .../bxteam/divinemc/config/DivineConfig.java | 4 +- .../dfc/common/ducks/IArrayCacheCapable.java | 7 -- .../divinemc/util/ExecutorShutdown.java | 6 +- .../divinemc/util/PWTTeleportState.java | 7 -- 82 files changed, 370 insertions(+), 391 deletions(-) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/IDensityFunctionsCaveScaler.java (90%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/AstNode.java (86%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/AstTransformer.java (61%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/EvalType.java (84%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/McToAst.java (72%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/binary/AbstractBinaryNode.java (93%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/binary/AddNode.java (87%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/binary/MaxNode.java (89%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/binary/MaxShortNode.java (94%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/binary/MinNode.java (89%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/binary/MinShortNode.java (94%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/binary/MulNode.java (93%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/dfvisitor/StripBlending.java (94%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/misc/CacheLikeNode.java (95%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/misc/ConstantNode.java (87%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/misc/DelegateNode.java (92%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/misc/RangeChoiceNode.java (97%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/misc/RootNode.java (90%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/misc/YClampedGradientNode.java (92%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/noise/DFTNoiseNode.java (94%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/noise/DFTShiftANode.java (93%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/noise/DFTShiftBNode.java (93%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/noise/DFTShiftNode.java (94%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/noise/DFTWeirdScaledSamplerNode.java (95%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/noise/ShiftedNoiseNode.java (96%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/spline/SplineAstNode.java (98%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/spline/SplineSupport.java (92%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/unary/AbsNode.java (89%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/unary/AbstractUnaryNode.java (91%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/unary/CubeNode.java (88%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/unary/NegMulNode.java (92%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/unary/SquareNode.java (87%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ast/unary/SqueezeNode.java (93%) create mode 100644 divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IArrayCacheCapable.java rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ducks/IBlendingAwareVisitor.java (63%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ducks/ICoordinatesFilling.java (69%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ducks/IEqualityOverriding.java (72%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/ducks/IFastCacheLike.java (85%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/gen/BytecodeGen.java (97%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/gen/CompiledDensityFunction.java (95%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/gen/CompiledEntry.java (68%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/gen/DelegatingBlendingAwareVisitor.java (89%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/gen/IMultiMethod.java (50%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/gen/ISingleMethod.java (55%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/gen/SubCompiledDensityFunction.java (92%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/util/ArrayCache.java (97%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/vif/AstVanillaInterface.java (91%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/vif/EachApplierVanillaInterface.java (87%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts}/dfc/common/vif/NoisePosVanillaInterface.java (87%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/c2me/opts/dfc}/util/Files.java (96%) rename divinemc-server/src/main/java/{org/bxteam/divinemc/util/RandomUtil.java => com/ishland/c2me/opts/worldgen/general/common/random_instances/RandomUtils.java} (81%) rename divinemc-server/src/main/java/{org/bxteam/divinemc => com/ishland/flowsched}/util/Assertions.java (95%) rename divinemc-server/src/main/java/{org/bxteam/divinemc/util/AsyncProcessor.java => gg/pufferfish/pufferfish/util/AsyncExecutor.java} (92%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{server/network => async}/AsyncJoinHandler.java (80%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{entity => async}/pathfinding/AsyncPath.java (99%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{entity => async}/pathfinding/AsyncPathProcessor.java (98%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{entity => async}/pathfinding/NodeEvaluatorCache.java (97%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{entity => async}/pathfinding/NodeEvaluatorFeatures.java (95%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{entity => async}/pathfinding/NodeEvaluatorGenerator.java (82%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{entity => async}/pathfinding/NodeEvaluatorType.java (90%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{entity => async}/pathfinding/PathProcessState.java (61%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{entity => async}/pathfinding/PathfindTaskRejectPolicy.java (91%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{entity => async}/tracking/MultithreadedTracker.java (99%) rename divinemc-server/src/main/java/org/bxteam/divinemc/{server/ServerLevelTickExecutorThreadFactory.java => async/world/ServerLevelTickThreadFactory.java} (80%) create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/async/world/TeleportState.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IArrayCacheCapable.java delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/util/PWTTeleportState.java diff --git a/divinemc-server/minecraft-patches/features/0056-Petal-Async-Pathfinding.patch b/divinemc-server/minecraft-patches/features/0056-Petal-Async-Pathfinding.patch index 0af68dc..f30600d 100644 --- a/divinemc-server/minecraft-patches/features/0056-Petal-Async-Pathfinding.patch +++ b/divinemc-server/minecraft-patches/features/0056-Petal-Async-Pathfinding.patch @@ -9,7 +9,7 @@ You can find the original code on https://github.com/Bloom-host/Petal Makes most pathfinding-related work happen asynchronously diff --git a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index 67cbf9f5760fae5db6f31e64095cd1b6be6ade8e..327a0414c8723420ffe34597464c1772768e8fa3 100644 +index 67cbf9f5760fae5db6f31e64095cd1b6be6ade8e..3e7db8ef9ba48d42e8373296031301308573b154 100644 --- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java @@ -94,21 +94,18 @@ public class AcquirePoi { @@ -29,7 +29,7 @@ index 67cbf9f5760fae5db6f31e64095cd1b6be6ade8e..327a0414c8723420ffe34597464c1772 + if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) { + Path possiblePath = findPathToPois(mob, set); + -+ org.bxteam.divinemc.entity.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> { ++ org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> { + processPath(acquirablePois, entityEventId, (Long2ObjectMap) map, memoryAccessor, level, mob, time, poiManager, set, path); }); } else { @@ -222,7 +222,7 @@ index 621ba76784f2b92790eca62be4d0688834335ab6..92d8899ff7d42ecc987a7bf2035cc724 private boolean tryComputePath(Mob mob, WalkTarget target, long time) { BlockPos blockPos = target.getTarget().currentBlockPosition(); diff --git a/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java b/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java -index 4f9f3367b1ca3903df03a80fa2b01a3d24e6e77d..87f218cbeda68d2996a354afabb8be70f513920e 100644 +index 4f9f3367b1ca3903df03a80fa2b01a3d24e6e77d..48b7e91191192266d57f4d4692d1865cbddae5c0 100644 --- a/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java +++ b/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java @@ -60,17 +60,18 @@ public class SetClosestHomeAsWalkTarget { @@ -243,7 +243,7 @@ index 4f9f3367b1ca3903df03a80fa2b01a3d24e6e77d..87f218cbeda68d2996a354afabb8be70 + if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) { + Path possiblePath = AcquirePoi.findPathToPois(mob, set); + -+ org.bxteam.divinemc.entity.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> { ++ org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> { + processPath(speedModifier, map, mutableLong, walkTarget, level, poiManager, mutableInt, path); + }); + } else { @@ -295,7 +295,7 @@ index 73bba480f3f017a8aed14562bd82ba33db04391c..b31976b68eec3cd0ab0620a487e99ecd Node node = path.getNode(i); this.doorPos = new BlockPos(node.x, node.y + 1, node.z); diff --git a/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java b/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java -index 458ceec68ca138b0aa9b70d6c934473c01d468f4..62e385f40294c2343ce0a3deb95229057539503b 100644 +index 458ceec68ca138b0aa9b70d6c934473c01d468f4..ff06ba3ede2f2e40aae8f9a0b997150cfaaeecb7 100644 --- a/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java +++ b/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java @@ -12,9 +12,25 @@ public class AmphibiousPathNavigation extends PathNavigation { @@ -303,7 +303,7 @@ index 458ceec68ca138b0aa9b70d6c934473c01d468f4..62e385f40294c2343ce0a3deb9522905 } + // DivineMC start - async path processing -+ private static final org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { ++ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { + AmphibiousNodeEvaluator nodeEvaluator = new AmphibiousNodeEvaluator(false); + nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); + nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); @@ -325,7 +325,7 @@ index 458ceec68ca138b0aa9b70d6c934473c01d468f4..62e385f40294c2343ce0a3deb9522905 } diff --git a/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java b/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java -index 077863b758fbc3e51f25bcf842d00a2cc07c6a2f..4b2cc7fa8848b6cb15cc82090bf37bcdd16f098a 100644 +index 077863b758fbc3e51f25bcf842d00a2cc07c6a2f..b544685d191af2dcf3742abe45693b1eab0507e8 100644 --- a/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java +++ b/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java @@ -16,9 +16,25 @@ public class FlyingPathNavigation extends PathNavigation { @@ -333,7 +333,7 @@ index 077863b758fbc3e51f25bcf842d00a2cc07c6a2f..4b2cc7fa8848b6cb15cc82090bf37bcd } + // DivineMC start - async path processing -+ private static final org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { ++ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { + FlyNodeEvaluator nodeEvaluator = new FlyNodeEvaluator(); + nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); + nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); @@ -363,7 +363,7 @@ index 077863b758fbc3e51f25bcf842d00a2cc07c6a2f..4b2cc7fa8848b6cb15cc82090bf37bcd if (!this.isDone()) { if (this.canUpdatePath()) { diff --git a/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java -index 86fccf3617a32f3791b03d8067e2eaf6b8d8bebb..2c26d30a7373c6ac8ead22894b63a8d6529ba1f2 100644 +index 86fccf3617a32f3791b03d8067e2eaf6b8d8bebb..348fe5b7f8f3d7c87891704115d911a271e8882a 100644 --- a/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java +++ b/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java @@ -24,9 +24,25 @@ public class GroundPathNavigation extends PathNavigation { @@ -371,7 +371,7 @@ index 86fccf3617a32f3791b03d8067e2eaf6b8d8bebb..2c26d30a7373c6ac8ead22894b63a8d6 } + // DivineMC start - async path processing -+ protected static final org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { ++ protected static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { + WalkNodeEvaluator nodeEvaluator = new WalkNodeEvaluator(); + nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); + nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); @@ -393,7 +393,7 @@ index 86fccf3617a32f3791b03d8067e2eaf6b8d8bebb..2c26d30a7373c6ac8ead22894b63a8d6 } diff --git a/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index 24dd92449f70144c79f25bf24942ebd666655ed2..8d243cac4a0ba0536bd65c39bf3483d056e00116 100644 +index 24dd92449f70144c79f25bf24942ebd666655ed2..90035d61f705094507e1738a77bd624bcab3d235 100644 --- a/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/net/minecraft/world/entity/ai/navigation/PathNavigation.java @@ -167,6 +167,10 @@ public abstract class PathNavigation { @@ -401,7 +401,7 @@ index 24dd92449f70144c79f25bf24942ebd666655ed2..8d243cac4a0ba0536bd65c39bf3483d0 } else if (!this.canUpdatePath()) { return null; + // DivineMC start - catch early if it's still processing these positions let it keep processing -+ } else if (this.path instanceof org.bxteam.divinemc.entity.pathfinding.AsyncPath asyncPath && !asyncPath.isProcessed() && asyncPath.hasSameProcessingPositions(targets)) { ++ } else if (this.path instanceof org.bxteam.divinemc.async.pathfinding.AsyncPath asyncPath && !asyncPath.isProcessed() && asyncPath.hasSameProcessingPositions(targets)) { + return this.path; + // DivineMC end - catch early if it's still processing these positions let it keep processing } else if (this.path != null && !this.path.isDone() && targets.contains(this.targetPos)) { @@ -420,7 +420,7 @@ index 24dd92449f70144c79f25bf24942ebd666655ed2..8d243cac4a0ba0536bd65c39bf3483d0 + // assign early a target position. most calls will only have 1 position + if (!targets.isEmpty()) this.targetPos = targets.iterator().next(); + -+ org.bxteam.divinemc.entity.pathfinding.AsyncPathProcessor.awaitProcessing(path, processedPath -> { ++ org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor.awaitProcessing(path, processedPath -> { + // check that processing didn't take so long that we calculated a new path + if (processedPath != this.path) return; + @@ -478,7 +478,7 @@ index 24dd92449f70144c79f25bf24942ebd666655ed2..8d243cac4a0ba0536bd65c39bf3483d0 Vec3 vec3 = new Vec3((endNode.x + this.mob.getX()) / 2.0, (endNode.y + this.mob.getY()) / 2.0, (endNode.z + this.mob.getZ()) / 2.0); return pos.closerToCenterThan(vec3, this.path.getNodeCount() - this.path.getNextNodeIndex()); diff --git a/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java b/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java -index ea0f6a19e4a79538e68917ba86cbc98be4dbca8d..2c9c16d30ae55e86e00d3b97447c870a66ac8f6e 100644 +index ea0f6a19e4a79538e68917ba86cbc98be4dbca8d..030d90f93dbbc07e94d4776198c368650539bf91 100644 --- a/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java +++ b/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java @@ -15,11 +15,27 @@ public class WaterBoundPathNavigation extends PathNavigation { @@ -486,7 +486,7 @@ index ea0f6a19e4a79538e68917ba86cbc98be4dbca8d..2c9c16d30ae55e86e00d3b97447c870a } + // DivineMC start - async path processing -+ private static final org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { ++ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { + SwimNodeEvaluator nodeEvaluator = new SwimNodeEvaluator(nodeEvaluatorFeatures.allowBreaching()); + nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); + nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); @@ -510,7 +510,7 @@ index ea0f6a19e4a79538e68917ba86cbc98be4dbca8d..2c9c16d30ae55e86e00d3b97447c870a } diff --git a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -index 1f96fd5085bacb4c584576c7cb9f51e7898e9b03..e56869b8c700bfd9fa25f7b7db8663c4b8bad006 100644 +index 1f96fd5085bacb4c584576c7cb9f51e7898e9b03..d975b89c7bb57562852596751a4ff881d3ecf193 100644 --- a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java +++ b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java @@ -57,17 +57,32 @@ public class NearestBedSensor extends Sensor { @@ -530,7 +530,7 @@ index 1f96fd5085bacb4c584576c7cb9f51e7898e9b03..e56869b8c700bfd9fa25f7b7db8663c4 + // DivineMC start - async pathfinding + if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) { + Path possiblePath = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes)); -+ org.bxteam.divinemc.entity.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> { ++ org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> { + processPath(entity, poiManager, path); + }); + } else { @@ -579,7 +579,7 @@ index ca5651f15552f91fba650747d28a75c00fa11442..c5883758d11e91f96b4139b3bd8586a8 } } diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java -index 85963b74a533beb7883ea417ceb3c21d834aebe0..1c9f3f0b2a344c026532c89c0db377ab8183c912 100644 +index 85963b74a533beb7883ea417ceb3c21d834aebe0..dd2874406ad224393ccf1b45aef88c396597e633 100644 --- a/net/minecraft/world/entity/animal/frog/Frog.java +++ b/net/minecraft/world/entity/animal/frog/Frog.java @@ -488,6 +488,17 @@ public class Frog extends Animal { @@ -587,7 +587,7 @@ index 85963b74a533beb7883ea417ceb3c21d834aebe0..1c9f3f0b2a344c026532c89c0db377ab } + // DivineMC start - async path processing -+ private static final org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { ++ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { + Frog.FrogNodeEvaluator nodeEvaluator = new Frog.FrogNodeEvaluator(true); + nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); + nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); @@ -626,7 +626,7 @@ index 2a13332ebabf2e63a8f51a5d794fab3d66c7a1db..d4e7fc0a5bda4f44bcfed3d1adae7cda if (target != null) { double d = this.distanceToSqr(target.getX(), target.getY(), target.getZ()); diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java -index fe31c4a45afd61be8b74efe9d0858ccd0aced075..859c41c3c81b3d3ac05eebdc83c959d196bd5b3e 100644 +index fe31c4a45afd61be8b74efe9d0858ccd0aced075..e2e42bbdba1daf6783d10a62aa4c4b1bcf138fe6 100644 --- a/net/minecraft/world/entity/monster/Strider.java +++ b/net/minecraft/world/entity/monster/Strider.java @@ -560,9 +560,25 @@ public class Strider extends Animal implements ItemSteerable { @@ -634,7 +634,7 @@ index fe31c4a45afd61be8b74efe9d0858ccd0aced075..859c41c3c81b3d3ac05eebdc83c959d1 } + // DivineMC start - async path processing -+ private static final org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { ++ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { + WalkNodeEvaluator nodeEvaluator = new WalkNodeEvaluator(); + nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); + nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); @@ -707,18 +707,18 @@ index d6d3c8f5e5dd4a8cab0d3fcc131c3a59f06130c6..839653a997f1e10970fa2956fadaf493 return false; } else if (pathentity.nodes.size() != this.nodes.size()) { diff --git a/net/minecraft/world/level/pathfinder/PathFinder.java b/net/minecraft/world/level/pathfinder/PathFinder.java -index c2baadcdceb1df6a881d6f73aa4eb4dd264bcdfe..8997908508c1dbe839aab25e4f546b9aa664047e 100644 +index c2baadcdceb1df6a881d6f73aa4eb4dd264bcdfe..38c8019f3cdfa351c120e80e312219416b157e6d 100644 --- a/net/minecraft/world/level/pathfinder/PathFinder.java +++ b/net/minecraft/world/level/pathfinder/PathFinder.java @@ -22,11 +22,19 @@ public class PathFinder { public final NodeEvaluator nodeEvaluator; private static final boolean DEBUG = false; private final BinaryHeap openSet = new BinaryHeap(); -+ private final @Nullable org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator; // DivineMC - we use this later to generate an evaluator ++ private final @Nullable org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator; // DivineMC - we use this later to generate an evaluator - public PathFinder(NodeEvaluator nodeEvaluator, int maxVisitedNodes) { + // DivineMC start - support nodeEvaluatorgenerators -+ public PathFinder(NodeEvaluator nodeEvaluator, int maxVisitedNodes, @Nullable org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator) { // DivineMC - add nodeEvaluatorGenerator ++ public PathFinder(NodeEvaluator nodeEvaluator, int maxVisitedNodes, @Nullable org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator) { // DivineMC - add nodeEvaluatorGenerator this.nodeEvaluator = nodeEvaluator; this.maxVisitedNodes = maxVisitedNodes; + this.nodeEvaluatorGenerator = nodeEvaluatorGenerator; @@ -743,12 +743,12 @@ index c2baadcdceb1df6a881d6f73aa4eb4dd264bcdfe..8997908508c1dbe839aab25e4f546b9a + this.openSet.clear(); // it's always cleared in processPath + NodeEvaluator nodeEvaluator = this.nodeEvaluatorGenerator == null + ? this.nodeEvaluator -+ : org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorCache.takeNodeEvaluator(this.nodeEvaluatorGenerator, this.nodeEvaluator); ++ : org.bxteam.divinemc.async.pathfinding.NodeEvaluatorCache.takeNodeEvaluator(this.nodeEvaluatorGenerator, this.nodeEvaluator); + nodeEvaluator.prepare(region, mob); + Node start = nodeEvaluator.getStart(); + // DivineMC end - use a generated evaluator if we have one otherwise run sync if (start == null) { -+ org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); // DivineMC - handle nodeEvaluatorGenerator ++ org.bxteam.divinemc.async.pathfinding.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); // DivineMC - handle nodeEvaluatorGenerator return null; } else { // Paper start - Perf: remove streams and optimize collection @@ -764,11 +764,11 @@ index c2baadcdceb1df6a881d6f73aa4eb4dd264bcdfe..8997908508c1dbe839aab25e4f546b9a + // DivineMC start - async path processing + if (this.nodeEvaluatorGenerator == null) { + // run sync :( -+ org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); ++ org.bxteam.divinemc.async.pathfinding.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); + return this.findPath(start, map, maxRange, accuracy, searchDepthMultiplier); + } + -+ return new org.bxteam.divinemc.entity.pathfinding.AsyncPath(Lists.newArrayList(), targetPositions, () -> { ++ return new org.bxteam.divinemc.async.pathfinding.AsyncPath(Lists.newArrayList(), targetPositions, () -> { + try { + return this.processPath(nodeEvaluator, start, map, maxRange, accuracy, searchDepthMultiplier); + } catch (Exception e) { @@ -776,7 +776,7 @@ index c2baadcdceb1df6a881d6f73aa4eb4dd264bcdfe..8997908508c1dbe839aab25e4f546b9a + return null; + } finally { + nodeEvaluator.done(); -+ org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorCache.returnNodeEvaluator(nodeEvaluator); ++ org.bxteam.divinemc.async.pathfinding.NodeEvaluatorCache.returnNodeEvaluator(nodeEvaluator); + } + }); + // DivineMC end - async path processing diff --git a/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch b/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch index 424b895..14856a6 100644 --- a/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch +++ b/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch @@ -66,7 +66,7 @@ index 9c0c99b936b4a82ebfe924866e53ec71f7bbe9ad..01ed1e3572e9c2ccfd19df117cda0d5c .add( new ClientboundUpdateAttributesPacket.AttributeSnapshot( diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index c0d996fb99f053863ce623889add3feb70d7137d..a3290eb416ecb377d240bf334aef4e2b5e3bbefc 100644 +index c0d996fb99f053863ce623889add3feb70d7137d..7ca147cf9da67c399806056e5092841f7ca32321 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java @@ -255,9 +255,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -98,7 +98,7 @@ index c0d996fb99f053863ce623889add3feb70d7137d..a3290eb416ecb377d240bf334aef4e2b + // DivineMC start - Multithreaded tracker + if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled) { + final ServerLevel level = this.level; -+ org.bxteam.divinemc.entity.tracking.MultithreadedTracker.tick(level); ++ org.bxteam.divinemc.async.tracking.MultithreadedTracker.tick(level); + return; + } + // DivineMC end - Multithreaded tracker diff --git a/divinemc-server/minecraft-patches/features/0058-Pufferfish-Optimize-mob-spawning.patch b/divinemc-server/minecraft-patches/features/0058-Pufferfish-Optimize-mob-spawning.patch index bf55e8f..e925976 100644 --- a/divinemc-server/minecraft-patches/features/0058-Pufferfish-Optimize-mob-spawning.patch +++ b/divinemc-server/minecraft-patches/features/0058-Pufferfish-Optimize-mob-spawning.patch @@ -9,14 +9,14 @@ Original project: https://github.com/pufferfish-gg/Pufferfish This patch reduces the main-thread impact of mob spawning by moving spawning work to other threads diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 4a53105e46e338a52bc5ad22d51688a9a261d9e5..ed4a722c0fa458a0977366b92561d6a16827da56 100644 +index 4a53105e46e338a52bc5ad22d51688a9a261d9e5..9bd7cc58cf10489f0e463347cdc2bc537f0509ec 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -289,6 +289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function threadFunction) { ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system diff --git a/divinemc-server/minecraft-patches/features/0060-C2ME-Density-Function-Compiler.patch b/divinemc-server/minecraft-patches/features/0060-C2ME-Density-Function-Compiler.patch index dbdaee6..3abb81c 100644 --- a/divinemc-server/minecraft-patches/features/0060-C2ME-Density-Function-Compiler.patch +++ b/divinemc-server/minecraft-patches/features/0060-C2ME-Density-Function-Compiler.patch @@ -111,7 +111,7 @@ index f36f8f2d49d4eba5c80eb243883749d6f831eb8a..b43b7e242ea0a4f87704853c03201144 } } diff --git a/net/minecraft/world/level/levelgen/DensityFunctions.java b/net/minecraft/world/level/levelgen/DensityFunctions.java -index 4c53031cf8f6198825b190955d96f20bbcccd77e..fb3c3c3e837056e2762cf32050440ed7a4142ddc 100644 +index 4c53031cf8f6198825b190955d96f20bbcccd77e..2b65f922f802a9dbea56f1bae0d243af1080501f 100644 --- a/net/minecraft/world/level/levelgen/DensityFunctions.java +++ b/net/minecraft/world/level/levelgen/DensityFunctions.java @@ -275,38 +275,66 @@ public final class DensityFunctions { @@ -182,7 +182,7 @@ index 4c53031cf8f6198825b190955d96f20bbcccd77e..fb3c3c3e837056e2762cf32050440ed7 - break; - case MAX: - d1 = this.argument2.maxValue(); -+ org.bxteam.divinemc.dfc.common.util.ArrayCache arrayCache = contextProvider instanceof org.bxteam.divinemc.dfc.common.ducks.IArrayCacheCapable arrayCacheCapable ? arrayCacheCapable.c2me$getArrayCache() : null; ++ com.ishland.c2me.opts.dfc.common.util.ArrayCache arrayCache = contextProvider instanceof com.ishland.c2me.opts.dfc.common.ducks.IArrayCacheCapable arrayCacheCapable ? arrayCacheCapable.c2me$getArrayCache() : null; - for (int i2 = 0; i2 < array.length; i2++) { - double d2 = array[i2]; @@ -216,7 +216,7 @@ index 4c53031cf8f6198825b190955d96f20bbcccd77e..fb3c3c3e837056e2762cf32050440ed7 - protected record Marker(@Override DensityFunctions.Marker.Type type, @Override DensityFunction wrapped) implements DensityFunctions.MarkerOrMarked { + // DivineMC start - Density Function Compiler -+ public static final class Marker implements org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike, org.bxteam.divinemc.dfc.common.ducks.IEqualityOverriding, MarkerOrMarked { ++ public static final class Marker implements com.ishland.c2me.opts.dfc.common.ducks.IFastCacheLike, com.ishland.c2me.opts.dfc.common.ducks.IEqualityOverriding, MarkerOrMarked { + private final Type type; + private final DensityFunction wrapped; + private Object c2me$optionalEquality; @@ -234,7 +234,7 @@ index 4c53031cf8f6198825b190955d96f20bbcccd77e..fb3c3c3e837056e2762cf32050440ed7 + return original.apply(that); + } + Object a = this.c2me$getOverriddenEquality(); -+ Object b = that instanceof org.bxteam.divinemc.dfc.common.ducks.IEqualityOverriding equalityOverriding ? equalityOverriding.c2me$getOverriddenEquality() : null; ++ Object b = that instanceof com.ishland.c2me.opts.dfc.common.ducks.IEqualityOverriding equalityOverriding ? equalityOverriding.c2me$getOverriddenEquality() : null; + if (a == null) { + return original.apply(b != null ? b : that); + } else { @@ -259,22 +259,22 @@ index 4c53031cf8f6198825b190955d96f20bbcccd77e..fb3c3c3e837056e2762cf32050440ed7 + } + + @Override -+ public double c2me$getCached(int x, int y, int z, org.bxteam.divinemc.dfc.common.ast.EvalType evalType) { ++ public double c2me$getCached(int x, int y, int z, com.ishland.c2me.opts.dfc.common.ast.EvalType evalType) { + return Double.longBitsToDouble(CACHE_MISS_NAN_BITS); + } + + @Override -+ public boolean c2me$getCached(double[] res, int[] x, int[] y, int[] z, org.bxteam.divinemc.dfc.common.ast.EvalType evalType) { ++ public boolean c2me$getCached(double[] res, int[] x, int[] y, int[] z, com.ishland.c2me.opts.dfc.common.ast.EvalType evalType) { + return false; + } + + @Override -+ public void c2me$cache(int x, int y, int z, org.bxteam.divinemc.dfc.common.ast.EvalType evalType, double cached) { ++ public void c2me$cache(int x, int y, int z, com.ishland.c2me.opts.dfc.common.ast.EvalType evalType, double cached) { + // nop + } + + @Override -+ public void c2me$cache(double[] res, int[] x, int[] y, int[] z, org.bxteam.divinemc.dfc.common.ast.EvalType evalType) { ++ public void c2me$cache(double[] res, int[] x, int[] y, int[] z, com.ishland.c2me.opts.dfc.common.ast.EvalType evalType) { + // nop + } + @@ -286,7 +286,7 @@ index 4c53031cf8f6198825b190955d96f20bbcccd77e..fb3c3c3e837056e2762cf32050440ed7 + @Override + public DensityFunction c2me$withDelegate(DensityFunction delegate) { + DensityFunctions.Marker wrapping = new DensityFunctions.Marker(this.type(), delegate); -+ ((org.bxteam.divinemc.dfc.common.ducks.IEqualityOverriding) (Object) wrapping).c2me$overrideEquality(this); ++ ((com.ishland.c2me.opts.dfc.common.ducks.IEqualityOverriding) (Object) wrapping).c2me$overrideEquality(this); + return wrapping; + } + @@ -294,7 +294,7 @@ index 4c53031cf8f6198825b190955d96f20bbcccd77e..fb3c3c3e837056e2762cf32050440ed7 + public void c2me$overrideEquality(Object object) { + Object inner = object; + while (true) { -+ Object inner1 = inner instanceof org.bxteam.divinemc.dfc.common.ducks.IEqualityOverriding e1 ? e1.c2me$getOverriddenEquality() : null; ++ Object inner1 = inner instanceof com.ishland.c2me.opts.dfc.common.ducks.IEqualityOverriding e1 ? e1.c2me$getOverriddenEquality() : null; + if (inner1 == null) { + this.c2me$optionalEquality = inner; + break; @@ -339,7 +339,7 @@ index 4c53031cf8f6198825b190955d96f20bbcccd77e..fb3c3c3e837056e2762cf32050440ed7 FlatCache("flat_cache"), Cache2D("cache_2d"), diff --git a/net/minecraft/world/level/levelgen/NoiseChunk.java b/net/minecraft/world/level/levelgen/NoiseChunk.java -index 977b0d595e5637c80e7d4bb20da8896a0b64b844..840c15e4e2613c20b6d4fbcb44cb096997958bd3 100644 +index 977b0d595e5637c80e7d4bb20da8896a0b64b844..1a3da40d668054c92027cfe83d2ddbd803e0a1dd 100644 --- a/net/minecraft/world/level/levelgen/NoiseChunk.java +++ b/net/minecraft/world/level/levelgen/NoiseChunk.java @@ -4,9 +4,11 @@ import com.google.common.collect.Lists; @@ -360,14 +360,14 @@ index 977b0d595e5637c80e7d4bb20da8896a0b64b844..840c15e4e2613c20b6d4fbcb44cb0969 -public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunction.FunctionContext { +// DivineMC start - Density Function Compiler -+import org.bxteam.divinemc.dfc.common.ast.EvalType; -+import org.bxteam.divinemc.dfc.common.ducks.IArrayCacheCapable; -+import org.bxteam.divinemc.dfc.common.ducks.ICoordinatesFilling; -+import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike; -+import org.bxteam.divinemc.dfc.common.gen.DelegatingBlendingAwareVisitor; -+import org.bxteam.divinemc.dfc.common.util.ArrayCache; -+import org.bxteam.divinemc.dfc.common.vif.EachApplierVanillaInterface; -+import org.bxteam.divinemc.dfc.common.vif.NoisePosVanillaInterface; ++import com.ishland.c2me.opts.dfc.common.ast.EvalType; ++import com.ishland.c2me.opts.dfc.common.ducks.IArrayCacheCapable; ++import com.ishland.c2me.opts.dfc.common.ducks.ICoordinatesFilling; ++import com.ishland.c2me.opts.dfc.common.ducks.IFastCacheLike; ++import com.ishland.c2me.opts.dfc.common.gen.DelegatingBlendingAwareVisitor; ++import com.ishland.c2me.opts.dfc.common.util.ArrayCache; ++import com.ishland.c2me.opts.dfc.common.vif.EachApplierVanillaInterface; ++import com.ishland.c2me.opts.dfc.common.vif.NoisePosVanillaInterface; +// DivineMC end - Density Function Compiler + +public class NoiseChunk implements DensityFunction.ContextProvider, DensityFunction.FunctionContext, IArrayCacheCapable, ICoordinatesFilling { @@ -1153,7 +1153,7 @@ index 977b0d595e5637c80e7d4bb20da8896a0b64b844..840c15e4e2613c20b6d4fbcb44cb0969 @Override diff --git a/net/minecraft/world/level/levelgen/RandomState.java b/net/minecraft/world/level/levelgen/RandomState.java -index f1e089ecfffa40cd794c49db30fcedf138d3fee9..b28221ca337ce8d76bbccdd736a4c5b2c7cd08da 100644 +index f1e089ecfffa40cd794c49db30fcedf138d3fee9..3d8bdd7e40c7457c0ad7729162b43cba2043b8b5 100644 --- a/net/minecraft/world/level/levelgen/RandomState.java +++ b/net/minecraft/world/level/levelgen/RandomState.java @@ -122,6 +122,41 @@ public final class RandomState { @@ -1166,29 +1166,29 @@ index f1e089ecfffa40cd794c49db30fcedf138d3fee9..b28221ca337ce8d76bbccdd736a4c5b2 + com.google.common.base.Stopwatch stopwatch = com.google.common.base.Stopwatch.createStarted(); + it.unimi.dsi.fastutil.objects.Reference2ReferenceMap tempCache = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(); + this.router = new NoiseRouter( -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.barrierNoise(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.fluidLevelFloodednessNoise(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.fluidLevelSpreadNoise(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.lavaNoise(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.temperature(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.vegetation(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.continents(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.erosion(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.depth(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.ridges(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.initialDensityWithoutJaggedness(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.finalDensity(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.veinToggle(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.veinRidged(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.router.veinGap(), tempCache) ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.barrierNoise(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.fluidLevelFloodednessNoise(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.fluidLevelSpreadNoise(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.lavaNoise(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.temperature(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.vegetation(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.continents(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.erosion(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.depth(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.ridges(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.initialDensityWithoutJaggedness(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.finalDensity(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.veinToggle(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.veinRidged(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.router.veinGap(), tempCache) + ); + this.sampler = new Climate.Sampler( -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.sampler.temperature(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.sampler.humidity(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.sampler.continentalness(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.sampler.erosion(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.sampler.depth(), tempCache), -+ org.bxteam.divinemc.dfc.common.gen.BytecodeGen.compile(this.sampler.weirdness(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.temperature(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.humidity(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.continentalness(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.erosion(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.depth(), tempCache), ++ com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.compile(this.sampler.weirdness(), tempCache), + this.sampler.spawnTarget() + ); + stopwatch.stop(); diff --git a/divinemc-server/minecraft-patches/features/0062-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0062-SparklyPaper-Parallel-world-ticking.patch index 1fb2468..45c9c8c 100644 --- a/divinemc-server/minecraft-patches/features/0062-SparklyPaper-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0062-SparklyPaper-Parallel-world-ticking.patch @@ -82,13 +82,13 @@ index ac27ff24f018d8798921c5152e679ceed1e88d8d..ec7d1353b19e55b00c558df8981323ef List states = new java.util.ArrayList<>(level.capturedBlockStates.values()); level.capturedBlockStates.clear(); diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index ed4a722c0fa458a0977366b92561d6a16827da56..9f5beb74d8b0198aebf7cad40def52d12a4a9b3d 100644 +index 951199cb015694790ea8d81264779a7d294ab6ef..85f0abc2ead2d78a7189abaac8f803b70328a21b 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -290,6 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function threadFunction) { @@ -363,7 +363,7 @@ index bf680624bc6c618dfa0eeeb74c103ff6716fd27e..654d03368f06ab9870c11745b0994ea6 } } diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 3c1795eb56900cd80cfec38bd1d922d566463ecb..07b9a2529be69bf8158528e996e7ddb95ede9614 100644 +index 3c1795eb56900cd80cfec38bd1d922d566463ecb..b752bcc03b558a26f9c592c829efb44a299be8de 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -180,7 +180,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -396,7 +396,7 @@ index 3c1795eb56900cd80cfec38bd1d922d566463ecb..07b9a2529be69bf8158528e996e7ddb9 this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle this.ominousBanner = Objects.requireNonNullElse(this.registryAccess(), net.minecraft.core.RegistryAccess.EMPTY).lookup(Registries.BANNER_PATTERN).map(Raid::getOminousBannerInstance).orElse(null); // DivineMC - Optimize Raids -+ this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new org.bxteam.divinemc.server.ServerLevelTickExecutorThreadFactory(getWorld().getName())); // DivineMC - Parallel world ticking ++ this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new org.bxteam.divinemc.async.world.ServerLevelTickThreadFactory(getWorld().getName())); // DivineMC - Parallel world ticking } // Paper start @@ -686,14 +686,14 @@ index bdf9899f960b6cca3529af97ebff738761208439..adea48cfde04df3107341075f414133a List list = new ArrayList<>(passengers.size()); this.ejectPassengers(); diff --git a/net/minecraft/world/entity/PortalProcessor.java b/net/minecraft/world/entity/PortalProcessor.java -index 91f6d43b3785ddad7db8eb529ba3293c45f3588d..fc3ab0881bf9b275beb9b32ca5a7475d50789401 100644 +index 91f6d43b3785ddad7db8eb529ba3293c45f3588d..7fd5f40ee928330769bbe0c5e8da17fa65b30db6 100644 --- a/net/minecraft/world/entity/PortalProcessor.java +++ b/net/minecraft/world/entity/PortalProcessor.java @@ -11,6 +11,7 @@ public class PortalProcessor { private BlockPos entryPosition; private int portalTime; private boolean insidePortalThisTick; -+ private org.bxteam.divinemc.util.PWTTeleportState teleportState = org.bxteam.divinemc.util.PWTTeleportState.INACTIVE; // DivineMC - Parallel world ticking ++ private org.bxteam.divinemc.async.world.TeleportState teleportState = org.bxteam.divinemc.async.world.TeleportState.INACTIVE; // DivineMC - Parallel world ticking public PortalProcessor(Portal portal, BlockPos entryPosition) { this.portal = portal; @@ -721,27 +721,27 @@ index 91f6d43b3785ddad7db8eb529ba3293c45f3588d..fc3ab0881bf9b275beb9b32ca5a7475d + + // DivineMC start - Parallel world ticking + public boolean isParallelTeleportPending() { -+ return this.teleportState == org.bxteam.divinemc.util.PWTTeleportState.PENDING; ++ return this.teleportState == org.bxteam.divinemc.async.world.TeleportState.PENDING; + } + + public boolean isParallelTeleportScheduled() { -+ return this.teleportState != org.bxteam.divinemc.util.PWTTeleportState.INACTIVE; ++ return this.teleportState != org.bxteam.divinemc.async.world.TeleportState.INACTIVE; + } + + public boolean isParallelCancelledByPlugin() { -+ return this.teleportState == org.bxteam.divinemc.util.PWTTeleportState.CANCELLED; ++ return this.teleportState == org.bxteam.divinemc.async.world.TeleportState.CANCELLED; + } + + public void setParallelAsScheduled() { -+ this.teleportState = org.bxteam.divinemc.util.PWTTeleportState.PENDING; ++ this.teleportState = org.bxteam.divinemc.async.world.TeleportState.PENDING; + } + + public void confirmParallelAsHandled() { -+ this.teleportState = org.bxteam.divinemc.util.PWTTeleportState.INACTIVE; ++ this.teleportState = org.bxteam.divinemc.async.world.TeleportState.INACTIVE; + } + + public void setParallelAsCancelled() { -+ this.teleportState = org.bxteam.divinemc.util.PWTTeleportState.CANCELLED; ++ this.teleportState = org.bxteam.divinemc.async.world.TeleportState.CANCELLED; + } + // DivineMC end - Parallel world ticking } diff --git a/divinemc-server/minecraft-patches/features/0063-MSPT-Tracking-for-each-world.patch b/divinemc-server/minecraft-patches/features/0063-MSPT-Tracking-for-each-world.patch index a47025b..df8753f 100644 --- a/divinemc-server/minecraft-patches/features/0063-MSPT-Tracking-for-each-world.patch +++ b/divinemc-server/minecraft-patches/features/0063-MSPT-Tracking-for-each-world.patch @@ -5,7 +5,7 @@ Subject: [PATCH] MSPT Tracking for each world diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 9f5beb74d8b0198aebf7cad40def52d12a4a9b3d..4bbb9b8701e4f5a411a12b8fd977e6de19a22b26 100644 +index 85f0abc2ead2d78a7189abaac8f803b70328a21b..432b4b981353fe8427f9675806500e43a080535c 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -1677,7 +1677,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { + // DivineMC start - Async Join Thread -+ org.bxteam.divinemc.server.network.AsyncJoinHandler.runAsync(() -> { ++ org.bxteam.divinemc.async.AsyncJoinHandler.runAsync(() -> { try { GameProfile gameprofile = ServerLoginPacketListenerImpl.this.createOfflineProfile(ServerLoginPacketListenerImpl.this.requestedUsername); // Spigot @@ -54,7 +54,7 @@ index 443aebb71b2a55ee9dcd2dd4bf9a30fbb8da9e49..cd926f0576d73bc3ef41c9a075a7ac9c // Paper start - Cache authenticator threads - authenticatorPool.execute(new Runnable() { + // DivineMC start - Async Join Thread -+ org.bxteam.divinemc.server.network.AsyncJoinHandler.runAsync(new Runnable() { ++ org.bxteam.divinemc.async.AsyncJoinHandler.runAsync(new Runnable() { @Override public void run() { String string1 = Objects.requireNonNull(ServerLoginPacketListenerImpl.this.requestedUsername, "Player name not initialized"); @@ -64,7 +64,7 @@ index 443aebb71b2a55ee9dcd2dd4bf9a30fbb8da9e49..cd926f0576d73bc3ef41c9a075a7ac9c // Proceed with login - authenticatorPool.execute(() -> { + // DivineMC start - Async Join Thread -+ org.bxteam.divinemc.server.network.AsyncJoinHandler.runAsync(() -> { ++ org.bxteam.divinemc.async.AsyncJoinHandler.runAsync(() -> { try { final GameProfile gameprofile = this.callPlayerPreLoginEvents(this.authenticatedProfile); ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId()); diff --git a/divinemc-server/minecraft-patches/features/0072-Leaves-Protocol-Core.patch b/divinemc-server/minecraft-patches/features/0072-Leaves-Protocol-Core.patch index 960fe5b..8ef8ce9 100644 --- a/divinemc-server/minecraft-patches/features/0072-Leaves-Protocol-Core.patch +++ b/divinemc-server/minecraft-patches/features/0072-Leaves-Protocol-Core.patch @@ -54,7 +54,7 @@ index 62b9d9486c15a1ec6527f786df4e9fc483390bcb..36d8b93182cc44e3bea245800ea9e271 int i = buffer.readableBytes(); if (i >= 0 && i <= maxSize) { diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index b31a4edee0616a63026f7a4335205f2d99d2f641..0072f3f07b1962adc1766930bb9a2f709cb76e6e 100644 +index b6cfd764273a2102525a66955ab2217071d0154d..0ccfbee593fc16073484b1d4ed9458406b8cce50 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -1788,6 +1788,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop future = new java.util.concurrent.CompletableFuture<>(); + net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { + boolean resultFlag = false; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/IDensityFunctionsCaveScaler.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/IDensityFunctionsCaveScaler.java similarity index 90% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/IDensityFunctionsCaveScaler.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/IDensityFunctionsCaveScaler.java index 1fa43ca..42c76c1 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/IDensityFunctionsCaveScaler.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/IDensityFunctionsCaveScaler.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.dfc.common; +package com.ishland.c2me.opts.dfc.common; import net.minecraft.world.level.levelgen.NoiseRouterData; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/AstNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/AstNode.java similarity index 86% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/AstNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/AstNode.java index c61fcb7..b9e1da7 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/AstNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/AstNode.java @@ -1,6 +1,6 @@ -package org.bxteam.divinemc.dfc.common.ast; +package com.ishland.c2me.opts.dfc.common.ast; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import org.objectweb.asm.commons.InstructionAdapter; public interface AstNode { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/AstTransformer.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/AstTransformer.java similarity index 61% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/AstTransformer.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/AstTransformer.java index 81017d3..3a97e4f 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/AstTransformer.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/AstTransformer.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.dfc.common.ast; +package com.ishland.c2me.opts.dfc.common.ast; public interface AstTransformer { AstNode transform(AstNode var1); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/EvalType.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/EvalType.java similarity index 84% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/EvalType.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/EvalType.java index 3e19f35..3878311 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/EvalType.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/EvalType.java @@ -1,6 +1,6 @@ -package org.bxteam.divinemc.dfc.common.ast; +package com.ishland.c2me.opts.dfc.common.ast; -import org.bxteam.divinemc.dfc.common.vif.EachApplierVanillaInterface; +import com.ishland.c2me.opts.dfc.common.vif.EachApplierVanillaInterface; import net.minecraft.world.level.levelgen.DensityFunction; import net.minecraft.world.level.levelgen.NoiseChunk; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/McToAst.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/McToAst.java similarity index 72% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/McToAst.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/McToAst.java index 532e6fb..245e338 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/McToAst.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/McToAst.java @@ -1,31 +1,31 @@ -package org.bxteam.divinemc.dfc.common.ast; +package com.ishland.c2me.opts.dfc.common.ast; -import org.bxteam.divinemc.dfc.common.ast.binary.AddNode; -import org.bxteam.divinemc.dfc.common.ast.binary.MaxNode; -import org.bxteam.divinemc.dfc.common.ast.binary.MaxShortNode; -import org.bxteam.divinemc.dfc.common.ast.binary.MinNode; -import org.bxteam.divinemc.dfc.common.ast.binary.MinShortNode; -import org.bxteam.divinemc.dfc.common.ast.binary.MulNode; -import org.bxteam.divinemc.dfc.common.ast.misc.CacheLikeNode; -import org.bxteam.divinemc.dfc.common.ast.misc.ConstantNode; -import org.bxteam.divinemc.dfc.common.ast.misc.DelegateNode; -import org.bxteam.divinemc.dfc.common.ast.misc.RangeChoiceNode; -import org.bxteam.divinemc.dfc.common.ast.misc.YClampedGradientNode; -import org.bxteam.divinemc.dfc.common.ast.noise.DFTNoiseNode; -import org.bxteam.divinemc.dfc.common.ast.noise.DFTShiftANode; -import org.bxteam.divinemc.dfc.common.ast.noise.DFTShiftBNode; -import org.bxteam.divinemc.dfc.common.ast.noise.DFTShiftNode; -import org.bxteam.divinemc.dfc.common.ast.noise.DFTWeirdScaledSamplerNode; -import org.bxteam.divinemc.dfc.common.ast.noise.ShiftedNoiseNode; -import org.bxteam.divinemc.dfc.common.ast.spline.SplineAstNode; -import org.bxteam.divinemc.dfc.common.ast.unary.AbsNode; -import org.bxteam.divinemc.dfc.common.ast.unary.CubeNode; -import org.bxteam.divinemc.dfc.common.ast.unary.NegMulNode; -import org.bxteam.divinemc.dfc.common.ast.unary.SquareNode; -import org.bxteam.divinemc.dfc.common.ast.unary.SqueezeNode; -import org.bxteam.divinemc.dfc.common.ducks.IEqualityOverriding; -import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike; -import org.bxteam.divinemc.dfc.common.vif.AstVanillaInterface; +import com.ishland.c2me.opts.dfc.common.ast.binary.AddNode; +import com.ishland.c2me.opts.dfc.common.ast.binary.MaxNode; +import com.ishland.c2me.opts.dfc.common.ast.binary.MaxShortNode; +import com.ishland.c2me.opts.dfc.common.ast.binary.MinNode; +import com.ishland.c2me.opts.dfc.common.ast.binary.MinShortNode; +import com.ishland.c2me.opts.dfc.common.ast.binary.MulNode; +import com.ishland.c2me.opts.dfc.common.ast.misc.CacheLikeNode; +import com.ishland.c2me.opts.dfc.common.ast.misc.ConstantNode; +import com.ishland.c2me.opts.dfc.common.ast.misc.DelegateNode; +import com.ishland.c2me.opts.dfc.common.ast.misc.RangeChoiceNode; +import com.ishland.c2me.opts.dfc.common.ast.misc.YClampedGradientNode; +import com.ishland.c2me.opts.dfc.common.ast.noise.DFTNoiseNode; +import com.ishland.c2me.opts.dfc.common.ast.noise.DFTShiftANode; +import com.ishland.c2me.opts.dfc.common.ast.noise.DFTShiftBNode; +import com.ishland.c2me.opts.dfc.common.ast.noise.DFTShiftNode; +import com.ishland.c2me.opts.dfc.common.ast.noise.DFTWeirdScaledSamplerNode; +import com.ishland.c2me.opts.dfc.common.ast.noise.ShiftedNoiseNode; +import com.ishland.c2me.opts.dfc.common.ast.spline.SplineAstNode; +import com.ishland.c2me.opts.dfc.common.ast.unary.AbsNode; +import com.ishland.c2me.opts.dfc.common.ast.unary.CubeNode; +import com.ishland.c2me.opts.dfc.common.ast.unary.NegMulNode; +import com.ishland.c2me.opts.dfc.common.ast.unary.SquareNode; +import com.ishland.c2me.opts.dfc.common.ast.unary.SqueezeNode; +import com.ishland.c2me.opts.dfc.common.ducks.IEqualityOverriding; +import com.ishland.c2me.opts.dfc.common.ducks.IFastCacheLike; +import com.ishland.c2me.opts.dfc.common.vif.AstVanillaInterface; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import net.minecraft.world.level.levelgen.DensityFunctions; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/AbstractBinaryNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/AbstractBinaryNode.java similarity index 93% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/AbstractBinaryNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/AbstractBinaryNode.java index 7c01c36..17e53a6 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/AbstractBinaryNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/AbstractBinaryNode.java @@ -1,9 +1,9 @@ -package org.bxteam.divinemc.dfc.common.ast.binary; +package com.ishland.c2me.opts.dfc.common.ast.binary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context; -import org.bxteam.divinemc.dfc.common.util.ArrayCache; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.Context; +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; import java.util.Objects; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/AddNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/AddNode.java similarity index 87% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/AddNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/AddNode.java index 53b50d6..118619c 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/AddNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/AddNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.binary; +package com.ishland.c2me.opts.dfc.common.ast.binary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MaxNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MaxNode.java similarity index 89% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MaxNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MaxNode.java index bed1a4c..df10413 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MaxNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MaxNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.binary; +package com.ishland.c2me.opts.dfc.common.ast.binary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MaxShortNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MaxShortNode.java similarity index 94% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MaxShortNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MaxShortNode.java index 8cab854..13fe3f1 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MaxShortNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MaxShortNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.binary; +package com.ishland.c2me.opts.dfc.common.ast.binary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.Context; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MinNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MinNode.java similarity index 89% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MinNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MinNode.java index 909180b..d37312b 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MinNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MinNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.binary; +package com.ishland.c2me.opts.dfc.common.ast.binary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MinShortNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MinShortNode.java similarity index 94% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MinShortNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MinShortNode.java index 615ca64..9335d4d 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MinShortNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MinShortNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.binary; +package com.ishland.c2me.opts.dfc.common.ast.binary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.Context; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MulNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MulNode.java similarity index 93% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MulNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MulNode.java index 87cc44c..bcf9a4d 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/binary/MulNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/binary/MulNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.binary; +package com.ishland.c2me.opts.dfc.common.ast.binary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.Context; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/dfvisitor/StripBlending.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/dfvisitor/StripBlending.java similarity index 94% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/dfvisitor/StripBlending.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/dfvisitor/StripBlending.java index ad9fa65..20e02d6 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/dfvisitor/StripBlending.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/dfvisitor/StripBlending.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.dfc.common.ast.dfvisitor; +package com.ishland.c2me.opts.dfc.common.ast.dfvisitor; import net.minecraft.world.level.levelgen.DensityFunction; import net.minecraft.world.level.levelgen.DensityFunctions; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/CacheLikeNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/CacheLikeNode.java similarity index 95% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/CacheLikeNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/CacheLikeNode.java index d9a2689..956838a 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/CacheLikeNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/CacheLikeNode.java @@ -1,13 +1,13 @@ -package org.bxteam.divinemc.dfc.common.ast.misc; +package com.ishland.c2me.opts.dfc.common.ast.misc; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context; -import org.bxteam.divinemc.dfc.common.gen.IMultiMethod; -import org.bxteam.divinemc.dfc.common.gen.ISingleMethod; -import org.bxteam.divinemc.dfc.common.gen.SubCompiledDensityFunction; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ducks.IFastCacheLike; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.Context; +import com.ishland.c2me.opts.dfc.common.gen.IMultiMethod; +import com.ishland.c2me.opts.dfc.common.gen.ISingleMethod; +import com.ishland.c2me.opts.dfc.common.gen.SubCompiledDensityFunction; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import net.minecraft.world.level.levelgen.DensityFunctions; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/ConstantNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/ConstantNode.java similarity index 87% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/ConstantNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/ConstantNode.java index 558bc3a..b21f212 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/ConstantNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/ConstantNode.java @@ -1,9 +1,9 @@ -package org.bxteam.divinemc.dfc.common.ast.misc; +package com.ishland.c2me.opts.dfc.common.ast.misc; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import java.util.Arrays; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/DelegateNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/DelegateNode.java similarity index 92% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/DelegateNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/DelegateNode.java index 050d9ff..7c05664 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/DelegateNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/DelegateNode.java @@ -1,12 +1,12 @@ -package org.bxteam.divinemc.dfc.common.ast.misc; +package com.ishland.c2me.opts.dfc.common.ast.misc; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; -import org.bxteam.divinemc.dfc.common.util.ArrayCache; -import org.bxteam.divinemc.dfc.common.vif.EachApplierVanillaInterface; -import org.bxteam.divinemc.dfc.common.vif.NoisePosVanillaInterface; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; +import com.ishland.c2me.opts.dfc.common.vif.EachApplierVanillaInterface; +import com.ishland.c2me.opts.dfc.common.vif.NoisePosVanillaInterface; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import org.objectweb.asm.Label; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/RangeChoiceNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/RangeChoiceNode.java similarity index 97% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/RangeChoiceNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/RangeChoiceNode.java index b3ce05b..b5bd4f8 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/RangeChoiceNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/RangeChoiceNode.java @@ -1,10 +1,10 @@ -package org.bxteam.divinemc.dfc.common.ast.misc; +package com.ishland.c2me.opts.dfc.common.ast.misc; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.Context; import java.util.Objects; import org.objectweb.asm.Label; import org.objectweb.asm.Type; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/RootNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/RootNode.java similarity index 90% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/RootNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/RootNode.java index 4c6001f..b053377 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/RootNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/RootNode.java @@ -1,9 +1,9 @@ -package org.bxteam.divinemc.dfc.common.ast.misc; +package com.ishland.c2me.opts.dfc.common.ast.misc; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import java.util.Objects; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/YClampedGradientNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/YClampedGradientNode.java similarity index 92% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/YClampedGradientNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/YClampedGradientNode.java index 0eb4c48..2994710 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/misc/YClampedGradientNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/misc/YClampedGradientNode.java @@ -1,9 +1,9 @@ -package org.bxteam.divinemc.dfc.common.ast.misc; +package com.ishland.c2me.opts.dfc.common.ast.misc; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import net.minecraft.util.Mth; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTNoiseNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTNoiseNode.java similarity index 94% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTNoiseNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTNoiseNode.java index 76b1899..e18bf80 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTNoiseNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTNoiseNode.java @@ -1,9 +1,9 @@ -package org.bxteam.divinemc.dfc.common.ast.noise; +package com.ishland.c2me.opts.dfc.common.ast.noise; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import org.objectweb.asm.Type; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTShiftANode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTShiftANode.java similarity index 93% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTShiftANode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTShiftANode.java index 499c09f..35c0620 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTShiftANode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTShiftANode.java @@ -1,9 +1,9 @@ -package org.bxteam.divinemc.dfc.common.ast.noise; +package com.ishland.c2me.opts.dfc.common.ast.noise; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import org.objectweb.asm.Type; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTShiftBNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTShiftBNode.java similarity index 93% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTShiftBNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTShiftBNode.java index 1611540..97d6095 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTShiftBNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTShiftBNode.java @@ -1,9 +1,9 @@ -package org.bxteam.divinemc.dfc.common.ast.noise; +package com.ishland.c2me.opts.dfc.common.ast.noise; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import org.objectweb.asm.Type; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTShiftNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTShiftNode.java similarity index 94% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTShiftNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTShiftNode.java index cff0089..2ddfe69 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTShiftNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTShiftNode.java @@ -1,9 +1,9 @@ -package org.bxteam.divinemc.dfc.common.ast.noise; +package com.ishland.c2me.opts.dfc.common.ast.noise; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import org.objectweb.asm.Type; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTWeirdScaledSamplerNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTWeirdScaledSamplerNode.java similarity index 95% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTWeirdScaledSamplerNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTWeirdScaledSamplerNode.java index 9f9c368..c14b752 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/DFTWeirdScaledSamplerNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/DFTWeirdScaledSamplerNode.java @@ -1,10 +1,10 @@ -package org.bxteam.divinemc.dfc.common.ast.noise; +package com.ishland.c2me.opts.dfc.common.ast.noise; -import org.bxteam.divinemc.dfc.common.IDensityFunctionsCaveScaler; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.IDensityFunctionsCaveScaler; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import net.minecraft.world.level.levelgen.DensityFunctions; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/ShiftedNoiseNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/ShiftedNoiseNode.java similarity index 96% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/ShiftedNoiseNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/ShiftedNoiseNode.java index 75c82a6..2659eab 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/noise/ShiftedNoiseNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/noise/ShiftedNoiseNode.java @@ -1,10 +1,10 @@ -package org.bxteam.divinemc.dfc.common.ast.noise; +package com.ishland.c2me.opts.dfc.common.ast.noise; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context; -import org.bxteam.divinemc.dfc.common.util.ArrayCache; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen.Context; +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import org.objectweb.asm.Type; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/spline/SplineAstNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/spline/SplineAstNode.java similarity index 98% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/spline/SplineAstNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/spline/SplineAstNode.java index 176b6a1..42142de 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/spline/SplineAstNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/spline/SplineAstNode.java @@ -1,11 +1,11 @@ -package org.bxteam.divinemc.dfc.common.ast.spline; +package com.ishland.c2me.opts.dfc.common.ast.spline; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.ast.McToAst; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; -import org.bxteam.divinemc.dfc.common.vif.NoisePosVanillaInterface; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ast.McToAst; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.vif.NoisePosVanillaInterface; import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.IntObjectPair; import java.util.ArrayList; @@ -16,7 +16,7 @@ import net.minecraft.util.CubicSpline; import net.minecraft.util.Mth; import net.minecraft.world.level.levelgen.DensityFunction; import net.minecraft.world.level.levelgen.DensityFunctions; -import org.bxteam.divinemc.util.Assertions; +import com.ishland.flowsched.util.Assertions; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import org.objectweb.asm.commons.AnalyzerAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/spline/SplineSupport.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/spline/SplineSupport.java similarity index 92% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/spline/SplineSupport.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/spline/SplineSupport.java index ee23110..4d0d3fd 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/spline/SplineSupport.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/spline/SplineSupport.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.dfc.common.ast.spline; +package com.ishland.c2me.opts.dfc.common.ast.spline; public class SplineSupport { public SplineSupport() { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/AbsNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/AbsNode.java similarity index 89% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/AbsNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/AbsNode.java index e3a91a5..3f2f263 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/AbsNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/AbsNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.unary; +package com.ishland.c2me.opts.dfc.common.ast.unary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/AbstractUnaryNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/AbstractUnaryNode.java similarity index 91% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/AbstractUnaryNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/AbstractUnaryNode.java index a48ca64..45efd85 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/AbstractUnaryNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/AbstractUnaryNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.unary; +package com.ishland.c2me.opts.dfc.common.ast.unary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.AstTransformer; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.AstTransformer; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import java.util.Objects; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/CubeNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/CubeNode.java similarity index 88% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/CubeNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/CubeNode.java index 8bd4d3f..bc57baf 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/CubeNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/CubeNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.unary; +package com.ishland.c2me.opts.dfc.common.ast.unary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/NegMulNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/NegMulNode.java similarity index 92% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/NegMulNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/NegMulNode.java index 4be770d..1f658f9 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/NegMulNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/NegMulNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.unary; +package com.ishland.c2me.opts.dfc.common.ast.unary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/SquareNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/SquareNode.java similarity index 87% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/SquareNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/SquareNode.java index 284ff98..7c85252 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/SquareNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/SquareNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.unary; +package com.ishland.c2me.opts.dfc.common.ast.unary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/SqueezeNode.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/SqueezeNode.java similarity index 93% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/SqueezeNode.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/SqueezeNode.java index ae7e8b1..c7db44b 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ast/unary/SqueezeNode.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ast/unary/SqueezeNode.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.ast.unary; +package com.ishland.c2me.opts.dfc.common.ast.unary; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.gen.BytecodeGen; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.gen.BytecodeGen; import net.minecraft.util.Mth; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; diff --git a/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IArrayCacheCapable.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IArrayCacheCapable.java new file mode 100644 index 0000000..15aaf8c --- /dev/null +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IArrayCacheCapable.java @@ -0,0 +1,7 @@ +package com.ishland.c2me.opts.dfc.common.ducks; + +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; + +public interface IArrayCacheCapable { + ArrayCache c2me$getArrayCache(); +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IBlendingAwareVisitor.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IBlendingAwareVisitor.java similarity index 63% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IBlendingAwareVisitor.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IBlendingAwareVisitor.java index 1454273..72959ec 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IBlendingAwareVisitor.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IBlendingAwareVisitor.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.dfc.common.ducks; +package com.ishland.c2me.opts.dfc.common.ducks; public interface IBlendingAwareVisitor { boolean c2me$isBlendingEnabled(); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/ICoordinatesFilling.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/ICoordinatesFilling.java similarity index 69% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/ICoordinatesFilling.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/ICoordinatesFilling.java index 4fa5595..ab1a3a5 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/ICoordinatesFilling.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/ICoordinatesFilling.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.dfc.common.ducks; +package com.ishland.c2me.opts.dfc.common.ducks; public interface ICoordinatesFilling { void c2me$fillCoordinates(int[] var1, int[] var2, int[] var3); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IEqualityOverriding.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IEqualityOverriding.java similarity index 72% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IEqualityOverriding.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IEqualityOverriding.java index 9236883..5c1d237 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IEqualityOverriding.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IEqualityOverriding.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.dfc.common.ducks; +package com.ishland.c2me.opts.dfc.common.ducks; public interface IEqualityOverriding { void c2me$overrideEquality(Object var1); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IFastCacheLike.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IFastCacheLike.java similarity index 85% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IFastCacheLike.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IFastCacheLike.java index 8289c85..de3c3c4 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IFastCacheLike.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/ducks/IFastCacheLike.java @@ -1,6 +1,6 @@ -package org.bxteam.divinemc.dfc.common.ducks; +package com.ishland.c2me.opts.dfc.common.ducks; -import org.bxteam.divinemc.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; import net.minecraft.world.level.levelgen.DensityFunction; public interface IFastCacheLike extends DensityFunction { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/BytecodeGen.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/BytecodeGen.java similarity index 97% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/BytecodeGen.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/BytecodeGen.java index 365ed1a..19011da 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/BytecodeGen.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/BytecodeGen.java @@ -1,14 +1,14 @@ -package org.bxteam.divinemc.dfc.common.gen; +package com.ishland.c2me.opts.dfc.common.gen; import com.google.common.io.Files; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.ast.McToAst; -import org.bxteam.divinemc.dfc.common.ast.dfvisitor.StripBlending; -import org.bxteam.divinemc.dfc.common.ast.misc.ConstantNode; -import org.bxteam.divinemc.dfc.common.ast.misc.RootNode; -import org.bxteam.divinemc.dfc.common.util.ArrayCache; -import org.bxteam.divinemc.dfc.common.vif.AstVanillaInterface; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ast.McToAst; +import com.ishland.c2me.opts.dfc.common.ast.dfvisitor.StripBlending; +import com.ishland.c2me.opts.dfc.common.ast.misc.ConstantNode; +import com.ishland.c2me.opts.dfc.common.ast.misc.RootNode; +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; +import com.ishland.c2me.opts.dfc.common.vif.AstVanillaInterface; import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.IntObjectPair; @@ -237,7 +237,7 @@ public class BytecodeGen { static { try { - org.bxteam.divinemc.util.Files.deleteRecursively(exportDir); + com.ishland.c2me.opts.dfc.util.Files.deleteRecursively(exportDir); } catch (IOException var1) { IOException e = var1; e.printStackTrace(); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/CompiledDensityFunction.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/CompiledDensityFunction.java similarity index 95% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/CompiledDensityFunction.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/CompiledDensityFunction.java index 15b6c16..dfecbb3 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/CompiledDensityFunction.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/CompiledDensityFunction.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.gen; +package com.ishland.c2me.opts.dfc.common.gen; import com.google.common.base.Suppliers; -import org.bxteam.divinemc.dfc.common.ducks.IBlendingAwareVisitor; -import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike; +import com.ishland.c2me.opts.dfc.common.ducks.IBlendingAwareVisitor; +import com.ishland.c2me.opts.dfc.common.ducks.IFastCacheLike; import java.util.List; import java.util.ListIterator; import java.util.Objects; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/CompiledEntry.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/CompiledEntry.java similarity index 68% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/CompiledEntry.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/CompiledEntry.java index 35b0867..682a348 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/CompiledEntry.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/CompiledEntry.java @@ -1,7 +1,7 @@ -package org.bxteam.divinemc.dfc.common.gen; +package com.ishland.c2me.opts.dfc.common.gen; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.util.ArrayCache; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; import java.util.List; public interface CompiledEntry extends ISingleMethod, IMultiMethod { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/DelegatingBlendingAwareVisitor.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/DelegatingBlendingAwareVisitor.java similarity index 89% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/DelegatingBlendingAwareVisitor.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/DelegatingBlendingAwareVisitor.java index 1b4ec4e..1f509b6 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/DelegatingBlendingAwareVisitor.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/DelegatingBlendingAwareVisitor.java @@ -1,6 +1,6 @@ -package org.bxteam.divinemc.dfc.common.gen; +package com.ishland.c2me.opts.dfc.common.gen; -import org.bxteam.divinemc.dfc.common.ducks.IBlendingAwareVisitor; +import com.ishland.c2me.opts.dfc.common.ducks.IBlendingAwareVisitor; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; import org.jetbrains.annotations.NotNull; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/IMultiMethod.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/IMultiMethod.java similarity index 50% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/IMultiMethod.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/IMultiMethod.java index 21b2796..a503660 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/IMultiMethod.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/IMultiMethod.java @@ -1,7 +1,7 @@ -package org.bxteam.divinemc.dfc.common.gen; +package com.ishland.c2me.opts.dfc.common.gen; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.util.ArrayCache; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; @FunctionalInterface public interface IMultiMethod { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/ISingleMethod.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/ISingleMethod.java similarity index 55% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/ISingleMethod.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/ISingleMethod.java index f946553..6f0c199 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/ISingleMethod.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/ISingleMethod.java @@ -1,6 +1,6 @@ -package org.bxteam.divinemc.dfc.common.gen; +package com.ishland.c2me.opts.dfc.common.gen; -import org.bxteam.divinemc.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; @FunctionalInterface public interface ISingleMethod { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/SubCompiledDensityFunction.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/SubCompiledDensityFunction.java similarity index 92% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/SubCompiledDensityFunction.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/SubCompiledDensityFunction.java index aec0c62..d1323ef 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/gen/SubCompiledDensityFunction.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/gen/SubCompiledDensityFunction.java @@ -1,12 +1,12 @@ -package org.bxteam.divinemc.dfc.common.gen; +package com.ishland.c2me.opts.dfc.common.gen; import com.google.common.base.Suppliers; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.ducks.IArrayCacheCapable; -import org.bxteam.divinemc.dfc.common.ducks.IBlendingAwareVisitor; -import org.bxteam.divinemc.dfc.common.ducks.ICoordinatesFilling; -import org.bxteam.divinemc.dfc.common.util.ArrayCache; -import org.bxteam.divinemc.dfc.common.vif.EachApplierVanillaInterface; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ducks.IArrayCacheCapable; +import com.ishland.c2me.opts.dfc.common.ducks.IBlendingAwareVisitor; +import com.ishland.c2me.opts.dfc.common.ducks.ICoordinatesFilling; +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; +import com.ishland.c2me.opts.dfc.common.vif.EachApplierVanillaInterface; import java.util.Objects; import java.util.function.Supplier; import net.minecraft.util.KeyDispatchDataCodec; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/util/ArrayCache.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/util/ArrayCache.java similarity index 97% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/util/ArrayCache.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/util/ArrayCache.java index a3813ca..089d6fa 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/util/ArrayCache.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/util/ArrayCache.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.dfc.common.util; +package com.ishland.c2me.opts.dfc.common.util; import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/vif/AstVanillaInterface.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/vif/AstVanillaInterface.java similarity index 91% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/vif/AstVanillaInterface.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/vif/AstVanillaInterface.java index 5b8c9ef..7c5e531 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/vif/AstVanillaInterface.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/vif/AstVanillaInterface.java @@ -1,10 +1,10 @@ -package org.bxteam.divinemc.dfc.common.vif; +package com.ishland.c2me.opts.dfc.common.vif; -import org.bxteam.divinemc.dfc.common.ast.AstNode; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.ast.misc.CacheLikeNode; -import org.bxteam.divinemc.dfc.common.ast.misc.DelegateNode; -import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike; +import com.ishland.c2me.opts.dfc.common.ast.AstNode; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ast.misc.CacheLikeNode; +import com.ishland.c2me.opts.dfc.common.ast.misc.DelegateNode; +import com.ishland.c2me.opts.dfc.common.ducks.IFastCacheLike; import java.util.Objects; import net.minecraft.util.KeyDispatchDataCodec; import net.minecraft.world.level.levelgen.DensityFunction; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/vif/EachApplierVanillaInterface.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/vif/EachApplierVanillaInterface.java similarity index 87% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/vif/EachApplierVanillaInterface.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/vif/EachApplierVanillaInterface.java index d557a82..ba0c410 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/vif/EachApplierVanillaInterface.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/vif/EachApplierVanillaInterface.java @@ -1,8 +1,8 @@ -package org.bxteam.divinemc.dfc.common.vif; +package com.ishland.c2me.opts.dfc.common.vif; -import org.bxteam.divinemc.dfc.common.ast.EvalType; -import org.bxteam.divinemc.dfc.common.ducks.IArrayCacheCapable; -import org.bxteam.divinemc.dfc.common.util.ArrayCache; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ducks.IArrayCacheCapable; +import com.ishland.c2me.opts.dfc.common.util.ArrayCache; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/vif/NoisePosVanillaInterface.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/vif/NoisePosVanillaInterface.java similarity index 87% rename from divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/vif/NoisePosVanillaInterface.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/vif/NoisePosVanillaInterface.java index 88b83cc..84584c8 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/vif/NoisePosVanillaInterface.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/common/vif/NoisePosVanillaInterface.java @@ -1,6 +1,6 @@ -package org.bxteam.divinemc.dfc.common.vif; +package com.ishland.c2me.opts.dfc.common.vif; -import org.bxteam.divinemc.dfc.common.ast.EvalType; +import com.ishland.c2me.opts.dfc.common.ast.EvalType; import java.util.Objects; import net.minecraft.world.level.levelgen.DensityFunction; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/Files.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/util/Files.java similarity index 96% rename from divinemc-server/src/main/java/org/bxteam/divinemc/util/Files.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/util/Files.java index 7d02eb2..2bb440f 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/Files.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/dfc/util/Files.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.util; +package com.ishland.c2me.opts.dfc.util; import java.io.File; import java.io.IOException; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java b/divinemc-server/src/main/java/com/ishland/c2me/opts/worldgen/general/common/random_instances/RandomUtils.java similarity index 81% rename from divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java rename to divinemc-server/src/main/java/com/ishland/c2me/opts/worldgen/general/common/random_instances/RandomUtils.java index 5f47188..a93bd0d 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java +++ b/divinemc-server/src/main/java/com/ishland/c2me/opts/worldgen/general/common/random_instances/RandomUtils.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.util; +package com.ishland.c2me.opts.worldgen.general.common.random_instances; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; @@ -7,27 +7,18 @@ import net.minecraft.world.level.levelgen.PositionalRandomFactory; import net.minecraft.world.level.levelgen.SingleThreadedRandomSource; import net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus; import net.minecraft.world.level.levelgen.XoroshiroRandomSource; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -public final class RandomUtil { - public static @NotNull RandomSource getRandom(PositionalRandomFactory deriver) { - if (deriver instanceof XoroshiroRandomSource.XoroshiroPositionalRandomFactory) { - return new XoroshiroRandomSource(0L, 0L); - } - if (deriver instanceof LegacyRandomSource.LegacyPositionalRandomFactory) { - return new SingleThreadedRandomSource(0L); - } - throw new IllegalArgumentException(); - } - +public class RandomUtils { private static final ThreadLocal xoroshiro = ThreadLocal.withInitial(() -> new XoroshiroRandomSource(0L, 0L)); private static final ThreadLocal simple = ThreadLocal.withInitial(() -> new SingleThreadedRandomSource(0L)); public static void derive(PositionalRandomFactory deriver, RandomSource random, int x, int y, int z) { - if (deriver instanceof final XoroshiroRandomSource.XoroshiroPositionalRandomFactory deriver1) { + if (deriver instanceof XoroshiroRandomSource.XoroshiroPositionalRandomFactory(long seedLo, long seedHi)) { final Xoroshiro128PlusPlus implementation = ((XoroshiroRandomSource) random).randomNumberGenerator; - implementation.seedLo = (Mth.getSeed(x, y, z) ^ deriver1.seedLo()); - implementation.seedHi = (deriver1.seedHi()); + implementation.seedLo = (Mth.getSeed(x, y, z) ^ seedLo); + implementation.seedHi = (seedHi); return; } if (deriver instanceof LegacyRandomSource.LegacyPositionalRandomFactory(long seed)) { @@ -37,4 +28,15 @@ public final class RandomUtil { } throw new IllegalArgumentException(); } + + @Contract("null -> fail") + public static @NotNull RandomSource getRandom(PositionalRandomFactory deriver) { + if (deriver instanceof XoroshiroRandomSource.XoroshiroPositionalRandomFactory) { + return new XoroshiroRandomSource(0L, 0L); + } + if (deriver instanceof LegacyRandomSource.LegacyPositionalRandomFactory) { + return new SingleThreadedRandomSource(0L); + } + throw new IllegalArgumentException(); + } } diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/Assertions.java b/divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java similarity index 95% rename from divinemc-server/src/main/java/org/bxteam/divinemc/util/Assertions.java rename to divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java index 98975c5..c3ee6c4 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/Assertions.java +++ b/divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.util; +package com.ishland.flowsched.util; public final class Assertions { public static void assertTrue(boolean value, String message) { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java b/divinemc-server/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java similarity index 92% rename from divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java rename to divinemc-server/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java index 042ffcb..c2a308a 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncProcessor.java +++ b/divinemc-server/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.util; +package gg.pufferfish.pufferfish.util; import it.unimi.dsi.fastutil.PriorityQueue; import it.unimi.dsi.fastutil.PriorityQueues; @@ -10,14 +10,14 @@ import org.bxteam.divinemc.spark.ThreadDumperRegistry; import java.util.NoSuchElementException; import java.util.concurrent.locks.LockSupport; -public class AsyncProcessor implements Runnable { - private static final Logger LOGGER = LogManager.getLogger(AsyncProcessor.class); +public class AsyncExecutor implements Runnable { + private static final Logger LOGGER = LogManager.getLogger(AsyncExecutor.class); public final Thread thread; private final PriorityQueue jobs = PriorityQueues.synchronize(new ObjectArrayFIFOQueue<>()); private volatile boolean killswitch = false; - public AsyncProcessor(String threadName) { + public AsyncExecutor(String threadName) { this.thread = Thread.ofPlatform() .name(threadName) .priority(Thread.NORM_PRIORITY - 1) diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java index 4af97d7..b182414 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java @@ -4,7 +4,6 @@ import io.papermc.paper.ServerBuildInfo; import joptsimple.OptionParser; import joptsimple.OptionSet; import net.minecraft.SharedConstants; -import net.minecraft.server.Eula; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.Main; import org.slf4j.Logger; @@ -13,11 +12,8 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; -@SuppressWarnings("DuplicatedCode") public class DivineBootstrap { private static final Logger LOGGER = LoggerFactory.getLogger("DivineBootstrap"); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/server/network/AsyncJoinHandler.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/AsyncJoinHandler.java similarity index 80% rename from divinemc-server/src/main/java/org/bxteam/divinemc/server/network/AsyncJoinHandler.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/AsyncJoinHandler.java index 9f62666..e7ddee8 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/server/network/AsyncJoinHandler.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/AsyncJoinHandler.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.server.network; +package org.bxteam.divinemc.async; import com.google.common.util.concurrent.ThreadFactoryBuilder; import net.minecraft.server.MinecraftServer; @@ -19,14 +19,9 @@ public class AsyncJoinHandler { public static ExecutorService JOIN_EXECUTOR; private static boolean enabled = false; - private static int threadCount = 2; - /** - * Initialize the AsyncJoinHandler with configuration settings - */ public static void init(boolean enabled, int threadCount) { AsyncJoinHandler.enabled = enabled; - AsyncJoinHandler.threadCount = Math.max(1, threadCount); if (enabled) { if (JOIN_EXECUTOR != null) { @@ -50,13 +45,6 @@ public class AsyncJoinHandler { } } - /** - * Execute a potentially blocking task asynchronously - * - * @param task The task to run asynchronously - * @param callback The callback to execute on the main thread when the task completes - * @param The return type of the task - */ public static void runAsync(Supplier task, java.util.function.Consumer callback) { if (!enabled || JOIN_EXECUTOR == null) { T result = task.get(); @@ -74,11 +62,6 @@ public class AsyncJoinHandler { }); } - /** - * Execute a potentially blocking task asynchronously without a result - * - * @param asyncTask The task to run asynchronously - */ public static void runAsync(Runnable asyncTask) { if (!enabled || JOIN_EXECUTOR == null) { asyncTask.run(); @@ -93,9 +76,6 @@ public class AsyncJoinHandler { }); } - /** - * Get the executor service for async join operations - */ public static Executor getExecutor() { return enabled && JOIN_EXECUTOR != null ? JOIN_EXECUTOR : Runnable::run; } diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/AsyncPath.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/AsyncPath.java similarity index 99% rename from divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/AsyncPath.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/AsyncPath.java index 81b7b27..56072f3 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/AsyncPath.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/AsyncPath.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.entity.pathfinding; +package org.bxteam.divinemc.async.pathfinding; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.Entity; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/AsyncPathProcessor.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/AsyncPathProcessor.java similarity index 98% rename from divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/AsyncPathProcessor.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/AsyncPathProcessor.java index fb793a0..938182f 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/AsyncPathProcessor.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/AsyncPathProcessor.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.entity.pathfinding; +package org.bxteam.divinemc.async.pathfinding; import ca.spottedleaf.moonrise.common.util.TickThread; import net.minecraft.server.MinecraftServer; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorCache.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorCache.java similarity index 97% rename from divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorCache.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorCache.java index cdd7344..12ef7e2 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorCache.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorCache.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.entity.pathfinding; +package org.bxteam.divinemc.async.pathfinding; import net.minecraft.world.level.pathfinder.NodeEvaluator; import org.apache.commons.lang3.Validate; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorFeatures.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorFeatures.java similarity index 95% rename from divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorFeatures.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorFeatures.java index 1f0f1a3..8965627 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorFeatures.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorFeatures.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.entity.pathfinding; +package org.bxteam.divinemc.async.pathfinding; import net.minecraft.world.level.pathfinder.NodeEvaluator; import net.minecraft.world.level.pathfinder.SwimNodeEvaluator; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorGenerator.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorGenerator.java similarity index 82% rename from divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorGenerator.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorGenerator.java index 0fa93c7..1466ca4 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorGenerator.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorGenerator.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.entity.pathfinding; +package org.bxteam.divinemc.async.pathfinding; import net.minecraft.world.level.pathfinder.NodeEvaluator; import org.jetbrains.annotations.NotNull; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorType.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorType.java similarity index 90% rename from divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorType.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorType.java index c9f3d8e..62889b3 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/NodeEvaluatorType.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/NodeEvaluatorType.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.entity.pathfinding; +package org.bxteam.divinemc.async.pathfinding; import net.minecraft.world.level.pathfinder.*; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/PathProcessState.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/PathProcessState.java similarity index 61% rename from divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/PathProcessState.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/PathProcessState.java index 9211740..5075af6 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/PathProcessState.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/PathProcessState.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.entity.pathfinding; +package org.bxteam.divinemc.async.pathfinding; public enum PathProcessState { WAITING, diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/PathfindTaskRejectPolicy.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/PathfindTaskRejectPolicy.java similarity index 91% rename from divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/PathfindTaskRejectPolicy.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/PathfindTaskRejectPolicy.java index 36886ea..84bd64a 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/pathfinding/PathfindTaskRejectPolicy.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/pathfinding/PathfindTaskRejectPolicy.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.entity.pathfinding; +package org.bxteam.divinemc.async.pathfinding; import org.bxteam.divinemc.config.DivineConfig; import java.util.Locale; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/tracking/MultithreadedTracker.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/tracking/MultithreadedTracker.java similarity index 99% rename from divinemc-server/src/main/java/org/bxteam/divinemc/entity/tracking/MultithreadedTracker.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/tracking/MultithreadedTracker.java index 038ebdf..e117753 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/entity/tracking/MultithreadedTracker.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/tracking/MultithreadedTracker.java @@ -1,4 +1,4 @@ -package org.bxteam.divinemc.entity.tracking; +package org.bxteam.divinemc.async.tracking; import ca.spottedleaf.moonrise.common.list.ReferenceList; import ca.spottedleaf.moonrise.common.misc.NearbyPlayers; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/world/ServerLevelTickThreadFactory.java similarity index 80% rename from divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/world/ServerLevelTickThreadFactory.java index d7d2785..328109d 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/server/ServerLevelTickExecutorThreadFactory.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/world/ServerLevelTickThreadFactory.java @@ -1,13 +1,14 @@ -package org.bxteam.divinemc.server; +package org.bxteam.divinemc.async.world; import ca.spottedleaf.moonrise.common.util.TickThread; import org.bxteam.divinemc.spark.ThreadDumperRegistry; + import java.util.concurrent.ThreadFactory; -public class ServerLevelTickExecutorThreadFactory implements ThreadFactory { +public class ServerLevelTickThreadFactory implements ThreadFactory { private final String worldName; - public ServerLevelTickExecutorThreadFactory(String worldName) { + public ServerLevelTickThreadFactory(String worldName) { this.worldName = worldName; ThreadDumperRegistry.REGISTRY.add(worldName + " - ServerLevel Tick Worker"); } diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/async/world/TeleportState.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/world/TeleportState.java new file mode 100644 index 0000000..83b0c6c --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/world/TeleportState.java @@ -0,0 +1,7 @@ +package org.bxteam.divinemc.async.world; + +public enum TeleportState { + INACTIVE, + PENDING, + CANCELLED +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 70cbcc0..42077c2 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -10,10 +10,10 @@ import org.apache.logging.log4j.Logger; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; import org.bxteam.divinemc.config.annotations.Experimental; -import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy; +import org.bxteam.divinemc.async.pathfinding.PathfindTaskRejectPolicy; import org.bxteam.divinemc.region.EnumRegionFileExtension; import org.bxteam.divinemc.region.type.LinearRegionFile; -import org.bxteam.divinemc.server.network.AsyncJoinHandler; +import org.bxteam.divinemc.async.AsyncJoinHandler; import org.jetbrains.annotations.Nullable; import org.simpleyaml.configuration.comments.CommentType; import org.simpleyaml.configuration.file.YamlFile; diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IArrayCacheCapable.java b/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IArrayCacheCapable.java deleted file mode 100644 index 2afddfa..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/dfc/common/ducks/IArrayCacheCapable.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.bxteam.divinemc.dfc.common.ducks; - -import org.bxteam.divinemc.dfc.common.util.ArrayCache; - -public interface IArrayCacheCapable { - ArrayCache c2me$getArrayCache(); -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java index c0296b8..e8ae0fc 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java @@ -3,9 +3,9 @@ package org.bxteam.divinemc.util; import net.minecraft.server.MinecraftServer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.bxteam.divinemc.entity.pathfinding.AsyncPathProcessor; -import org.bxteam.divinemc.entity.tracking.MultithreadedTracker; -import org.bxteam.divinemc.server.network.AsyncJoinHandler; +import org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor; +import org.bxteam.divinemc.async.tracking.MultithreadedTracker; +import org.bxteam.divinemc.async.AsyncJoinHandler; import java.util.concurrent.TimeUnit; @SuppressWarnings("ConstantValue") diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/PWTTeleportState.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/PWTTeleportState.java deleted file mode 100644 index 21b3c37..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/PWTTeleportState.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.bxteam.divinemc.util; - -public enum PWTTeleportState { - INACTIVE, - PENDING, - CANCELLED -} From dbea76a0d70ba4af9b8f49966f15e1f7c94c72a8 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 17 Jul 2025 21:02:58 +0300 Subject: [PATCH 51/67] The End Biome Cache --- .../0078-C2ME-The-End-Biome-Cache.patch | 54 +++++++++++++++++++ .../bxteam/divinemc/config/DivineConfig.java | 15 ++++-- 2 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 divinemc-server/minecraft-patches/features/0078-C2ME-The-End-Biome-Cache.patch diff --git a/divinemc-server/minecraft-patches/features/0078-C2ME-The-End-Biome-Cache.patch b/divinemc-server/minecraft-patches/features/0078-C2ME-The-End-Biome-Cache.patch new file mode 100644 index 0000000..da790b7 --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0078-C2ME-The-End-Biome-Cache.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Thu, 17 Jul 2025 20:53:13 +0300 +Subject: [PATCH] C2ME: The End Biome Cache + +This patch is based on the following mixins: +* "com/ishland/c2me/opts/worldgen/vanilla/mixin/the_end_biome_cache/MixinTheEndBiomeSource.java" +By: ishland +As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric) +Licensed under: MIT (https://opensource.org/licenses/MIT) + +diff --git a/net/minecraft/world/level/biome/TheEndBiomeSource.java b/net/minecraft/world/level/biome/TheEndBiomeSource.java +index cf3172be76fa4c7987ed569138439ff42f92fa7f..0545a0dd25917d75b511d507dc19a5ca7d45b9d9 100644 +--- a/net/minecraft/world/level/biome/TheEndBiomeSource.java ++++ b/net/minecraft/world/level/biome/TheEndBiomeSource.java +@@ -55,8 +55,37 @@ public class TheEndBiomeSource extends BiomeSource { + return CODEC; + } + ++ // DivineMC start - C2ME: The End Biome Cache ++ private final ThreadLocal>> cache = ThreadLocal.withInitial(it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap::new); ++ private final int cacheCapacity = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.endBiomeCacheCapacity; ++ + @Override +- public Holder getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) { ++ public Holder getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler multiNoiseSampler) { ++ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.endBiomeCacheEnabled) { ++ return getVanillaNoiseBiome(biomeX, biomeY, biomeZ, multiNoiseSampler); ++ } ++ ++ final long key = net.minecraft.world.level.ChunkPos.asLong(biomeX, biomeZ); ++ final it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap> cacheThreadLocal = cache.get(); ++ final Holder biome = cacheThreadLocal.get(key); ++ ++ if (biome != null) { ++ return biome; ++ } else { ++ final Holder gennedBiome = getVanillaNoiseBiome(biomeX, biomeY, biomeZ, multiNoiseSampler); ++ cacheThreadLocal.put(key, gennedBiome); ++ if (cacheThreadLocal.size() > cacheCapacity) { ++ for (int i = 0; i < cacheCapacity / 16; i ++) { ++ cacheThreadLocal.removeFirst(); ++ } ++ } ++ ++ return gennedBiome; ++ } ++ } ++ // DivineMC end - C2ME: The End Biome Cache ++ ++ private Holder getVanillaNoiseBiome(int x, int y, int z, Climate.Sampler sampler) { // DivineMC - C2ME: The End Biome Cache + int blockPosX = QuartPos.toBlock(x); + int blockPosY = QuartPos.toBlock(y); + int blockPosZ = QuartPos.toBlock(z); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 42077c2..d60289b 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -372,6 +372,8 @@ public class DivineConfig { public static long chunkDataCacheLimit = 32678L; public static int maxViewDistance = 32; public static int playerNearChunkDetectionRange = 128; + public static boolean endBiomeCacheEnabled = false; + public static int endBiomeCacheCapacity = 1024; public static boolean smoothBedrockLayer = false; public static boolean enableDensityFunctionCompiler = false; public static boolean enableStructureLayoutOptimizer = true; @@ -428,10 +430,10 @@ public class DivineConfig { "By default, this range is computed to 8, meaning a player must be within an 8 chunk radius of a chunk position to pass.", "Keep in mind the result is rounded to the nearest whole number."); - if (playerNearChunkDetectionRange < 0) { - LOGGER.warn("Invalid player near chunk detection range: {}, resetting to default (128)", playerNearChunkDetectionRange); - playerNearChunkDetectionRange = 128; - } + endBiomeCacheEnabled = getBoolean(ConfigCategory.PERFORMANCE.key("chunks.end-biome-cache-enabled"), endBiomeCacheEnabled, + "Enables the end biome cache, which can accelerate The End worldgen."); + endBiomeCacheCapacity = getInt(ConfigCategory.PERFORMANCE.key("chunks.end-biome-cache-capacity"), endBiomeCacheCapacity, + "The cache capacity for the end biome cache. Only used if end-biome-cache-enabled is true."); smoothBedrockLayer = getBoolean(ConfigCategory.PERFORMANCE.key("chunks.smooth-bedrock-layer"), smoothBedrockLayer, "Smoothens the bedrock layer at the bottom of overworld, and on the top of nether during the world generation."); @@ -455,6 +457,11 @@ public class DivineConfig { "This will not break the structure generation, but it will make the structure layout different than", "if this config was off (breaking vanilla seed parity). The cost of speed may be worth it in large", "modpacks where many structure mods are using very high weight values in their template pools."); + + if (playerNearChunkDetectionRange < 0) { + LOGGER.warn("Invalid player near chunk detection range: {}, resetting to default (128)", playerNearChunkDetectionRange); + playerNearChunkDetectionRange = 128; + } } private static void optimizationSettings() { From 64b482491e740e6c2e04ef85a00aa724f3ab9536 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Thu, 17 Jul 2025 21:16:22 +0300 Subject: [PATCH 52/67] configurable f3 name --- .../minecraft-patches/features/0001-Rebrand.patch | 13 +++++++++++++ .../0001-Update-Purpur-rebrand-settings.patch | 9 ++++++--- .../0002-Add-missing-purpur-config-options.patch | 6 +++--- .../0003-Optimize-default-values-for-configs.patch | 4 ++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index c76532c..72a601d 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -17,6 +17,19 @@ index 394443d00e661715439be1e56dddc129947699a4..480ad57a6b7b74e6b83e9c6ceb69ea1f public CrashReport(String title, Throwable exception) { io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper +diff --git a/net/minecraft/network/protocol/common/custom/BrandPayload.java b/net/minecraft/network/protocol/common/custom/BrandPayload.java +index 97844ec1ccc986eb3d3a185d78a03ceeca49fc1a..5e40ec3fbe6e6d5f98ad98df7d4c27d6de615778 100644 +--- a/net/minecraft/network/protocol/common/custom/BrandPayload.java ++++ b/net/minecraft/network/protocol/common/custom/BrandPayload.java +@@ -12,7 +12,7 @@ public record BrandPayload(String brand) implements CustomPacketPayload { + } + + private void write(FriendlyByteBuf buffer) { +- buffer.writeUtf(this.brand); ++ buffer.writeUtf(org.purpurmc.purpur.PurpurConfig.f3Name + "§r"); // DivineMC - Update Purpur rebrand settings + } + + @Override diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..a058ef4d74da29372a894c8a4d619b2d5ba0c74f 100644 --- a/net/minecraft/server/Main.java diff --git a/divinemc-server/purpur-patches/features/0001-Update-Purpur-rebrand-settings.patch b/divinemc-server/purpur-patches/features/0001-Update-Purpur-rebrand-settings.patch index fa36843..dacb4da 100644 --- a/divinemc-server/purpur-patches/features/0001-Update-Purpur-rebrand-settings.patch +++ b/divinemc-server/purpur-patches/features/0001-Update-Purpur-rebrand-settings.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Update Purpur rebrand settings diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 31bf765d2dfa75d854f7f8e55bab7792ace843ab..d923efc61592c430e3945fd9c38e558f9e85710e 100644 +index 31bf765d2dfa75d854f7f8e55bab7792ace843ab..e5244941506e99a8a2450e798483fed6fc328b85 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -230,10 +230,14 @@ public class PurpurConfig { +@@ -230,10 +230,16 @@ public class PurpurConfig { deathMessageOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.death.only-broadcast-to-affected-player", deathMessageOnlyBroadcastToAffectedPlayer); } @@ -16,11 +16,14 @@ index 31bf765d2dfa75d854f7f8e55bab7792ace843ab..d923efc61592c430e3945fd9c38e558f public static String serverModName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); - private static void serverModName() { - serverModName = getString("settings.server-mod-name", serverModName); +- } + public static String serverGUIName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName() + " Console"; ++ public static String f3Name = io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); + private static void serverName() { + serverModName = getString("settings.rebrand.server-mod-name", serverModName); + serverGUIName = getString("settings.rebrand.server-gui-name", serverGUIName); - } ++ f3Name = getString("settings.rebrand.f3-name", f3Name); ++ } + // DivineMC end - Update Purpur rebrand settings public static double laggingThreshold = 19.0D; diff --git a/divinemc-server/purpur-patches/features/0002-Add-missing-purpur-config-options.patch b/divinemc-server/purpur-patches/features/0002-Add-missing-purpur-config-options.patch index 000e5d5..555a786 100644 --- a/divinemc-server/purpur-patches/features/0002-Add-missing-purpur-config-options.patch +++ b/divinemc-server/purpur-patches/features/0002-Add-missing-purpur-config-options.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add missing purpur config options diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index d923efc61592c430e3945fd9c38e558f9e85710e..01094a003a96118bdc1fdc7a665cce89a2f54dfb 100644 +index e5244941506e99a8a2450e798483fed6fc328b85..657776f124e761fd2017cd43c73cd94a4abb20e6 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -331,6 +331,7 @@ public class PurpurConfig { +@@ -333,6 +333,7 @@ public class PurpurConfig { } public static int barrelRows = 3; @@ -16,7 +16,7 @@ index d923efc61592c430e3945fd9c38e558f9e85710e..01094a003a96118bdc1fdc7a665cce89 public static boolean enderChestSixRows = false; public static boolean enderChestPermissionRows = false; public static boolean cryingObsidianValidForPortalFrame = false; -@@ -374,6 +375,7 @@ public class PurpurConfig { +@@ -376,6 +377,7 @@ public class PurpurConfig { case 1 -> 9; default -> 27; }); diff --git a/divinemc-server/purpur-patches/features/0003-Optimize-default-values-for-configs.patch b/divinemc-server/purpur-patches/features/0003-Optimize-default-values-for-configs.patch index cd991c3..8224a62 100644 --- a/divinemc-server/purpur-patches/features/0003-Optimize-default-values-for-configs.patch +++ b/divinemc-server/purpur-patches/features/0003-Optimize-default-values-for-configs.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimize default values for configs diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 01094a003a96118bdc1fdc7a665cce89a2f54dfb..34edbde5707326ac6e364a24c9640ac1263c85b0 100644 +index 657776f124e761fd2017cd43c73cd94a4abb20e6..6e0174abe76c43a2114cc36e2a3b865b5dbf8cce 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -244,7 +244,7 @@ public class PurpurConfig { +@@ -246,7 +246,7 @@ public class PurpurConfig { laggingThreshold = getDouble("settings.lagging-threshold", laggingThreshold); } From 29c5aa45f4b8c841a31ff9a0e060df1f697ae844 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 18 Jul 2025 12:25:47 +0300 Subject: [PATCH 53/67] review --- .../features/0026-Optimize-entity-brain.patch | 59 ++++++++++++++----- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/divinemc-server/minecraft-patches/features/0026-Optimize-entity-brain.patch b/divinemc-server/minecraft-patches/features/0026-Optimize-entity-brain.patch index 44089cc..a46a021 100644 --- a/divinemc-server/minecraft-patches/features/0026-Optimize-entity-brain.patch +++ b/divinemc-server/minecraft-patches/features/0026-Optimize-entity-brain.patch @@ -26,23 +26,23 @@ index 04875840085541ebfc7014868beec49bb7ab9976..bbfb1de1a03c4208406feb803a2f378d super.onSyncedDataUpdated(key); diff --git a/net/minecraft/world/entity/ai/Brain.java b/net/minecraft/world/entity/ai/Brain.java -index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d5068096603b03980 100644 +index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..9277b5da6065a5500e40727815083da25b9c9327 100644 --- a/net/minecraft/world/entity/ai/Brain.java +++ b/net/minecraft/world/entity/ai/Brain.java -@@ -45,16 +45,74 @@ public class Brain { +@@ -45,16 +45,75 @@ public class Brain { static final Logger LOGGER = LogUtils.getLogger(); private final Supplier>> codec; private static final int SCHEDULE_UPDATE_DELAY = 20; - private final Map, Optional>> memories = Maps.newHashMap(); - public final Map>, Sensor> sensors = Maps.newLinkedHashMap(); -- private final Map>>> availableBehaviorsByPriority = Maps.newTreeMap(); -+ -+ private Map, Optional>> memories = Maps.newConcurrentMap(); // DivineMC - concurrent map -+ public Map>, Sensor> sensors = Maps.newLinkedHashMap(); // DivineMC - linked hash map -+ private final Map>>> availableBehaviorsByPriority = Maps.newTreeMap(); // DivineMC - tree map ++ // DivineMC start - Optimize entity brain ++ private Map, Optional>> memories = Maps.newConcurrentMap(); ++ public Map>, Sensor> sensors = Maps.newLinkedHashMap(); + private final Map>>> availableBehaviorsByPriority = Maps.newTreeMap(); private Schedule schedule = Schedule.EMPTY; - private final Map, MemoryStatus>>> activityRequirements = Maps.newHashMap(); -+ private Map, MemoryStatus>>> activityRequirements = Maps.newHashMap(); // DivineMC - hash map ++ private Map, MemoryStatus>>> activityRequirements = Maps.newHashMap(); ++ // DivineMC end - Optimize entity brain private final Map>> activityMemoriesToEraseWhenStopped = Maps.newHashMap(); private Set coreActivities = Sets.newHashSet(); private final Set activeActivities = Sets.newHashSet(); @@ -108,7 +108,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d50680966 public static Brain.Provider provider( Collection> memoryTypes, Collection>> sensorTypes -@@ -146,6 +204,12 @@ public class Brain { +@@ -146,6 +205,12 @@ public class Brain { for (Brain.MemoryValue memoryValue : memoryValues) { memoryValue.setMemoryInternal(this); } @@ -121,7 +121,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d50680966 } public DataResult serializeStart(DynamicOps ops) { -@@ -165,6 +229,7 @@ public class Brain { +@@ -165,6 +230,7 @@ public class Brain { } public void eraseMemory(MemoryModuleType type) { @@ -129,7 +129,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d50680966 this.setMemory(type, Optional.empty()); } -@@ -180,16 +245,33 @@ public class Brain { +@@ -180,16 +246,33 @@ public class Brain { this.setMemoryInternal(memoryType, memory.map(ExpirableValue::of)); } @@ -168,7 +168,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d50680966 public Optional getMemory(MemoryModuleType type) { Optional> optional = this.memories.get(type); if (optional == null) { -@@ -251,19 +333,7 @@ public class Brain { +@@ -251,19 +334,7 @@ public class Brain { @Deprecated @VisibleForDebug public List> getRunningBehaviors() { @@ -189,7 +189,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d50680966 } public void useDefaultActivity() { -@@ -294,6 +364,7 @@ public class Brain { +@@ -294,6 +365,7 @@ public class Brain { this.activeActivities.clear(); this.activeActivities.addAll(this.coreActivities); this.activeActivities.add(activity); @@ -197,7 +197,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d50680966 } } -@@ -383,11 +454,13 @@ public class Brain { +@@ -383,11 +455,13 @@ public class Brain { .computeIfAbsent(activity, activity1 -> Sets.newLinkedHashSet()) .add((BehaviorControl)pair.getSecond()); } @@ -211,7 +211,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d50680966 } public boolean isActive(Activity activity) { -@@ -404,6 +477,7 @@ public class Brain { +@@ -404,6 +478,7 @@ public class Brain { } } @@ -219,7 +219,7 @@ index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..56b8a46a9e9e99829c28a11d50680966 return brain; } -@@ -438,31 +512,38 @@ public class Brain { +@@ -438,31 +513,38 @@ public class Brain { for (BehaviorControl behaviorControl : this.getRunningBehaviors()) { behaviorControl.doStop(level, owner, gameTime); @@ -421,3 +421,30 @@ index 70b32e0d06f9b8b7999df5fdfd773c09394e23fb..997cff138d5c99b1be9224cb3c96bdfe } public ItemStack createHorn() { +diff --git a/net/minecraft/world/entity/schedule/Activity.java b/net/minecraft/world/entity/schedule/Activity.java +index 5a143bb6fabba3dc4e2272afb0be636d5722ea22..f17cc8135121f1a97f13bf83a0205e7fcb08b431 100644 +--- a/net/minecraft/world/entity/schedule/Activity.java ++++ b/net/minecraft/world/entity/schedule/Activity.java +@@ -32,10 +32,12 @@ public class Activity { + public static final Activity DIG = register("dig"); + private final String name; + private final int hashCode; ++ public final int id; // DivineMC - Cache registry ID + +- private Activity(String name) { ++ private Activity(String name, int id) { + this.name = name; + this.hashCode = name.hashCode(); ++ this.id = id; // DivineMC - Cache registry ID + } + + public String getName() { +@@ -43,7 +45,7 @@ public class Activity { + } + + private static Activity register(String key) { +- return Registry.register(BuiltInRegistries.ACTIVITY, key, new Activity(key)); ++ return Registry.register(BuiltInRegistries.ACTIVITY, key, new Activity(key, BuiltInRegistries.ACTIVITY.size())); // DivineMC - Cache registry ID + } + + @Override From aaf399b06cf199dc1bca837d45cf303586570404 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 18 Jul 2025 12:44:13 +0300 Subject: [PATCH 54/67] remove commented out lines; update start classes --- divinemc-server/build.gradle.kts.patch | 12 +++++- .../features/0001-Rebrand.patch | 41 ++++++++++++++++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/divinemc-server/build.gradle.kts.patch b/divinemc-server/build.gradle.kts.patch index 8658595..d3df812 100644 --- a/divinemc-server/build.gradle.kts.patch +++ b/divinemc-server/build.gradle.kts.patch @@ -185,8 +185,9 @@ val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim() + val experimental = rootProject.providers.gradleProperty("experimental").get() // DivineMC - Experimental flag attributes( - "Main-Class" to "org.bukkit.craftbukkit.Main", +- "Main-Class" to "org.bukkit.craftbukkit.Main", - "Implementation-Title" to "Purpur", // Purpur ++ "Main-Class" to "net.minecraft.server.Main", // DivineMC - Rebrand + "Implementation-Title" to "DivineMC", // DivineMC - Rebrand "Implementation-Version" to implementationVersion, "Implementation-Vendor" to date, @@ -207,3 +208,12 @@ ) for (tld in setOf("net", "com", "org")) { attributes("$tld/bukkit", "Sealed" to true) +@@ -333,7 +_,7 @@ + block: JavaExec.() -> Unit + ): TaskProvider = register(name) { + group = "runs" +- mainClass.set("org.bukkit.craftbukkit.Main") ++ mainClass.set("net.minecraft.server.Main") // DivineMC - Rebrand + standardInput = System.`in` + workingDir = rootProject.layout.projectDirectory + .dir(providers.gradleProperty("paper.runWorkDir").getOrElse("run")) diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index 72a601d..8e42e91 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -31,10 +31,10 @@ index 97844ec1ccc986eb3d3a185d78a03ceeca49fc1a..5e40ec3fbe6e6d5f98ad98df7d4c27d6 @Override diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java -index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..a058ef4d74da29372a894c8a4d619b2d5ba0c74f 100644 +index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..c3ac5ba5d8084fefc0e9f58b09b521ef516126eb 100644 --- a/net/minecraft/server/Main.java +++ b/net/minecraft/server/Main.java -@@ -64,11 +64,34 @@ import org.slf4j.Logger; +@@ -64,41 +64,39 @@ import org.slf4j.Logger; public class Main { private static final Logger LOGGER = LogUtils.getLogger(); @@ -66,10 +66,41 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..a058ef4d74da29372a894c8a4d619b2d + LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info."); + return; + } ++ io.papermc.paper.util.LogManagerShutdownThread.hook(); // Paper - Improved watchdog support SharedConstants.tryDetectVersion(); - /* CraftBukkit start - Replace everything -@@ -124,8 +147,6 @@ public class Main { +- /* CraftBukkit start - Replace everything +- OptionParser optionParser = new OptionParser(); +- OptionSpec optionSpec = optionParser.accepts("nogui"); +- OptionSpec optionSpec1 = optionParser.accepts("initSettings", "Initializes 'server.properties' and 'eula.txt', then quits"); +- OptionSpec optionSpec2 = optionParser.accepts("demo"); +- OptionSpec optionSpec3 = optionParser.accepts("bonusChest"); +- OptionSpec optionSpec4 = optionParser.accepts("forceUpgrade"); +- OptionSpec optionSpec5 = optionParser.accepts("eraseCache"); +- OptionSpec optionSpec6 = optionParser.accepts("recreateRegionFiles"); +- OptionSpec optionSpec7 = optionParser.accepts("safeMode", "Loads level with vanilla datapack only"); +- OptionSpec optionSpec8 = optionParser.accepts("help").forHelp(); +- OptionSpec optionSpec9 = optionParser.accepts("universe").withRequiredArg().defaultsTo("."); +- OptionSpec optionSpec10 = optionParser.accepts("world").withRequiredArg(); +- OptionSpec optionSpec11 = optionParser.accepts("port").withRequiredArg().ofType(Integer.class).defaultsTo(-1); +- OptionSpec optionSpec12 = optionParser.accepts("serverId").withRequiredArg(); +- OptionSpec optionSpec13 = optionParser.accepts("jfrProfile"); +- OptionSpec optionSpec14 = optionParser.accepts("pidFile").withRequiredArg().withValuesConvertedBy(new PathConverter()); +- OptionSpec optionSpec15 = optionParser.nonOptions(); + + try { +- OptionSet optionSet = optionParser.parse(args); +- if (optionSet.has(optionSpec8)) { +- optionParser.printHelpOn(System.err); +- return; +- } +- */ // CraftBukkit end +- try { +- + Path path = (Path) optionSet.valueOf("pidFile"); // CraftBukkit + if (path != null) { + writePidFile(path); +@@ -124,8 +122,6 @@ public class Main { DedicatedServerSettings dedicatedServerSettings = new DedicatedServerSettings(optionSet); // CraftBukkit - CLI argument support dedicatedServerSettings.forceSave(); RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression); @@ -78,7 +109,7 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..a058ef4d74da29372a894c8a4d619b2d // Paper start - load config files early for access below if needed 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")); -@@ -148,19 +169,6 @@ public class Main { +@@ -148,19 +144,6 @@ public class Main { return; } From 695e93a2f23dcff2aff025c00ab67d62794ad0a3 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:26:25 +0300 Subject: [PATCH 55/67] update async chunk sending --- .../features/0051-Async-Chunk-Sending.patch | 240 ++++++++++++------ .../0057-Petal-Multithreaded-Tracker.patch | 4 +- .../server/MinecraftServer.java.patch | 2 +- .../bxteam/divinemc/async/AsyncChunkSend.java | 24 ++ .../{util => async}/ExecutorShutdown.java | 13 +- .../util/NamedAgnosticThreadFactory.java | 5 +- 6 files changed, 210 insertions(+), 78 deletions(-) create mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/async/AsyncChunkSend.java rename divinemc-server/src/main/java/org/bxteam/divinemc/{util => async}/ExecutorShutdown.java (84%) diff --git a/divinemc-server/minecraft-patches/features/0051-Async-Chunk-Sending.patch b/divinemc-server/minecraft-patches/features/0051-Async-Chunk-Sending.patch index d7d8233..bc9b3c6 100644 --- a/divinemc-server/minecraft-patches/features/0051-Async-Chunk-Sending.patch +++ b/divinemc-server/minecraft-patches/features/0051-Async-Chunk-Sending.patch @@ -5,83 +5,181 @@ Subject: [PATCH] Async Chunk Sending diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -index 1ed2ae41e47b2446bf1835efc8bad369408d52da..053da602eb08b5a8b7a316e56f76a99e86149483 100644 +index 1ed2ae41e47b2446bf1835efc8bad369408d52da..c4a1e3908cf8e1b0614ff6c3a0f5f6708a7667e5 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -@@ -54,6 +54,8 @@ public final class RegionizedPlayerChunkLoader { - public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY); - public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL; - -+ private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger("RegionizedPlayerChunkLoader"); // DivineMC - Async Chunk Sending -+ - public static void setUnloadDelay(final long ticks) { - ((ChunkSystemTicketType)(Object)PLAYER_TICKET_DELAYED).moonrise$setTimeout(Math.max(1, ticks)); - } -@@ -415,17 +417,61 @@ public final class RegionizedPlayerChunkLoader { - } - - private void sendChunk(final int chunkX, final int chunkZ) { -- if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -- ((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager -- .getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$addReceivedChunk(this.player); +@@ -441,7 +441,13 @@ public final class RegionizedPlayerChunkLoader { + // Note: drop isAlive() check so that chunks properly unload client-side when the player dies + ((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager + .getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$removeReceivedChunk(this.player); +- this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ))); + // DivineMC start - Async Chunk Sending -+ final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ); -+ -+ if (!this.sentChunks.add(chunkKey)) return; - -- final LevelChunk chunk = ((ChunkSystemLevel)this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ); -+ final LevelChunk chunk = ((ChunkSystemLevel) this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ); -+ if (chunk == null) { -+ this.sentChunks.remove(chunkKey); -+ return; -+ } - -+ try { -+ ((ChunkSystemServerLevel) this.world).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkX, chunkZ).vanillaChunkHolder.moonrise$addReceivedChunk(this.player); - PlatformHooks.get().onChunkWatch(this.world, chunk, this.player); -- PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk); -+ } catch (IllegalStateException e) { -+ this.sentChunks.remove(chunkKey); - return; - } -- throw new IllegalStateException(); -+ + if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncChunkSendingEnabled) { -+ net.minecraft.Util.backgroundExecutor().execute(() -> { -+ try { -+ // Modified from PlayerChunkSender#sendChunk -+ final net.minecraft.server.network.ServerGamePacketListenerImpl connection = this.player.connection; -+ final ServerLevel serverLevel = this.world; -+ -+ final net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket packet = new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket( -+ chunk, serverLevel.getLightEngine(), null, null, -+ serverLevel.chunkPacketBlockController.shouldModify(this.player, chunk) -+ ); -+ -+ serverLevel.getServer().execute(() -> { -+ if (this.removed || !this.sentChunks.contains(chunkKey)) return; -+ -+ connection.send(packet); -+ -+ if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ new io.papermc.paper.event.packet.PlayerChunkLoadEvent( -+ new org.bukkit.craftbukkit.CraftChunk(chunk), -+ this.player.getBukkitEntity() -+ ).callEvent(); -+ } -+ -+ net.minecraft.network.protocol.game.DebugPackets.sendPoiPacketsForChunk(serverLevel, chunk.getPos()); -+ }); -+ } catch (Exception e) { -+ LOGGER.error("Failed to send chunk asynchronously!", e); -+ -+ if (!this.removed) this.sentChunks.remove(chunkKey); -+ } -+ }); ++ org.bxteam.divinemc.async.AsyncChunkSend.POOL.execute(() -> this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)))); + } else { -+ PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk); ++ this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ))); + } + // DivineMC end - Async Chunk Sending + // Paper start - PlayerChunkUnloadEvent + if (io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0) { + new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(new ChunkPos(chunkX, chunkZ).longKey), player.getBukkitEntity()).callEvent(); +diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java +index 9f6d7c5dc0e591488a8a3763d8a1f1b3671d5299..4983a34e42ef972f2d5ad8a12dfad99ca88d7032 100644 +--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java ++++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java +@@ -75,6 +75,52 @@ public class ClientboundLevelChunkPacketData { + } + } + ++ // DivineMC start - Async Chunk Sending ++ public ClientboundLevelChunkPacketData(LevelChunk levelChunk, io.papermc.paper.antixray.ChunkPacketInfo chunkPacketInfo, BlockEntity[] blockEntities, Map heightmaps) { ++ this.heightmaps = heightmaps; ++ ++ if (Thread.currentThread() instanceof org.bxteam.divinemc.async.AsyncChunkSend.AsyncChunkSendThread) { ++ int size = calculateChunkSize(levelChunk); ++ ByteBuf buffer = Unpooled.buffer(size); ++ extractChunkData(new FriendlyByteBuf(buffer), levelChunk, chunkPacketInfo); ++ // make sure all sections is latest ++ while (size != buffer.writerIndex()) { ++ buffer.writerIndex(0); ++ size = calculateChunkSize(levelChunk); ++ extractChunkData(new FriendlyByteBuf(buffer), levelChunk, chunkPacketInfo); ++ } ++ byte[] array = it.unimi.dsi.fastutil.bytes.ByteArrays.setLength(buffer.array(), buffer.writerIndex()); ++ if (chunkPacketInfo != null) { ++ chunkPacketInfo.setBuffer(array); ++ } ++ this.buffer = array; ++ } else { ++ this.buffer = new byte[calculateChunkSize(levelChunk)]; ++ // Paper start - Anti-Xray - Add chunk packet info ++ if (chunkPacketInfo != null) { ++ chunkPacketInfo.setBuffer(this.buffer); ++ } ++ extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk, chunkPacketInfo); ++ } ++ ++ this.blockEntitiesData = Lists.newArrayList(); ++ int totalTileEntities = 0; // Paper - Handle oversized block entities in chunks ++ ++ for (BlockEntity blockEntity : blockEntities) { ++ // Paper start - Handle oversized block entities in chunks ++ if (++totalTileEntities > BLOCK_ENTITY_LIMIT) { ++ net.minecraft.network.protocol.Packet packet = blockEntity.getUpdatePacket(); ++ if (packet != null) { ++ this.extraPackets.add(packet); ++ continue; ++ } ++ } ++ // Paper end - Handle oversized block entities in chunks ++ this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(blockEntity)); ++ } ++ } ++ // DivineMC end - Async Chunk Sending ++ + public ClientboundLevelChunkPacketData(RegistryFriendlyByteBuf buffer, int x, int z) { + this.heightmaps = HEIGHTMAPS_STREAM_CODEC.decode(buffer); + int varInt = buffer.readVarInt(); +@@ -123,6 +169,8 @@ public class ClientboundLevelChunkPacketData { + // Paper end - Anti-Xray - Add chunk packet info } - private void sendUnloadChunk(final int chunkX, final int chunkZ) { ++ if (Thread.currentThread() instanceof org.bxteam.divinemc.async.AsyncChunkSend.AsyncChunkSendThread) return; // DivineMC - Async Chunk Sending ++ + if (buffer.writerIndex() != buffer.capacity()) { + throw new IllegalStateException("Didn't fill chunk buffer: expected " + buffer.capacity() + " bytes, got " + buffer.writerIndex()); + } +diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java +index 8578d1f78ddd1bb75f3230f04bfaa35af9f5f822..7c55fabd264e4e813d68798433dfccfb170537a2 100644 +--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java ++++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java +@@ -45,6 +45,18 @@ public class ClientboundLevelChunkWithLightPacket implements Packet heightmaps) { ++ ChunkPos pos = chunk.getPos(); ++ this.x = pos.x; ++ this.z = pos.z; ++ io.papermc.paper.antixray.ChunkPacketInfo chunkPacketInfo = modifyBlocks ? chunk.getLevel().chunkPacketBlockController.getChunkPacketInfo(this, chunk) : null; // Paper - Ant-Xray ++ this.chunkData = new ClientboundLevelChunkPacketData(chunk, chunkPacketInfo, blockEntities, heightmaps); // Paper - Anti-Xray ++ this.lightData = new ClientboundLightUpdatePacketData(pos, lightEngine, skyLight, blockLight); ++ chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks ++ } ++ // DivineMC end - Async Chunk Sending ++ + private ClientboundLevelChunkWithLightPacket(RegistryFriendlyByteBuf buffer) { + this.x = buffer.readInt(); + this.z = buffer.readInt(); +diff --git a/net/minecraft/server/network/PlayerChunkSender.java b/net/minecraft/server/network/PlayerChunkSender.java +index 0376a10ee0544b13e8fd629a7b13f78811e57a30..68c34ebf4dcf280aca6be27f3e34a5a74934ff45 100644 +--- a/net/minecraft/server/network/PlayerChunkSender.java ++++ b/net/minecraft/server/network/PlayerChunkSender.java +@@ -64,13 +64,25 @@ public class PlayerChunkSender { + if (!list.isEmpty()) { + ServerGamePacketListenerImpl serverGamePacketListenerImpl = player.connection; + this.unacknowledgedBatches++; +- serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE); ++ // DivineMC start - Async Chunk Sending ++ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncChunkSendingEnabled) { ++ org.bxteam.divinemc.async.AsyncChunkSend.POOL.execute(() -> serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE)); ++ } else { ++ serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE); ++ } ++ // DivineMC end - Async Chunk Sending + + for (LevelChunk levelChunk : list) { + sendChunk(serverGamePacketListenerImpl, serverLevel, levelChunk); + } + +- serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size())); ++ // DivineMC start - Async Chunk Sending ++ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncChunkSendingEnabled) { ++ org.bxteam.divinemc.async.AsyncChunkSend.POOL.execute(() -> serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size()))); ++ } else { ++ serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size())); ++ } ++ // DivineMC end - Async Chunk Sending + this.batchQuota = this.batchQuota - list.size(); + } + } +@@ -81,7 +93,24 @@ public class PlayerChunkSender { + // Paper start - Anti-Xray + public static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) { + final boolean shouldModify = level.chunkPacketBlockController.shouldModify(packetListener.player, chunk); +- packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify)); ++ ++ // DivineMC start - Async Chunk Sending ++ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncChunkSendingEnabled) { ++ var blockEntities = chunk.blockEntities.values().toArray(new net.minecraft.world.level.block.entity.BlockEntity[0]); ++ java.util.Map heightmaps = new java.util.concurrent.ConcurrentHashMap<>(); ++ ++ for (var entry : chunk.getHeightmaps()) { ++ if (entry.getKey().sendToClient()) { ++ heightmaps.put(entry.getKey(), entry.getValue().getRawData()); ++ } ++ } ++ ++ org.bxteam.divinemc.async.AsyncChunkSend.POOL.execute(() -> packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify, blockEntities, heightmaps))); ++ } else { ++ packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify)); ++ } ++ // DivineMC end - Async Chunk Sending ++ + // Paper end - Anti-Xray + // Paper start - PlayerChunkLoadEvent + if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { +diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java +index df717c545472006b99532280c38c1fbef12bcf82..ba4c20df405f41a526273a6216d2aedf4e5c435e 100644 +--- a/net/minecraft/world/level/chunk/LevelChunkSection.java ++++ b/net/minecraft/world/level/chunk/LevelChunkSection.java +@@ -18,7 +18,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ + public static final int SECTION_HEIGHT = 16; + public static final int SECTION_SIZE = 4096; + public static final int BIOME_CONTAINER_BITS = 2; +- short nonEmptyBlockCount; // Paper - package private ++ volatile short nonEmptyBlockCount; // Paper - package private // DivineMC - Async Chunk Sending + private short tickingBlockCount; + private short tickingFluidCount; + public final PalettedContainer states; diff --git a/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch b/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch index 14856a6..d02c5b8 100644 --- a/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch +++ b/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch @@ -37,10 +37,10 @@ index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..93272808d94e81d31af728ebe85df9a2 { for (int i = 0; i < this.directByChunk.length; ++i) { diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -index 053da602eb08b5a8b7a316e56f76a99e86149483..d1adef3f61acdbbc246f7ca3614b7e8aa7d25284 100644 +index c4a1e3908cf8e1b0614ff6c3a0f5f6708a7667e5..fef167837e05d6e80246d4fccd037cc1c9500f97 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -@@ -347,7 +347,11 @@ public final class RegionizedPlayerChunkLoader { +@@ -345,7 +345,11 @@ public final class RegionizedPlayerChunkLoader { private boolean canGenerateChunks = true; private final ArrayDeque> delayedTicketOps = new ArrayDeque<>(); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch index 6cd07b9..949f7c4 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -4,7 +4,7 @@ // Paper end - rewrite chunk system // Paper start - Improved watchdog support - move final shutdown items here Util.shutdownExecutors(); -+ org.bxteam.divinemc.util.ExecutorShutdown.shutdown(this); // DivineMC - Shutdown executors ++ org.bxteam.divinemc.async.ExecutorShutdown.shutdown(this); // DivineMC - Shutdown executors try { net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender } catch (final Exception ignored) { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/async/AsyncChunkSend.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/AsyncChunkSend.java new file mode 100644 index 0000000..ae34e3d --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/AsyncChunkSend.java @@ -0,0 +1,24 @@ +package org.bxteam.divinemc.async; + +import org.bxteam.divinemc.util.NamedAgnosticThreadFactory; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class AsyncChunkSend { + public static final ExecutorService POOL = new ThreadPoolExecutor( + 1, 1, 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), + new NamedAgnosticThreadFactory<>("Async Chunk Sending", AsyncChunkSendThread::new, Thread.NORM_PRIORITY), + new ThreadPoolExecutor.CallerRunsPolicy() + ); + + public static class AsyncChunkSendThread extends Thread { + protected AsyncChunkSendThread(ThreadGroup group, Runnable task, String name) { + super(group, task, name); + } + } +} + diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/ExecutorShutdown.java similarity index 84% rename from divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java rename to divinemc-server/src/main/java/org/bxteam/divinemc/async/ExecutorShutdown.java index e8ae0fc..33a64e4 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ExecutorShutdown.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/ExecutorShutdown.java @@ -1,11 +1,11 @@ -package org.bxteam.divinemc.util; +package org.bxteam.divinemc.async; import net.minecraft.server.MinecraftServer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor; import org.bxteam.divinemc.async.tracking.MultithreadedTracker; -import org.bxteam.divinemc.async.AsyncJoinHandler; + import java.util.concurrent.TimeUnit; @SuppressWarnings("ConstantValue") @@ -21,6 +21,15 @@ public class ExecutorShutdown { } catch (InterruptedException ignored) { } } + if (AsyncChunkSend.POOL != null) { + LOGGER.info("Shutting down async chunk send executor..."); + AsyncChunkSend.POOL.shutdown(); + + try { + AsyncChunkSend.POOL.awaitTermination(10L, TimeUnit.SECONDS); + } catch (InterruptedException ignored) { } + } + if (MultithreadedTracker.TRACKER_EXECUTOR != null) { LOGGER.info("Shutting down mob tracker executor..."); MultithreadedTracker.TRACKER_EXECUTOR.shutdown(); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/NamedAgnosticThreadFactory.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/NamedAgnosticThreadFactory.java index a3c901c..3522fad 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/NamedAgnosticThreadFactory.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/util/NamedAgnosticThreadFactory.java @@ -1,12 +1,13 @@ package org.bxteam.divinemc.util; import com.mojang.logging.LogUtils; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; import org.bxteam.divinemc.spark.ThreadDumperRegistry; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + public class NamedAgnosticThreadFactory implements ThreadFactory { private static final Logger LOGGER = LogUtils.getLogger(); private final ThreadGroup group; From d2465af868b662129c7be6b6698535dcbcf7fe8c Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:55:19 +0300 Subject: [PATCH 56/67] Euclidean distance squared option --- ...79-Euclidean-distance-squared-option.patch | 34 +++++++++++++++++++ .../bxteam/divinemc/config/DivineConfig.java | 3 ++ 2 files changed, 37 insertions(+) create mode 100644 divinemc-server/minecraft-patches/features/0079-Euclidean-distance-squared-option.patch diff --git a/divinemc-server/minecraft-patches/features/0079-Euclidean-distance-squared-option.patch b/divinemc-server/minecraft-patches/features/0079-Euclidean-distance-squared-option.patch new file mode 100644 index 0000000..cd42ddf --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0079-Euclidean-distance-squared-option.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Fri, 18 Jul 2025 13:54:17 +0300 +Subject: [PATCH] Euclidean distance squared option + + +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +index fef167837e05d6e80246d4fccd037cc1c9500f97..1ef70cc1ca0a47ddae8655e88fa6b74fa7f81dc6 100644 +--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +@@ -387,10 +387,19 @@ public final class RegionizedPlayerChunkLoader { + final int centerX = PlayerChunkLoaderData.this.lastChunkX; + final int centerZ = PlayerChunkLoaderData.this.lastChunkZ; + +- return Integer.compare( +- Math.abs(c1x - centerX) + Math.abs(c1z - centerZ), +- Math.abs(c2x - centerX) + Math.abs(c2z - centerZ) +- ); ++ // DivineMC start - Euclidean distance squared option ++ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.useEuclideanDistanceSquared) { ++ return Integer.compare( ++ (c1x - centerX) * (c1x - centerX) + (c1z - centerZ) * (c1z - centerZ), ++ (c2x - centerX) * (c2x - centerX) + (c2z - centerZ) * (c2z - centerZ) ++ ); ++ } else { ++ return Integer.compare( ++ Math.abs(c1x - centerX) + Math.abs(c1z - centerZ), ++ Math.abs(c2x - centerX) + Math.abs(c2z - centerZ) ++ ); ++ } ++ // DivineMC end - Euclidean distance squared option + }; + private final LongHeapPriorityQueue sendQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); + private final LongHeapPriorityQueue tickingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index d60289b..31cae55 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -372,6 +372,7 @@ public class DivineConfig { public static long chunkDataCacheLimit = 32678L; public static int maxViewDistance = 32; public static int playerNearChunkDetectionRange = 128; + public static boolean useEuclideanDistanceSquared = true; public static boolean endBiomeCacheEnabled = false; public static int endBiomeCacheCapacity = 1024; public static boolean smoothBedrockLayer = false; @@ -429,6 +430,8 @@ public class DivineConfig { "This value is used in the calculation 'range/16' to get the distance in chunks any player must be to allow the check to pass.", "By default, this range is computed to 8, meaning a player must be within an 8 chunk radius of a chunk position to pass.", "Keep in mind the result is rounded to the nearest whole number."); + useEuclideanDistanceSquared = getBoolean(ConfigCategory.PERFORMANCE.key("chunks.use-euclidean-distance-squared"), useEuclideanDistanceSquared, + "If enabled, euclidean distance squared for chunk task ordering will be used."); endBiomeCacheEnabled = getBoolean(ConfigCategory.PERFORMANCE.key("chunks.end-biome-cache-enabled"), endBiomeCacheEnabled, "Enables the end biome cache, which can accelerate The End worldgen."); From faecae75a16f58f6b54223cb6c960607a3c9877a Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 19 Jul 2025 23:49:06 +0300 Subject: [PATCH 57/67] improve buffered --- .../divinemc/async/ExecutorShutdown.java | 11 + .../divinemc/region/BufferReleaser.java | 34 -- .../region/type/BufferedRegionFile.java | 303 +++++++++++++++--- 3 files changed, 264 insertions(+), 84 deletions(-) delete mode 100644 divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferReleaser.java diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/async/ExecutorShutdown.java b/divinemc-server/src/main/java/org/bxteam/divinemc/async/ExecutorShutdown.java index 33a64e4..5586e16 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/async/ExecutorShutdown.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/async/ExecutorShutdown.java @@ -5,6 +5,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor; import org.bxteam.divinemc.async.tracking.MultithreadedTracker; +import org.bxteam.divinemc.config.DivineConfig; +import org.bxteam.divinemc.region.EnumRegionFileExtension; +import org.bxteam.divinemc.region.type.BufferedRegionFile; import java.util.concurrent.TimeUnit; @@ -13,6 +16,14 @@ public class ExecutorShutdown { public static final Logger LOGGER = LogManager.getLogger(ExecutorShutdown.class.getSimpleName()); public static void shutdown(MinecraftServer server) { + if (BufferedRegionFile.flusherInitialized && DivineConfig.MiscCategory.regionFileType == EnumRegionFileExtension.B_LINEAR) { + LOGGER.info("Shutting down buffered region executors..."); + + try { + BufferedRegionFile.shutdown(); + } catch (InterruptedException ignored) { } + } + if (server.mobSpawnExecutor != null && server.mobSpawnExecutor.thread.isAlive()) { LOGGER.info("Shutting down mob spawn executor..."); diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferReleaser.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferReleaser.java deleted file mode 100644 index 88739d1..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/BufferReleaser.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bxteam.divinemc.region; - -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; - -public class BufferReleaser { - private static final Method CLEANER_METHOD; - private static final Object UNSAFE; - - static { - try { - Class unsafeClass = Class.forName("sun.misc.Unsafe"); - Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe"); - theUnsafe.setAccessible(true); - UNSAFE = theUnsafe.get(null); - CLEANER_METHOD = unsafeClass.getMethod("invokeCleaner", ByteBuffer.class); - } catch (Exception ex) { - throw new RuntimeException("Unsafe init failed", ex); - } - } - - public static boolean clean(@NotNull ByteBuffer buffer) { - if (!buffer.isDirect()) return false; - try { - CLEANER_METHOD.invoke(UNSAFE, buffer); - return true; - } catch (Exception e) { - return false; - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java index 45b7b93..b6c094c 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java @@ -1,16 +1,22 @@ package org.bxteam.divinemc.region.type; +import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import net.jpountz.xxhash.XXHash32; import net.jpountz.xxhash.XXHashFactory; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.ChunkPos; -import org.bxteam.divinemc.region.BufferReleaser; +import org.bxteam.divinemc.region.EnumRegionFileExtension; import org.bxteam.divinemc.region.IRegionFile; +import org.bxteam.divinemc.config.DivineConfig; +import org.bxteam.divinemc.util.NamedAgnosticThreadFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import java.io.*; +import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; @@ -19,20 +25,15 @@ import java.nio.file.StandardOpenOption; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.*; +import java.util.Arrays; +import java.util.List; +import java.util.Set; /** * A buffered region file implementation that provides efficient chunk storage and retrieval * with compression, checksums, and automatic compaction capabilities. * - *

This implementation includes: - *

    - *
  • Zstandard compression for chunk data
  • - *
  • XXHash32 checksums for data integrity verification
  • - *
  • Automatic file compaction when fragmentation exceeds thresholds
  • - *
  • Thread-safe operations with read-write locks
  • - *
  • Direct ByteBuffer usage for memory efficiency
  • - *
- * *

For conversion tools between MCA and buffered region file formats, see: * LinearRegionFileFormatTools */ @@ -52,10 +53,24 @@ public class BufferedRegionFile implements IRegionFile { private byte compressionLevel = 6; private int xxHash32Seed = HASH_SEED; private FileChannel channel; + private boolean closed = false; + + private volatile boolean synced = true; + private volatile boolean beingSynced = false; + private volatile long lastWritten = 0L; + + private static final Set MANAGED_FILES = new ObjectLinkedOpenHashSet<>(); + private static volatile ScheduledFuture flusherChecker; + private static volatile Executor ioWorkerPool; + private static final Object FLUSHER_LOCK = new Object(); + public static volatile boolean flusherInitialized = false; + + private static final VarHandle SYNCED_HANDLE = ConcurrentUtil.getVarHandle(BufferedRegionFile.class, "synced", boolean.class); + private static final VarHandle BEING_SYNCED_HANDLE = ConcurrentUtil.getVarHandle(BufferedRegionFile.class, "beingSynced", boolean.class); + private static final VarHandle LAST_WRITTEN_HANDLE = ConcurrentUtil.getVarHandle(BufferedRegionFile.class, "lastWritten", long.class); public BufferedRegionFile(Path filePath, int compressionLevel) throws IOException { this(filePath); - this.compressionLevel = (byte) compressionLevel; } @@ -73,6 +88,179 @@ public class BufferedRegionFile implements IRegionFile { } this.readHeaders(); + + if (DivineConfig.MiscCategory.regionFileType == EnumRegionFileExtension.B_LINEAR) initializeFlusherIfNeeded(); + addToFlusherManagement(); + } + + private static void initializeFlusherIfNeeded() { + if (flusherInitialized) return; + + synchronized (FLUSHER_LOCK) { + if (flusherInitialized) { + return; + } + + final int nIoThreads = DivineConfig.MiscCategory.linearIoThreadCount; + final long checkIntervalMs = 20; + + ioWorkerPool = Executors.newFixedThreadPool(nIoThreads, + new NamedAgnosticThreadFactory<>( + "BufferedRegionFile I/O Worker", + (group, runnable, name) -> { + Thread thread = new Thread(group, runnable, name); + thread.setDaemon(true); + return thread; + }, + Thread.NORM_PRIORITY + ) + ); + + ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( + new NamedAgnosticThreadFactory<>( + "BufferedRegionFile Flusher Checker", + (group, runnable, name) -> { + Thread thread = new Thread(group, runnable, name); + thread.setDaemon(true); + return thread; + }, + Thread.NORM_PRIORITY + ) + ); + + flusherChecker = scheduler.scheduleWithFixedDelay( + BufferedRegionFile::runFlusherCheck, + checkIntervalMs, + checkIntervalMs, + TimeUnit.MILLISECONDS + ); + + flusherInitialized = true; + } + } + + private static void runFlusherCheck() { + final long currentNanos = System.nanoTime(); + final BufferedRegionFile[] copied; + + synchronized (MANAGED_FILES) { + copied = Arrays.copyOf( + MANAGED_FILES.toArray(new BufferedRegionFile[0]), + MANAGED_FILES.size(), + BufferedRegionFile[].class + ); + } + + final List toRemove = new ObjectArrayList<>(); + for (BufferedRegionFile file : copied) { + if (!file.softReadLock()) { + continue; + } + + boolean closed; + + try { + closed = file.isClosedRaw(); + } finally { + file.releaseReadLock(); + } + + if (closed) { + toRemove.add(file); + continue; + } + + if (!file.shouldSync()) { + continue; + } + + final long lastWriteNanos = file.getLastWritten(); + final long timeElapsed = (currentNanos - lastWriteNanos) / 1_000_000; + final long flushTimeoutMs = DivineConfig.MiscCategory.linearIoFlushDelayMs; + + if (timeElapsed >= flushTimeoutMs) { + if (!file.markAsBeingSynced()) { + continue; + } + + ioWorkerPool.execute(() -> { + try { + file.flush(); + file.syncIfNeeded(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + } + + synchronized (MANAGED_FILES) { + for (BufferedRegionFile file : toRemove) { + MANAGED_FILES.remove(file); + } + } + } + + public static void shutdown() throws InterruptedException { + synchronized (FLUSHER_LOCK) { + if (!flusherInitialized) { + return; + } + + if (flusherChecker != null) { + flusherChecker.cancel(false); + } + + if (ioWorkerPool instanceof ExecutorService) { + ((ExecutorService) ioWorkerPool).shutdown(); + //noinspection StatementWithEmptyBody + while (!((ExecutorService) ioWorkerPool).awaitTermination(100, TimeUnit.MILLISECONDS)); + } + + flusherInitialized = false; + } + } + + private void addToFlusherManagement() { + synchronized (MANAGED_FILES) { + MANAGED_FILES.add(this); + } + } + + private void removeFromFlusherManagement() { + synchronized (MANAGED_FILES) { + MANAGED_FILES.remove(this); + } + } + + public boolean softReadLock() { + return this.fileAccessLock.readLock().tryLock(); + } + + public void releaseReadLock() { + this.fileAccessLock.readLock().unlock(); + } + + public boolean isClosedRaw() { + return this.closed; + } + + public boolean shouldSync() { + return !(boolean) SYNCED_HANDLE.get(this); + } + + public long getLastWritten() { + return (long) LAST_WRITTEN_HANDLE.get(this); + } + + public boolean markAsBeingSynced() { + return BEING_SYNCED_HANDLE.compareAndSet(this, false, true); + } + + public void syncIfNeeded() throws IOException { + if (this.channel != null && this.channel.isOpen()) { + this.channel.force(true); + } } private void readHeaders() throws IOException { @@ -98,8 +286,6 @@ public class BufferedRegionFile implements IRegionFile { this.currentAcquiredIndex = Math.max(this.currentAcquiredIndex, sector.offset + sector.length); } } - - BufferReleaser.clean(buffer); } private void writeHeaders() throws IOException { @@ -121,8 +307,6 @@ public class BufferedRegionFile implements IRegionFile { while (buffer.hasRemaining()) { offset += this.channel.write(buffer, offset); } - - BufferReleaser.clean(buffer); } private int sectorSize() { @@ -143,6 +327,10 @@ public class BufferedRegionFile implements IRegionFile { } private void flushInternal() throws IOException { + if (this.closed) { + return; + } + this.writeHeaders(); long spareSize = this.channel.size(); @@ -163,6 +351,7 @@ public class BufferedRegionFile implements IRegionFile { } private void closeInternal() throws IOException { + this.closed = true; this.writeHeaders(); this.channel.force(true); this.compact(); @@ -186,35 +375,36 @@ public class BufferedRegionFile implements IRegionFile { while (headerBuffer.hasRemaining()) { offsetHeader += tempChannel.write(headerBuffer, offsetHeader); } - BufferReleaser.clean(headerBuffer); - int offsetPointer = this.headerSize(); + long offsetPointer = this.headerSize(); + tempChannel.position(offsetPointer); + for (Sector sector : this.sectors) { if (!sector.hasData()) { continue; } - final ByteBuffer sectorData = sector.read(this.channel); - final int length = sectorData.remaining(); - - final Sector newRecalculated = new Sector(sector.index, offsetPointer, length); - offsetPointer += length; - this.sectors[sector.index] = newRecalculated; - - newRecalculated.hasData = true; - - long offset = newRecalculated.offset; - while (sectorData.hasRemaining()) { - offset += tempChannel.write(sectorData, offset); + long transferred = 0; + while (transferred < sector.length) { + transferred += this.channel.transferTo( + sector.offset + transferred, + sector.length - transferred, + tempChannel); } - BufferReleaser.clean(sectorData); + final Sector newRecalculated = new Sector(sector.index, offsetPointer, sector.length); + newRecalculated.hasData = true; + + offsetPointer += sector.length; + this.sectors[sector.index] = newRecalculated; } tempChannel.force(true); - this.currentAcquiredIndex = tempChannel.size(); + this.currentAcquiredIndex = offsetPointer; } + this.channel.close(); + Files.move( new File(this.filePath.toString() + ".tmp").toPath(), this.filePath, @@ -242,6 +432,9 @@ public class BufferedRegionFile implements IRegionFile { final Sector sector = this.sectors[chunkOrdinal]; sector.store(chunkData, this.channel); + + SYNCED_HANDLE.set(this, false); + LAST_WRITTEN_HANDLE.set(this, System.nanoTime()); } private @Nullable ByteBuffer readChunkDataRaw(int chunkOrdinal) throws IOException { @@ -260,6 +453,9 @@ public class BufferedRegionFile implements IRegionFile { sector.clear(); this.writeHeaders(); + + SYNCED_HANDLE.set(this, false); + LAST_WRITTEN_HANDLE.set(this, System.nanoTime()); } private static int getChunkIndex(int x, int z) { @@ -281,13 +477,12 @@ public class BufferedRegionFile implements IRegionFile { final ByteBuffer chunkSectionBuilder = ByteBuffer.allocateDirect(compressedData.remaining() + 4 + 8 + 4); chunkSectionBuilder.putInt(data.remaining()); // Uncompressed length - chunkSectionBuilder.putLong(System.nanoTime()); // Timestamp + chunkSectionBuilder.putLong(System.currentTimeMillis()); // Timestamp chunkSectionBuilder.putInt(xxHash32OfData); // xxHash32 of the original data chunkSectionBuilder.put(compressedData); // Compressed data chunkSectionBuilder.flip(); this.writeChunkDataRaw(chunkIndex, chunkSectionBuilder); - BufferReleaser.clean(chunkSectionBuilder); } private @Nullable ByteBuffer readChunk(int x, int z) throws IOException { @@ -297,17 +492,15 @@ public class BufferedRegionFile implements IRegionFile { return null; } - final int uncompressedLength = compressed.getInt(); // compressed length + final int uncompressedLength = compressed.getInt(); final long timestamp = compressed.getLong(); // TODO use this timestamp for something? - final int dataXXHash32 = compressed.getInt(); // XXHash32 for validation + final int dataXXHash32 = compressed.getInt(); final ByteBuffer decompressed = this.decompress(this.ensureDirectBuffer(compressed), uncompressedLength); - BufferReleaser.clean(compressed); - final IOException xxHash32CheckFailedEx = this.checkXXHash32(dataXXHash32, decompressed); if (xxHash32CheckFailedEx != null) { - throw xxHash32CheckFailedEx; // prevent from loading + throw xxHash32CheckFailedEx; } return decompressed; @@ -437,10 +630,8 @@ public class BufferedRegionFile implements IRegionFile { final byte[] dataBytes = new byte[data.remaining()]; data.get(dataBytes); - BufferReleaser.clean(data); - return new DataInputStream(new ByteArrayInputStream(dataBytes)); - }finally { + } finally { this.fileAccessLock.readLock().unlock(); } } @@ -450,7 +641,7 @@ public class BufferedRegionFile implements IRegionFile { this.fileAccessLock.readLock().lock(); try { return this.hasData(getChunkIndex(pos.x, pos.z)); - }finally { + } finally { this.fileAccessLock.readLock().unlock(); } } @@ -465,7 +656,7 @@ public class BufferedRegionFile implements IRegionFile { this.fileAccessLock.writeLock().lock(); try { this.clearChunkData(getChunkIndex(pos.x, pos.z)); - }finally { + } finally { this.fileAccessLock.writeLock().unlock(); } } @@ -515,7 +706,6 @@ public class BufferedRegionFile implements IRegionFile { public int getRecalculateCount() { return this.recalculateCount.get(); } - // MCC end @Override public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) { @@ -531,8 +721,21 @@ public class BufferedRegionFile implements IRegionFile { public void flush() throws IOException { this.fileAccessLock.writeLock().lock(); try { - this.flushInternal(); - }finally { + if ((boolean) SYNCED_HANDLE.get(this)) { + return; + } + + if (!BEING_SYNCED_HANDLE.compareAndSet(this, false, true)) { + return; + } + + try { + this.flushInternal(); + SYNCED_HANDLE.set(this, true); + } finally { + BEING_SYNCED_HANDLE.set(this, false); + } + } finally { this.fileAccessLock.writeLock().unlock(); } } @@ -541,8 +744,9 @@ public class BufferedRegionFile implements IRegionFile { public void close() throws IOException { this.fileAccessLock.writeLock().lock(); try { + removeFromFlusherManagement(); this.closeInternal(); - }finally { + } finally { this.fileAccessLock.writeLock().unlock(); } } @@ -577,7 +781,7 @@ public class BufferedRegionFile implements IRegionFile { long offset = this.offset; while (newData.hasRemaining()) { - offset = channel.write(newData, offset); + offset += channel.write(newData, offset); } } @@ -611,7 +815,6 @@ public class BufferedRegionFile implements IRegionFile { } static int sizeOfSingle() { - // offset length hasData return Long.BYTES * 2 + 1; } } @@ -630,7 +833,7 @@ public class BufferedRegionFile implements IRegionFile { ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); BufferedRegionFile.this.writeChunk(this.pos.x, this.pos.z, bytebuffer); - }finally { + } finally { BufferedRegionFile.this.fileAccessLock.writeLock().unlock(); } } From e2e67afa20b8cd123659c88364c66010fa7ad548 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 20 Jul 2025 00:37:46 +0300 Subject: [PATCH 58/67] option to disable spectator change packet --- build-data/divinemc.at | 1 + ...-Do-not-send-spectator-change-packet.patch | 70 +++++++++++++++++++ .../bxteam/divinemc/config/DivineConfig.java | 3 + 3 files changed, 74 insertions(+) create mode 100644 divinemc-server/minecraft-patches/features/0080-Do-not-send-spectator-change-packet.patch diff --git a/build-data/divinemc.at b/build-data/divinemc.at index dda3c44..fdbd156 100644 --- a/build-data/divinemc.at +++ b/build-data/divinemc.at @@ -6,6 +6,7 @@ private-f net.minecraft.world.level.levelgen.NoiseChunk$FlatCache noiseFiller private-f net.minecraft.world.level.levelgen.NoiseChunk$NoiseInterpolator noiseFiller private-f net.minecraft.world.level.levelgen.RandomState router private-f net.minecraft.world.level.levelgen.RandomState sampler +public net.minecraft.server.level.ServerPlayerGameMode gameModeForPlayer public net.minecraft.util.Mth SIN public net.minecraft.world.entity.ai.Brain sensors public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities lineOfSightTest diff --git a/divinemc-server/minecraft-patches/features/0080-Do-not-send-spectator-change-packet.patch b/divinemc-server/minecraft-patches/features/0080-Do-not-send-spectator-change-packet.patch new file mode 100644 index 0000000..6d27a4d --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0080-Do-not-send-spectator-change-packet.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 20 Jul 2025 00:09:31 +0300 +Subject: [PATCH] Do not send spectator change packet + + +diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java +index 6e7ed7451a45f4525946563617ccf0a55851449b..6a2f8a798f46b337d611c14556ab5ecc1f2584cd 100644 +--- a/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -75,10 +75,18 @@ public class ServerPlayerGameMode { + // CraftBukkit end + this.setGameModeForPlayer(gameModeForPlayer, this.gameModeForPlayer); // Paper - Fix MC-259571 + this.player.onUpdateAbilities(); +- this.level +- .getServer() +- .getPlayerList() +- .broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); // CraftBukkit ++ ++ // DivineMC start - Do not send spectator change packet ++ if (!org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket) { ++ this.level.getServer().getPlayerList().broadcastPlayerInfoWithoutSpectatorName(this.player); ++ } else { ++ this.level ++ .getServer() ++ .getPlayerList() ++ .broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); ++ } ++ // DivineMC end - Do not send spectator change packet ++ + this.level.updateSleepingPlayerList(); + if (gameModeForPlayer == GameType.CREATIVE) { + this.player.resetCurrentImpulseContext(); +diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java +index 96af2c75b526c59510965665da0b2ca00bf657b3..b59078273bb6214295a448d5607538557d7eb1ee 100644 +--- a/net/minecraft/server/players/PlayerList.java ++++ b/net/minecraft/server/players/PlayerList.java +@@ -1473,4 +1473,32 @@ public abstract class PlayerList { + public boolean isAllowCommandsForAllPlayers() { + return this.allowCommandsForAllPlayers; + } ++ ++ // DivineMC start - Do not send spectator change packet ++ public void broadcastPlayerInfoWithoutSpectatorName(ServerPlayer player) { ++ net.minecraft.world.level.GameType displayMode = player.gameMode.getGameModeForPlayer() == net.minecraft.world.level.GameType.SPECTATOR ? net.minecraft.world.level.GameType.SURVIVAL : player.gameMode.getGameModeForPlayer(); ++ ++ for (ServerPlayer otherPlayer : this.players) { ++ if (otherPlayer != player && otherPlayer.getBukkitEntity().canSee(player.getBukkitEntity())) { ++ ClientboundPlayerInfoUpdatePacket packet = createPlayerInfoPacketWithoutSpectatorName(player, displayMode); ++ otherPlayer.connection.send(packet); ++ } ++ } ++ } ++ ++ private ClientboundPlayerInfoUpdatePacket createPlayerInfoPacketWithoutSpectatorName(ServerPlayer player, net.minecraft.world.level.GameType displayMode) { ++ net.minecraft.world.level.GameType originalMode = player.gameMode.gameModeForPlayer; ++ ++ player.gameMode.gameModeForPlayer = displayMode; ++ ++ ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket( ++ ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ++ player ++ ); ++ ++ player.gameMode.gameModeForPlayer = originalMode; ++ ++ return packet; ++ } ++ // DivineMC end - Do not send spectator change packet + } diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 31cae55..3bff625 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -767,6 +767,7 @@ public class DivineConfig { public static boolean optimizeNonFlushPacketSending = false; public static boolean disableDisconnectSpam = false; public static boolean dontRespondPingBeforeStart = true; + public static boolean sendSpectatorChangePacket = true; public static boolean playerProfileResultCachingEnabled = true; public static int playerProfileResultCachingTimeout = 1440; @@ -803,6 +804,8 @@ public class DivineConfig { "Prevents players being disconnected by 'disconnect.spam' when sending too many chat packets"); dontRespondPingBeforeStart = getBoolean(ConfigCategory.NETWORK.key("general.dont-respond-ping-before-start"), dontRespondPingBeforeStart, "Prevents the server from responding to pings before the server is fully booted."); + sendSpectatorChangePacket = getBoolean(ConfigCategory.NETWORK.key("general.send-spectator-change-packet"), sendSpectatorChangePacket, + "When disabled, tab list will not show that the player have entered the spectator mode. Otherwise, it will act as normal spectator change packet."); playerProfileResultCachingEnabled = getBoolean(ConfigCategory.NETWORK.key("player-profile-result-caching.enabled"), playerProfileResultCachingEnabled, "Enables caching of player profile results on first join."); From ea6672f6f6a5d0b312d242e2f302e6752ce5a6ad Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 20 Jul 2025 15:35:17 +0300 Subject: [PATCH 59/67] update readme and links in bug report --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- README.md | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 890aaa8..840516c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -61,4 +61,4 @@ body: - type: input attributes: label: Error log (if applicable) - description: If you are reporting a console error, upload any relevant errors or full log to either https://bin.bxteam.org/, https://mclo.gs/ or https://pastes.dev/, save and the paste the link in this box. + description: If you are reporting a console error, upload any relevant errors or full log to either https://pastes.dev or https://mclo.gs, save and the paste the link in this box. diff --git a/README.md b/README.md index eec2e34..81ee0c6 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,13 @@ DivineMC is a multi-functional fork of [Purpur](https://github.com/PurpurMC/Purp ## ⚙️ Features - -### 🚀 Core Performance - **Based on [Purpur](https://github.com/PurpurMC/Purpur)** - Adds a high customization level to your server - **Regionized Chunk Ticking** - Tick chunks in parallel, similar to how Folia does it - **Parallel World Ticking** - Leverage multiple CPU cores for world processing - **Async Operations** - Pathfinding, entity tracker, mob spawning, joining and chunk sending - -### 🔧 Advanced Features - **Secure Seed** - Enhanced 1024-bit seed system (vs standard 64-bit) for maximum security - **Linear Region File Format** - Optimize your world with the old V1/V2 linear format and the new Buffered format - **Mod Protocols Support** - Compatible with Syncmatica, Apple Skin, Jade and Xaero's Map - -### 🔌 Compatibility & Reliability - **Fully Compatible** - Works seamlessly with Bukkit, Spigot and Paper plugins - **Bug Fixes** - Resolves various Minecraft issues (~10) - **Sentry Integration** - Detailed error tracking and monitoring (original by [Pufferfish](https://github.com/pufferfish-gg/Pufferfish)) From 1f51fdd5bf8617bbfb9b252262ece6e1e03d016b Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 20 Jul 2025 15:58:41 +0300 Subject: [PATCH 60/67] cleanup --- .../features/0001-Rebrand.patch | 4 +- ...03-Completely-remove-Mojang-profiler.patch | 56 +++++++++---------- ...til.patch => 0009-lithium-fast_util.patch} | 0 ...> 0010-C2ME-Optimize-world-gen-math.patch} | 0 ....patch => 0011-Async-locate-command.patch} | 0 ...Carpet-Fixes-RecipeManager-Optimize.patch} | 0 ...-lithium-faster-chunk-serialization.patch} | 0 ...0014-C2ME-optimize-noise-generation.patch} | 0 ...h => 0015-Use-Java-s-Math-functions.patch} | 0 ...ay.patch => 0016-Disable-leaf-decay.patch} | 0 ...patch => 0017-Optimize-entity-brain.patch} | 0 ...-distanceToSqr-call-in-ServerEntity.patch} | 0 ...pet-Fixes-Optimized-getBiome-method.patch} | 0 ...020-Carpet-Fixes-Sheep-Optimization.patch} | 0 ...ers-that-were-dead-on-server-restart.patch | 24 -------- ...S-Addition-Optimized-dragon-respawn.patch} | 0 .../features/0021-Configurable-MC-67.patch | 18 ------ ... 0022-ModernFix-compact_bit_storage.patch} | 0 ...3-Option-to-disable-disconnect.spam.patch} | 12 ++-- ...ble-saving-of-snowball-and-firework.patch} | 0 ...t-Fixes-Fix-Slime-Block-Bounce-Logic.patch | 28 ---------- ... => 0025-Snowball-and-Egg-knockback.patch} | 0 ....patch => 0026-Optimize-suffocation.patch} | 0 ...> 0027-Reduce-chunk-loading-lookups.patch} | 0 ...gurable-movement-speed-for-entities.patch} | 0 ...BlockEntity-ticking-isRemoved-check.patch} | 0 ...eird-movement-and-disable-teleporti.patch} | 10 ++-- ...-Raids.patch => 0031-Optimize-Raids.patch} | 0 ...Small-optimization-to-LinearPalette.patch} | 0 ...=> 0033-Use-switch-for-VarInt-write.patch} | 0 ...luids.patch => 0034-Optimize-Fluids.patch} | 0 ... 0035-Optimize-Structure-Generation.patch} | 0 ...tch => 0036-Implement-NoChatReports.patch} | 4 +- ...tion.patch => 0037-Lag-compensation.patch} | 2 +- ...reads.patch => 0038-Virtual-Threads.patch} | 6 +- ...g.patch => 0039-Async-Chunk-Sending.patch} | 0 ...et-dirty-flag-when-loading-maps-from.patch | 25 --------- ...Command-block-parse-results-caching.patch} | 0 ...> 0041-Player-ProfileResult-caching.patch} | 0 ...patch => 0042-Implement-Secure-Seed.patch} | 0 ...=> 0043-Dynamic-Activation-of-Brain.patch} | 0 ...-SparklyPaper-Optimize-canSee-checks.patch | 28 ---------- ...tch => 0044-Petal-Async-Pathfinding.patch} | 0 ...=> 0045-Petal-Multithreaded-Tracker.patch} | 4 +- ...46-Pufferfish-Optimize-mob-spawning.patch} | 2 +- ...r-ShapelessRecipes-comparison-for-V.patch} | 0 ...0048-C2ME-Density-Function-Compiler.patch} | 0 ...patch => 0049-Clump-experience-orbs.patch} | 0 ...SparklyPaper-Parallel-world-ticking.patch} | 4 +- ...> 0051-MSPT-Tracking-for-each-world.patch} | 2 +- ...ch => 0052-Catch-update-suppressors.patch} | 2 +- ...ch => 0053-Regionized-Chunk-Ticking.patch} | 2 +- ....patch => 0054-C2ME-Limit-NBT-cache.patch} | 0 ...2ME-Optimize-Aquifer-and-Beardifier.patch} | 0 ...patch => 0056-Copper-Bulb-1gt-delay.patch} | 0 ...lay.patch => 0057-Crafter-1gt-delay.patch} | 0 ...tch => 0058-Raytrace-Entity-Tracker.patch} | 2 +- ...ead.patch => 0059-Async-Join-Thread.patch} | 0 ....patch => 0060-Leaves-Protocol-Core.patch} | 10 ++-- ...R-Optimise-non-flush-packet-sending.patch} | 0 ...h => 0062-Linear-region-file-format.patch} | 2 +- ...> 0063-Cleanup-dead-code-from-Paper.patch} | 2 +- ...ch => 0064-C2ME-The-End-Biome-Cache.patch} | 0 ...5-Euclidean-distance-squared-option.patch} | 0 ...Do-not-send-spectator-change-packet.patch} | 0 .../subcommands/FixLightCommand.java.patch} | 12 +--- .../server/MinecraftServer.java.patch | 14 +++++ .../server/level/ChunkMap.java.patch | 11 ++++ .../ServerGamePacketListenerImpl.java.patch} | 14 +---- ...ServerStatusPacketListenerImpl.java.patch} | 11 +--- .../server/players/PlayerList.java.patch} | 12 +--- .../stats/ServerStatsCounter.java.patch} | 18 ++---- .../minecraft/world/entity/Entity.java.patch | 8 +++ .../minecraft/world/level/Level.java.patch} | 16 ++---- .../world/level/block/SlimeBlock.java.patch | 10 ++++ .../level/block/TripWireHookBlock.java.patch} | 15 +---- .../entity/HopperBlockEntity.java.patch} | 12 +--- .../world/level/chunk/LevelChunk.java.patch} | 18 ++---- .../maps/MapItemSavedData.java.patch | 10 ++++ .../paper-patches/features/0001-Rebrand.patch | 21 +------ .../features/0002-Configuration.patch | 6 +- ...loading-plugins-from-external-folder.patch | 4 +- .../org/bxteam/divinemc/DivineBootstrap.java | 3 +- .../region/type/BufferedRegionFile.java | 3 +- 84 files changed, 150 insertions(+), 317 deletions(-) rename divinemc-server/minecraft-patches/features/{0010-lithium-fast_util.patch => 0009-lithium-fast_util.patch} (100%) rename divinemc-server/minecraft-patches/features/{0011-C2ME-Optimize-world-gen-math.patch => 0010-C2ME-Optimize-world-gen-math.patch} (100%) rename divinemc-server/minecraft-patches/features/{0014-Async-locate-command.patch => 0011-Async-locate-command.patch} (100%) rename divinemc-server/minecraft-patches/features/{0015-Carpet-Fixes-RecipeManager-Optimize.patch => 0012-Carpet-Fixes-RecipeManager-Optimize.patch} (100%) rename divinemc-server/minecraft-patches/features/{0016-lithium-faster-chunk-serialization.patch => 0013-lithium-faster-chunk-serialization.patch} (100%) rename divinemc-server/minecraft-patches/features/{0017-C2ME-optimize-noise-generation.patch => 0014-C2ME-optimize-noise-generation.patch} (100%) rename divinemc-server/minecraft-patches/features/{0023-Use-Java-s-Math-functions.patch => 0015-Use-Java-s-Math-functions.patch} (100%) rename divinemc-server/minecraft-patches/features/{0024-Disable-leaf-decay.patch => 0016-Disable-leaf-decay.patch} (100%) rename divinemc-server/minecraft-patches/features/{0026-Optimize-entity-brain.patch => 0017-Optimize-entity-brain.patch} (100%) rename divinemc-server/minecraft-patches/features/{0027-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch => 0018-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch} (100%) rename divinemc-server/minecraft-patches/features/{0028-Carpet-Fixes-Optimized-getBiome-method.patch => 0019-Carpet-Fixes-Optimized-getBiome-method.patch} (100%) rename divinemc-server/minecraft-patches/features/{0030-Carpet-Fixes-Sheep-Optimization.patch => 0020-Carpet-Fixes-Sheep-Optimization.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0020-Respawn-players-that-were-dead-on-server-restart.patch rename divinemc-server/minecraft-patches/features/{0031-Carpet-AMS-Addition-Optimized-dragon-respawn.patch => 0021-Carpet-AMS-Addition-Optimized-dragon-respawn.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0021-Configurable-MC-67.patch rename divinemc-server/minecraft-patches/features/{0032-ModernFix-compact_bit_storage.patch => 0022-ModernFix-compact_bit_storage.patch} (100%) rename divinemc-server/minecraft-patches/features/{0033-Option-to-disable-disconnect.spam.patch => 0023-Option-to-disable-disconnect.spam.patch} (91%) rename divinemc-server/minecraft-patches/features/{0034-Option-to-disable-saving-of-snowball-and-firework.patch => 0024-Option-to-disable-saving-of-snowball-and-firework.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0025-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch rename divinemc-server/minecraft-patches/features/{0035-Snowball-and-Egg-knockback.patch => 0025-Snowball-and-Egg-knockback.patch} (100%) rename divinemc-server/minecraft-patches/features/{0036-Optimize-suffocation.patch => 0026-Optimize-suffocation.patch} (100%) rename divinemc-server/minecraft-patches/features/{0037-Reduce-chunk-loading-lookups.patch => 0027-Reduce-chunk-loading-lookups.patch} (100%) rename divinemc-server/minecraft-patches/features/{0038-Configurable-movement-speed-for-entities.patch => 0028-Configurable-movement-speed-for-entities.patch} (100%) rename divinemc-server/minecraft-patches/features/{0040-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch => 0029-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch} (100%) rename divinemc-server/minecraft-patches/features/{0041-Option-to-allow-weird-movement-and-disable-teleporti.patch => 0030-Option-to-allow-weird-movement-and-disable-teleporti.patch} (94%) rename divinemc-server/minecraft-patches/features/{0042-Optimize-Raids.patch => 0031-Optimize-Raids.patch} (100%) rename divinemc-server/minecraft-patches/features/{0044-Small-optimization-to-LinearPalette.patch => 0032-Small-optimization-to-LinearPalette.patch} (100%) rename divinemc-server/minecraft-patches/features/{0045-Use-switch-for-VarInt-write.patch => 0033-Use-switch-for-VarInt-write.patch} (100%) rename divinemc-server/minecraft-patches/features/{0046-Optimize-Fluids.patch => 0034-Optimize-Fluids.patch} (100%) rename divinemc-server/minecraft-patches/features/{0047-Optimize-Structure-Generation.patch => 0035-Optimize-Structure-Generation.patch} (100%) rename divinemc-server/minecraft-patches/features/{0048-Implement-NoChatReports.patch => 0036-Implement-NoChatReports.patch} (99%) rename divinemc-server/minecraft-patches/features/{0049-Lag-compensation.patch => 0037-Lag-compensation.patch} (99%) rename divinemc-server/minecraft-patches/features/{0050-Virtual-Threads.patch => 0038-Virtual-Threads.patch} (96%) rename divinemc-server/minecraft-patches/features/{0051-Async-Chunk-Sending.patch => 0039-Async-Chunk-Sending.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0039-SparklyPaper-Reset-dirty-flag-when-loading-maps-from.patch rename divinemc-server/minecraft-patches/features/{0052-Command-block-parse-results-caching.patch => 0040-Command-block-parse-results-caching.patch} (100%) rename divinemc-server/minecraft-patches/features/{0053-Player-ProfileResult-caching.patch => 0041-Player-ProfileResult-caching.patch} (100%) rename divinemc-server/minecraft-patches/features/{0054-Implement-Secure-Seed.patch => 0042-Implement-Secure-Seed.patch} (100%) rename divinemc-server/minecraft-patches/features/{0055-Dynamic-Activation-of-Brain.patch => 0043-Dynamic-Activation-of-Brain.patch} (100%) delete mode 100644 divinemc-server/minecraft-patches/features/0043-SparklyPaper-Optimize-canSee-checks.patch rename divinemc-server/minecraft-patches/features/{0056-Petal-Async-Pathfinding.patch => 0044-Petal-Async-Pathfinding.patch} (100%) rename divinemc-server/minecraft-patches/features/{0057-Petal-Multithreaded-Tracker.patch => 0045-Petal-Multithreaded-Tracker.patch} (99%) rename divinemc-server/minecraft-patches/features/{0058-Pufferfish-Optimize-mob-spawning.patch => 0046-Pufferfish-Optimize-mob-spawning.patch} (99%) rename divinemc-server/minecraft-patches/features/{0059-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch => 0047-Pufferfish-Simpler-ShapelessRecipes-comparison-for-V.patch} (100%) rename divinemc-server/minecraft-patches/features/{0060-C2ME-Density-Function-Compiler.patch => 0048-C2ME-Density-Function-Compiler.patch} (100%) rename divinemc-server/minecraft-patches/features/{0061-Clump-experience-orbs.patch => 0049-Clump-experience-orbs.patch} (100%) rename divinemc-server/minecraft-patches/features/{0062-SparklyPaper-Parallel-world-ticking.patch => 0050-SparklyPaper-Parallel-world-ticking.patch} (99%) rename divinemc-server/minecraft-patches/features/{0063-MSPT-Tracking-for-each-world.patch => 0051-MSPT-Tracking-for-each-world.patch} (95%) rename divinemc-server/minecraft-patches/features/{0064-Catch-update-suppressors.patch => 0052-Catch-update-suppressors.patch} (98%) rename divinemc-server/minecraft-patches/features/{0065-Regionized-Chunk-Ticking.patch => 0053-Regionized-Chunk-Ticking.patch} (99%) rename divinemc-server/minecraft-patches/features/{0066-C2ME-Limit-NBT-cache.patch => 0054-C2ME-Limit-NBT-cache.patch} (100%) rename divinemc-server/minecraft-patches/features/{0067-C2ME-Optimize-Aquifer-and-Beardifier.patch => 0055-C2ME-Optimize-Aquifer-and-Beardifier.patch} (100%) rename divinemc-server/minecraft-patches/features/{0068-Copper-Bulb-1gt-delay.patch => 0056-Copper-Bulb-1gt-delay.patch} (100%) rename divinemc-server/minecraft-patches/features/{0069-Crafter-1gt-delay.patch => 0057-Crafter-1gt-delay.patch} (100%) rename divinemc-server/minecraft-patches/features/{0070-Raytrace-Entity-Tracker.patch => 0058-Raytrace-Entity-Tracker.patch} (98%) rename divinemc-server/minecraft-patches/features/{0071-Async-Join-Thread.patch => 0059-Async-Join-Thread.patch} (100%) rename divinemc-server/minecraft-patches/features/{0072-Leaves-Protocol-Core.patch => 0060-Leaves-Protocol-Core.patch} (95%) rename divinemc-server/minecraft-patches/features/{0075-Paper-PR-Optimise-non-flush-packet-sending.patch => 0061-Paper-PR-Optimise-non-flush-packet-sending.patch} (100%) rename divinemc-server/minecraft-patches/features/{0076-Linear-region-file-format.patch => 0062-Linear-region-file-format.patch} (99%) rename divinemc-server/minecraft-patches/features/{0077-Cleanup-dead-code-from-Paper.patch => 0063-Cleanup-dead-code-from-Paper.patch} (98%) rename divinemc-server/minecraft-patches/features/{0078-C2ME-The-End-Biome-Cache.patch => 0064-C2ME-The-End-Biome-Cache.patch} (100%) rename divinemc-server/minecraft-patches/features/{0079-Euclidean-distance-squared-option.patch => 0065-Euclidean-distance-squared-option.patch} (100%) rename divinemc-server/minecraft-patches/features/{0080-Do-not-send-spectator-change-packet.patch => 0066-Do-not-send-spectator-change-packet.patch} (100%) rename divinemc-server/minecraft-patches/{features/0009-Parchment-Make-FixLight-use-action-bar.patch => sources/io/papermc/paper/command/subcommands/FixLightCommand.java.patch} (78%) create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch rename divinemc-server/minecraft-patches/{features/0074-Leaves-Syncmatica-Protocol.patch => sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch} (67%) rename divinemc-server/minecraft-patches/{features/0019-Don-t-respond-ping-before-start-fully.patch => sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch} (66%) rename divinemc-server/minecraft-patches/{features/0073-Leaves-Xaero-s-Map-Protocol.patch => sources/net/minecraft/server/players/PlayerList.java.patch} (59%) rename divinemc-server/minecraft-patches/{features/0013-SparklyPaper-Clear-dirty-stats-after-copying.patch => sources/net/minecraft/stats/ServerStatsCounter.java.patch} (59%) rename divinemc-server/minecraft-patches/{features/0012-Re-Fix-MC-117075.patch => sources/net/minecraft/world/level/Level.java.patch} (74%) create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/SlimeBlock.java.patch rename divinemc-server/minecraft-patches/{features/0022-Configurable-MC-59471.patch => sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch} (76%) rename divinemc-server/minecraft-patches/{features/0029-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch => sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch} (59%) rename divinemc-server/minecraft-patches/{features/0018-Optimize-block-state-lookup.patch => sources/net/minecraft/world/level/chunk/LevelChunk.java.patch} (63%) create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch diff --git a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch index 8e42e91..6a25e7d 100644 --- a/divinemc-server/minecraft-patches/features/0001-Rebrand.patch +++ b/divinemc-server/minecraft-patches/features/0001-Rebrand.patch @@ -130,10 +130,10 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..c3ac5ba5d8084fefc0e9f58b09b521ef String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck(); if (awtException != null) { diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index d651ddade8a460c25f4f8d70822d9ef69f1acb4b..8fce263f8cab4e0ff2ee6fe4fd9e46bbd0bbde19 100644 +index 3de43e4edb33bb2c657a315ad2676ce44ee3bd6a..2d01252a66e59f69ff69055b83d7e881f2f3e5cd 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1177,6 +1177,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && this.tickCount % autosavePeriod == 0; try { this.isSaving = true; -@@ -1593,10 +1557,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop serverPlayer1.connection.suspendFlushing()); this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit // Paper start - optimise Folia entity scheduler -@@ -1710,9 +1666,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Purpur - Ridables @@ -429,7 +429,7 @@ index 8fce263f8cab4e0ff2ee6fe4fd9e46bbd0bbde19..6498455c4c2838cbee743f016d8be1fe try { serverLevel.tick(hasTimeLeft); } catch (Throwable var7) { -@@ -1767,34 +1716,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop, AutoCl - this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 +@@ -1527,7 +1521,6 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl + this.blockEntityTickers.removeMarkedEntries(); // DivineMC - optimize block entity removals - Fix MC-117075 this.tickingBlockEntities = false; - profilerFiller.pop(); this.spigotConfig.currentPrimedTnt = 0; // Spigot } -@@ -1781,7 +1774,6 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1779,7 +1772,6 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @Override public List getEntities(@Nullable Entity entity, AABB boundingBox, Predicate predicate) { @@ -4973,7 +4973,7 @@ index 1ad419b4a2ad4610a0a8d18b26665a7ec0ccc960..4c1ce7e85f9c3315635472047ffaf15a List list = Lists.newArrayList(); // Paper start - rewrite chunk system -@@ -1810,8 +1802,6 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1808,8 +1800,6 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl public void getEntities(final EntityTypeTest entityTypeTest, final AABB boundingBox, final Predicate predicate, final List into, final int maxCount) { @@ -5039,7 +5039,7 @@ index b80924fbe054b00fe5117df896358e330f41e993..1669c21534a453c9cf16b992df7a6bf2 if (this.fire) { diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index 75578e6ed7233a03d9b6cd3c6d3997f1c6148392..b88254fb3c12b99684c6ede1ae8a6671ffbe9ad6 100644 +index 8345405116202b59055f5343fc26b82f48008050..dbb4142ea38cdf484e74c81103cebb024ae8813d 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -24,8 +24,6 @@ import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; @@ -5051,7 +5051,7 @@ index 75578e6ed7233a03d9b6cd3c6d3997f1c6148392..b88254fb3c12b99684c6ede1ae8a6671 import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; -@@ -385,12 +383,8 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -392,12 +390,8 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p } if (LightEngine.hasDifferentLightProperties(blockState, state)) { @@ -5064,7 +5064,7 @@ index 75578e6ed7233a03d9b6cd3c6d3997f1c6148392..b88254fb3c12b99684c6ede1ae8a6671 } boolean flag = !blockState.is(block); -@@ -922,8 +916,6 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -929,8 +923,6 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p BlockPos blockPos = this.blockEntity.getBlockPos(); if (LevelChunk.this.isTicking(blockPos)) { try { @@ -5073,7 +5073,7 @@ index 75578e6ed7233a03d9b6cd3c6d3997f1c6148392..b88254fb3c12b99684c6ede1ae8a6671 BlockState blockState = LevelChunk.this.getBlockState(blockPos); if (this.blockEntity.getType().isValid(blockState)) { this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity); -@@ -937,8 +929,6 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -944,8 +936,6 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p } // Paper end - Remove the Block Entity if it's invalid } @@ -5115,7 +5115,7 @@ index 81de6c1bbef1cafd3036e736dd305fbedc8368c6..c2baadcdceb1df6a881d6f73aa4eb4dd // Paper end - Perf: remove streams and optimize collection } diff --git a/net/minecraft/world/ticks/LevelTicks.java b/net/minecraft/world/ticks/LevelTicks.java -index 66abc2e7adee60fa98eed1ba36e018814fd02cad..0a9805d42142678ca5213c511235daa6505ddbf3 100644 +index 769037ecd67b2ed92067bba4e5f7ac9383c3d456..2f88649c398d7f60f10532eb6b36ce1c27bcbdcc 100644 --- a/net/minecraft/world/ticks/LevelTicks.java +++ b/net/minecraft/world/ticks/LevelTicks.java @@ -23,8 +23,6 @@ import net.minecraft.Util; diff --git a/divinemc-server/minecraft-patches/features/0010-lithium-fast_util.patch b/divinemc-server/minecraft-patches/features/0009-lithium-fast_util.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0010-lithium-fast_util.patch rename to divinemc-server/minecraft-patches/features/0009-lithium-fast_util.patch diff --git a/divinemc-server/minecraft-patches/features/0011-C2ME-Optimize-world-gen-math.patch b/divinemc-server/minecraft-patches/features/0010-C2ME-Optimize-world-gen-math.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0011-C2ME-Optimize-world-gen-math.patch rename to divinemc-server/minecraft-patches/features/0010-C2ME-Optimize-world-gen-math.patch diff --git a/divinemc-server/minecraft-patches/features/0014-Async-locate-command.patch b/divinemc-server/minecraft-patches/features/0011-Async-locate-command.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0014-Async-locate-command.patch rename to divinemc-server/minecraft-patches/features/0011-Async-locate-command.patch diff --git a/divinemc-server/minecraft-patches/features/0015-Carpet-Fixes-RecipeManager-Optimize.patch b/divinemc-server/minecraft-patches/features/0012-Carpet-Fixes-RecipeManager-Optimize.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0015-Carpet-Fixes-RecipeManager-Optimize.patch rename to divinemc-server/minecraft-patches/features/0012-Carpet-Fixes-RecipeManager-Optimize.patch diff --git a/divinemc-server/minecraft-patches/features/0016-lithium-faster-chunk-serialization.patch b/divinemc-server/minecraft-patches/features/0013-lithium-faster-chunk-serialization.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0016-lithium-faster-chunk-serialization.patch rename to divinemc-server/minecraft-patches/features/0013-lithium-faster-chunk-serialization.patch diff --git a/divinemc-server/minecraft-patches/features/0017-C2ME-optimize-noise-generation.patch b/divinemc-server/minecraft-patches/features/0014-C2ME-optimize-noise-generation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0017-C2ME-optimize-noise-generation.patch rename to divinemc-server/minecraft-patches/features/0014-C2ME-optimize-noise-generation.patch diff --git a/divinemc-server/minecraft-patches/features/0023-Use-Java-s-Math-functions.patch b/divinemc-server/minecraft-patches/features/0015-Use-Java-s-Math-functions.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0023-Use-Java-s-Math-functions.patch rename to divinemc-server/minecraft-patches/features/0015-Use-Java-s-Math-functions.patch diff --git a/divinemc-server/minecraft-patches/features/0024-Disable-leaf-decay.patch b/divinemc-server/minecraft-patches/features/0016-Disable-leaf-decay.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0024-Disable-leaf-decay.patch rename to divinemc-server/minecraft-patches/features/0016-Disable-leaf-decay.patch diff --git a/divinemc-server/minecraft-patches/features/0026-Optimize-entity-brain.patch b/divinemc-server/minecraft-patches/features/0017-Optimize-entity-brain.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0026-Optimize-entity-brain.patch rename to divinemc-server/minecraft-patches/features/0017-Optimize-entity-brain.patch diff --git a/divinemc-server/minecraft-patches/features/0027-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch b/divinemc-server/minecraft-patches/features/0018-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0027-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch rename to divinemc-server/minecraft-patches/features/0018-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch diff --git a/divinemc-server/minecraft-patches/features/0028-Carpet-Fixes-Optimized-getBiome-method.patch b/divinemc-server/minecraft-patches/features/0019-Carpet-Fixes-Optimized-getBiome-method.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0028-Carpet-Fixes-Optimized-getBiome-method.patch rename to divinemc-server/minecraft-patches/features/0019-Carpet-Fixes-Optimized-getBiome-method.patch diff --git a/divinemc-server/minecraft-patches/features/0030-Carpet-Fixes-Sheep-Optimization.patch b/divinemc-server/minecraft-patches/features/0020-Carpet-Fixes-Sheep-Optimization.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0030-Carpet-Fixes-Sheep-Optimization.patch rename to divinemc-server/minecraft-patches/features/0020-Carpet-Fixes-Sheep-Optimization.patch diff --git a/divinemc-server/minecraft-patches/features/0020-Respawn-players-that-were-dead-on-server-restart.patch b/divinemc-server/minecraft-patches/features/0020-Respawn-players-that-were-dead-on-server-restart.patch deleted file mode 100644 index 4d5e987..0000000 --- a/divinemc-server/minecraft-patches/features/0020-Respawn-players-that-were-dead-on-server-restart.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:50:15 +0300 -Subject: [PATCH] Respawn players that were dead on server restart - - -diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 6498455c4c2838cbee743f016d8be1fe2fb61f6d..141c19eb290080f762da1e2090dae0609f2e3575 100644 ---- a/net/minecraft/server/MinecraftServer.java -+++ b/net/minecraft/server/MinecraftServer.java -@@ -971,6 +971,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Sun, 23 Feb 2025 01:03:59 +0300 -Subject: [PATCH] Configurable MC-67 - - -diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 0171befef713e89d9241c7735d5d285b23373e8f..5bc7f37290eb99145a2ea3e40d31180f3494979b 100644 ---- a/net/minecraft/world/entity/Entity.java -+++ b/net/minecraft/world/entity/Entity.java -@@ -4198,6 +4198,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public boolean canTeleport(Level fromLevel, Level toLevel) { -+ if (!fromLevel.divineConfig.allowEntityPortalWithPassenger && (this.isPassenger() || this.isVehicle())) return false; // DivineMC - Allow entity teleport with passenger - if (!this.isAlive() || !this.valid) return false; // Paper - Fix item duplication and teleport issues - if (fromLevel.dimension() == Level.END && toLevel.dimension() == Level.OVERWORLD) { - for (Entity entity : this.getPassengers()) { diff --git a/divinemc-server/minecraft-patches/features/0032-ModernFix-compact_bit_storage.patch b/divinemc-server/minecraft-patches/features/0022-ModernFix-compact_bit_storage.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0032-ModernFix-compact_bit_storage.patch rename to divinemc-server/minecraft-patches/features/0022-ModernFix-compact_bit_storage.patch diff --git a/divinemc-server/minecraft-patches/features/0033-Option-to-disable-disconnect.spam.patch b/divinemc-server/minecraft-patches/features/0023-Option-to-disable-disconnect.spam.patch similarity index 91% rename from divinemc-server/minecraft-patches/features/0033-Option-to-disable-disconnect.spam.patch rename to divinemc-server/minecraft-patches/features/0023-Option-to-disable-disconnect.spam.patch index 984de26..acec63f 100644 --- a/divinemc-server/minecraft-patches/features/0033-Option-to-disable-disconnect.spam.patch +++ b/divinemc-server/minecraft-patches/features/0023-Option-to-disable-disconnect.spam.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Option to disable disconnect.spam diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index a63ade75461b68a780c56bfb5ff7c61f99f76744..fe7d68f3947bf55a389c73ef301fae8e396bf1da 100644 +index e269535609363528971268fdca9e6a6b70902608..637c5ca0c004e5de66bc3f84dba5fee47f729579 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -844,7 +844,7 @@ public class ServerGamePacketListenerImpl +@@ -846,7 +846,7 @@ public class ServerGamePacketListenerImpl public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) { // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); // Paper - AsyncTabCompleteEvent; run this async // CraftBukkit start @@ -17,7 +17,7 @@ index a63ade75461b68a780c56bfb5ff7c61f99f76744..fe7d68f3947bf55a389c73ef301fae8e this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause // Paper - add proper async disconnect return; } -@@ -856,7 +856,7 @@ public class ServerGamePacketListenerImpl +@@ -858,7 +858,7 @@ public class ServerGamePacketListenerImpl // Paper end - Don't suggest if tab-complete is disabled // Paper start final int index; @@ -26,7 +26,7 @@ index a63ade75461b68a780c56bfb5ff7c61f99f76744..fe7d68f3947bf55a389c73ef301fae8e this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - add proper async disconnect return; } -@@ -916,6 +916,7 @@ public class ServerGamePacketListenerImpl +@@ -918,6 +918,7 @@ public class ServerGamePacketListenerImpl ParseResults parseResults = this.server.getCommands().getDispatcher().parse(stringReader, this.player.createCommandSourceStack()); // Paper start - Handle non-recoverable exceptions if (!parseResults.getExceptions().isEmpty() @@ -34,7 +34,7 @@ index a63ade75461b68a780c56bfb5ff7c61f99f76744..fe7d68f3947bf55a389c73ef301fae8e && parseResults.getExceptions().values().stream().anyMatch(e -> e instanceof io.papermc.paper.brigadier.TagParseCommandSyntaxException)) { this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); return; -@@ -2629,6 +2630,7 @@ public class ServerGamePacketListenerImpl +@@ -2631,6 +2632,7 @@ public class ServerGamePacketListenerImpl // this.chatSpamThrottler.increment(); if (!this.chatSpamThrottler.isIncrementAndUnderThreshold() // CraftBukkit end @@ -42,7 +42,7 @@ index a63ade75461b68a780c56bfb5ff7c61f99f76744..fe7d68f3947bf55a389c73ef301fae8e && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause & add proper async disconnect -@@ -3328,7 +3330,7 @@ public class ServerGamePacketListenerImpl +@@ -3330,7 +3332,7 @@ public class ServerGamePacketListenerImpl public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { // Paper start - auto recipe limit if (!org.bukkit.Bukkit.isPrimaryThread()) { diff --git a/divinemc-server/minecraft-patches/features/0034-Option-to-disable-saving-of-snowball-and-firework.patch b/divinemc-server/minecraft-patches/features/0024-Option-to-disable-saving-of-snowball-and-firework.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0034-Option-to-disable-saving-of-snowball-and-firework.patch rename to divinemc-server/minecraft-patches/features/0024-Option-to-disable-saving-of-snowball-and-firework.patch diff --git a/divinemc-server/minecraft-patches/features/0025-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch b/divinemc-server/minecraft-patches/features/0025-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch deleted file mode 100644 index 879c556..0000000 --- a/divinemc-server/minecraft-patches/features/0025-Carpet-Fixes-Fix-Slime-Block-Bounce-Logic.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 03:04:04 +0300 -Subject: [PATCH] Carpet-Fixes: Fix Slime Block Bounce Logic - -This patch is based on the following mixins: -* "carpetfixes/mixins/blockFixes/SlimeBlock_incorrectLogicMixin.java" -By: fxmorin <28154542+fxmorin@users.noreply.github.com> -As part of: carpet-fixes (https://github.com/fxmorin/carpet-fixes) -Licensed under: MIT (https://opensource.org/licenses/MIT) - -Patch description: -Fixes incorrect logic in the slimeblock bounce code which prevents some entities from bouncing. -This bug in the slime code is due to onGround reversing the velocity, the best way to fix this issue is by -setting onGround to true, only once the Y velocity is smaller than -0.15 - -diff --git a/net/minecraft/world/level/block/SlimeBlock.java b/net/minecraft/world/level/block/SlimeBlock.java -index f26c3100d0aad0227f016bfa4c86ac647e13485a..59c9e63e6d5634973cc4927eac479463cc486a4a 100644 ---- a/net/minecraft/world/level/block/SlimeBlock.java -+++ b/net/minecraft/world/level/block/SlimeBlock.java -@@ -42,6 +42,7 @@ public class SlimeBlock extends HalfTransparentBlock { - Vec3 deltaMovement = entity.getDeltaMovement(); - if (deltaMovement.y < 0.0) { - double d = entity instanceof LivingEntity ? 1.0 : 0.8; -+ if (org.bxteam.divinemc.config.DivineConfig.FixesCategory.fixIncorrectBounceLogic) entity.setOnGround(deltaMovement.y > -0.15); // DivineMC - Carpet-Fixes: Fix Slime Block Bounce Logic - entity.setDeltaMovement(deltaMovement.x, -deltaMovement.y * d, deltaMovement.z); - } - } diff --git a/divinemc-server/minecraft-patches/features/0035-Snowball-and-Egg-knockback.patch b/divinemc-server/minecraft-patches/features/0025-Snowball-and-Egg-knockback.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0035-Snowball-and-Egg-knockback.patch rename to divinemc-server/minecraft-patches/features/0025-Snowball-and-Egg-knockback.patch diff --git a/divinemc-server/minecraft-patches/features/0036-Optimize-suffocation.patch b/divinemc-server/minecraft-patches/features/0026-Optimize-suffocation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0036-Optimize-suffocation.patch rename to divinemc-server/minecraft-patches/features/0026-Optimize-suffocation.patch diff --git a/divinemc-server/minecraft-patches/features/0037-Reduce-chunk-loading-lookups.patch b/divinemc-server/minecraft-patches/features/0027-Reduce-chunk-loading-lookups.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0037-Reduce-chunk-loading-lookups.patch rename to divinemc-server/minecraft-patches/features/0027-Reduce-chunk-loading-lookups.patch diff --git a/divinemc-server/minecraft-patches/features/0038-Configurable-movement-speed-for-entities.patch b/divinemc-server/minecraft-patches/features/0028-Configurable-movement-speed-for-entities.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0038-Configurable-movement-speed-for-entities.patch rename to divinemc-server/minecraft-patches/features/0028-Configurable-movement-speed-for-entities.patch diff --git a/divinemc-server/minecraft-patches/features/0040-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch b/divinemc-server/minecraft-patches/features/0029-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0040-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch rename to divinemc-server/minecraft-patches/features/0029-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch diff --git a/divinemc-server/minecraft-patches/features/0041-Option-to-allow-weird-movement-and-disable-teleporti.patch b/divinemc-server/minecraft-patches/features/0030-Option-to-allow-weird-movement-and-disable-teleporti.patch similarity index 94% rename from divinemc-server/minecraft-patches/features/0041-Option-to-allow-weird-movement-and-disable-teleporti.patch rename to divinemc-server/minecraft-patches/features/0030-Option-to-allow-weird-movement-and-disable-teleporti.patch index bbe95e9..bbbd9d9 100644 --- a/divinemc-server/minecraft-patches/features/0041-Option-to-allow-weird-movement-and-disable-teleporti.patch +++ b/divinemc-server/minecraft-patches/features/0030-Option-to-allow-weird-movement-and-disable-teleporti.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Option to allow weird movement and disable teleporting diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index fe7d68f3947bf55a389c73ef301fae8e396bf1da..39b95d3736d5acd3b71675410469727be6405cd3 100644 +index 637c5ca0c004e5de66bc3f84dba5fee47f729579..1bd6368704665f90eaa621366b4dec21bc937a96 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -607,7 +607,7 @@ public class ServerGamePacketListenerImpl +@@ -609,7 +609,7 @@ public class ServerGamePacketListenerImpl return; } // Paper end - Prevent moving into unloaded chunks @@ -18,7 +18,7 @@ index fe7d68f3947bf55a389c73ef301fae8e396bf1da..39b95d3736d5acd3b71675410469727b // CraftBukkit end LOGGER.warn( "{} (vehicle of {}) moved too quickly! {},{},{}", rootVehicle.getName().getString(), this.player.getName().getString(), d3, d4, d5 -@@ -637,7 +637,7 @@ public class ServerGamePacketListenerImpl +@@ -639,7 +639,7 @@ public class ServerGamePacketListenerImpl d5 = d2 - rootVehicle.getZ(); d7 = d3 * d3 + d4 * d4 + d5 * d5; boolean flag1 = false; @@ -27,7 +27,7 @@ index fe7d68f3947bf55a389c73ef301fae8e396bf1da..39b95d3736d5acd3b71675410469727b flag1 = true; // Paper - diff on change, this should be moved wrongly LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7)); } -@@ -1555,20 +1555,24 @@ public class ServerGamePacketListenerImpl +@@ -1557,20 +1557,24 @@ public class ServerGamePacketListenerImpl if (this.shouldCheckPlayerMovement(isFallFlying)) { float f2 = isFallFlying ? 300.0F : 100.0F; if (d7 - d6 > Math.max(f2, Mth.square(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed))) { @@ -63,7 +63,7 @@ index fe7d68f3947bf55a389c73ef301fae8e396bf1da..39b95d3736d5acd3b71675410469727b } } } -@@ -1629,6 +1633,7 @@ public class ServerGamePacketListenerImpl +@@ -1631,6 +1635,7 @@ public class ServerGamePacketListenerImpl d7 = d3 * d3 + d4 * d4 + d5 * d5; boolean movedWrongly = false; // Paper - Add fail move event; rename if (!this.player.isChangingDimension() diff --git a/divinemc-server/minecraft-patches/features/0042-Optimize-Raids.patch b/divinemc-server/minecraft-patches/features/0031-Optimize-Raids.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0042-Optimize-Raids.patch rename to divinemc-server/minecraft-patches/features/0031-Optimize-Raids.patch diff --git a/divinemc-server/minecraft-patches/features/0044-Small-optimization-to-LinearPalette.patch b/divinemc-server/minecraft-patches/features/0032-Small-optimization-to-LinearPalette.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0044-Small-optimization-to-LinearPalette.patch rename to divinemc-server/minecraft-patches/features/0032-Small-optimization-to-LinearPalette.patch diff --git a/divinemc-server/minecraft-patches/features/0045-Use-switch-for-VarInt-write.patch b/divinemc-server/minecraft-patches/features/0033-Use-switch-for-VarInt-write.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0045-Use-switch-for-VarInt-write.patch rename to divinemc-server/minecraft-patches/features/0033-Use-switch-for-VarInt-write.patch diff --git a/divinemc-server/minecraft-patches/features/0046-Optimize-Fluids.patch b/divinemc-server/minecraft-patches/features/0034-Optimize-Fluids.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0046-Optimize-Fluids.patch rename to divinemc-server/minecraft-patches/features/0034-Optimize-Fluids.patch diff --git a/divinemc-server/minecraft-patches/features/0047-Optimize-Structure-Generation.patch b/divinemc-server/minecraft-patches/features/0035-Optimize-Structure-Generation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0047-Optimize-Structure-Generation.patch rename to divinemc-server/minecraft-patches/features/0035-Optimize-Structure-Generation.patch diff --git a/divinemc-server/minecraft-patches/features/0048-Implement-NoChatReports.patch b/divinemc-server/minecraft-patches/features/0036-Implement-NoChatReports.patch similarity index 99% rename from divinemc-server/minecraft-patches/features/0048-Implement-NoChatReports.patch rename to divinemc-server/minecraft-patches/features/0036-Implement-NoChatReports.patch index 16db10b..2dee144 100644 --- a/divinemc-server/minecraft-patches/features/0048-Implement-NoChatReports.patch +++ b/divinemc-server/minecraft-patches/features/0036-Implement-NoChatReports.patch @@ -287,7 +287,7 @@ index 667ef5b2ab50eeb0491f7fe0bc8913ec29a4603a..a7c4fad2b1cb0cbac742a18d37d688bb if (packet == null || this.processedDisconnect) { // Spigot return; diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 7ed75ef10e3d4504cebb0ad544e05d9544642c9e..3165fd57f8f04251f220716beab49f6f43736eeb 100644 +index 2db120cd68447a4adc6f4ed6334fa52b8b55effc..84250c9786f4886fe4ab2e42808f8162da3f45d8 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java @@ -276,7 +276,7 @@ public abstract class PlayerList { @@ -299,7 +299,7 @@ index 7ed75ef10e3d4504cebb0ad544e05d9544642c9e..3165fd57f8f04251f220716beab49f6f ) ); player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit -@@ -1332,6 +1332,7 @@ public abstract class PlayerList { +@@ -1333,6 +1333,7 @@ public abstract class PlayerList { } public boolean verifyChatTrusted(PlayerChatMessage message) { diff --git a/divinemc-server/minecraft-patches/features/0049-Lag-compensation.patch b/divinemc-server/minecraft-patches/features/0037-Lag-compensation.patch similarity index 99% rename from divinemc-server/minecraft-patches/features/0049-Lag-compensation.patch rename to divinemc-server/minecraft-patches/features/0037-Lag-compensation.patch index 3e277d2..7c746cb 100644 --- a/divinemc-server/minecraft-patches/features/0049-Lag-compensation.patch +++ b/divinemc-server/minecraft-patches/features/0037-Lag-compensation.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Lag compensation diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 141c19eb290080f762da1e2090dae0609f2e3575..5a7cb4cffa218a17300c74ee4d95b08b705324ea 100644 +index 824f9200b66639ad1e3e821c8ae2ea4c66fe0b30..dd88e4d0f72a482e4feea38bc194fc16799adf02 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -288,6 +288,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop(), new com.google.common.util.concurrent.ThreadFactoryBuilder() diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 5a7cb4cffa218a17300c74ee4d95b08b705324ea..4a53105e46e338a52bc5ad22d51688a9a261d9e5 100644 +index dd88e4d0f72a482e4feea38bc194fc16799adf02..2baa4dc93bcc448ce65bae50ca39d41e562e2211 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -2640,8 +2640,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Mon, 7 Jul 2025 03:44:35 +0300 -Subject: [PATCH] SparklyPaper: Reset dirty flag when loading maps from the - disk - -Original project: https://github.com/SparklyPower/SparklyPaper - -Patch description: - -By default, the server will start rewriting all map datas to the disk after loading it, even if the map didn't have any changes -This also slows down world saving a lot if you have a lot of maps - -diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -index 7bbeed6c998c91e68376d3f17a510d68e3cd0b27..ebb0b7e5047efa65e8b6986f12dd5a7d6c0e9613 100644 ---- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -160,6 +160,7 @@ public class MapItemSavedData extends SavedData { - } - - this.vanillaRender.buffer = colors.array(); // Paper - Use Vanilla map renderer when possible -+ this.setDirty(false); // DivineMC - SparklyPaper: Reset dirty flag when loading maps from the disk - } - - public static MapItemSavedData createFresh( diff --git a/divinemc-server/minecraft-patches/features/0052-Command-block-parse-results-caching.patch b/divinemc-server/minecraft-patches/features/0040-Command-block-parse-results-caching.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0052-Command-block-parse-results-caching.patch rename to divinemc-server/minecraft-patches/features/0040-Command-block-parse-results-caching.patch diff --git a/divinemc-server/minecraft-patches/features/0053-Player-ProfileResult-caching.patch b/divinemc-server/minecraft-patches/features/0041-Player-ProfileResult-caching.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0053-Player-ProfileResult-caching.patch rename to divinemc-server/minecraft-patches/features/0041-Player-ProfileResult-caching.patch diff --git a/divinemc-server/minecraft-patches/features/0054-Implement-Secure-Seed.patch b/divinemc-server/minecraft-patches/features/0042-Implement-Secure-Seed.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0054-Implement-Secure-Seed.patch rename to divinemc-server/minecraft-patches/features/0042-Implement-Secure-Seed.patch diff --git a/divinemc-server/minecraft-patches/features/0055-Dynamic-Activation-of-Brain.patch b/divinemc-server/minecraft-patches/features/0043-Dynamic-Activation-of-Brain.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0055-Dynamic-Activation-of-Brain.patch rename to divinemc-server/minecraft-patches/features/0043-Dynamic-Activation-of-Brain.patch diff --git a/divinemc-server/minecraft-patches/features/0043-SparklyPaper-Optimize-canSee-checks.patch b/divinemc-server/minecraft-patches/features/0043-SparklyPaper-Optimize-canSee-checks.patch deleted file mode 100644 index c0914ed..0000000 --- a/divinemc-server/minecraft-patches/features/0043-SparklyPaper-Optimize-canSee-checks.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 1 Feb 2025 19:52:39 +0300 -Subject: [PATCH] SparklyPaper: Optimize "canSee" checks - -Original project: https://github.com/SparklyPower/SparklyPaper - -Patch description: - -The "canSee" checks is in a hot path, invoked by each entity for each player on the server if they are in tracking range, so optimizing it is pretty nice -First, we change the original "HashMap" to fastutil's "Object2ObjectOpenHashMap", because the containsKey throughput is better -Then, we add a "isEmpty()" check before attempting to check if the map contains something -This seems stupid, but it does seem that it improves the performance a bit, and it makes sense, "containsKey(...)" does not attempt to check the map size before attempting to check if the map contains the key -We also create a "canSee" method tailored for "ChunkMap#updatePlayer()", a method without the equals check (the "updatePlayer()" already checks if the entity is the same entity) because the CraftPlayer's `equals()` check is a *bit* expensive compared to only checking the object's identity, and because the identity has already been check, we don't need to check it twice. - -diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index edda52a8430386238be4963e8ea2406f0c2d4df3..c0d996fb99f053863ce623889add3feb70d7137d 100644 ---- a/net/minecraft/server/level/ChunkMap.java -+++ b/net/minecraft/server/level/ChunkMap.java -@@ -1295,7 +1295,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); - // Paper end - Configurable entity tracking range by Y - // CraftBukkit start - respect vanish API -- if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits -+ if (flag && !player.getBukkitEntity().canSeeChunkMapUpdatePlayer(this.entity.getBukkitEntity())) { // Paper - only consider hits // DivineMC - SparklyPaper: Optimize "canSee" checks - flag = false; - } - // CraftBukkit end diff --git a/divinemc-server/minecraft-patches/features/0056-Petal-Async-Pathfinding.patch b/divinemc-server/minecraft-patches/features/0044-Petal-Async-Pathfinding.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0056-Petal-Async-Pathfinding.patch rename to divinemc-server/minecraft-patches/features/0044-Petal-Async-Pathfinding.patch diff --git a/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch b/divinemc-server/minecraft-patches/features/0045-Petal-Multithreaded-Tracker.patch similarity index 99% rename from divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch rename to divinemc-server/minecraft-patches/features/0045-Petal-Multithreaded-Tracker.patch index d02c5b8..755b962 100644 --- a/divinemc-server/minecraft-patches/features/0057-Petal-Multithreaded-Tracker.patch +++ b/divinemc-server/minecraft-patches/features/0045-Petal-Multithreaded-Tracker.patch @@ -399,10 +399,10 @@ index 78bf3365b426e7090182af84630111d410a2460e..3c1795eb56900cd80cfec38bd1d922d5 } } diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 253eb728773ab09023e8db56bb6382d9e21a96b3..42ab4f50d07539aafba120e863d5b9cfc5a436e8 100644 +index 7b10fe7cf66757ed68f9e39e03259700dfabf184..c537d22fd97225c1b6d58bed61add83a20d9be24 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1934,7 +1934,6 @@ public class ServerGamePacketListenerImpl +@@ -1936,7 +1936,6 @@ public class ServerGamePacketListenerImpl } public void internalTeleport(PositionMoveRotation posMoveRotation, Set relatives) { diff --git a/divinemc-server/minecraft-patches/features/0058-Pufferfish-Optimize-mob-spawning.patch b/divinemc-server/minecraft-patches/features/0046-Pufferfish-Optimize-mob-spawning.patch similarity index 99% rename from divinemc-server/minecraft-patches/features/0058-Pufferfish-Optimize-mob-spawning.patch rename to divinemc-server/minecraft-patches/features/0046-Pufferfish-Optimize-mob-spawning.patch index e925976..d4c7b76 100644 --- a/divinemc-server/minecraft-patches/features/0058-Pufferfish-Optimize-mob-spawning.patch +++ b/divinemc-server/minecraft-patches/features/0046-Pufferfish-Optimize-mob-spawning.patch @@ -9,7 +9,7 @@ Original project: https://github.com/pufferfish-gg/Pufferfish This patch reduces the main-thread impact of mob spawning by moving spawning work to other threads diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 4a53105e46e338a52bc5ad22d51688a9a261d9e5..9bd7cc58cf10489f0e463347cdc2bc537f0509ec 100644 +index 2baa4dc93bcc448ce65bae50ca39d41e562e2211..a0cad0bdb8245b19f4ff983245d61d7b237a4042 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -289,6 +289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop states = new java.util.ArrayList<>(level.capturedBlockStates.values()); level.capturedBlockStates.clear(); diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 951199cb015694790ea8d81264779a7d294ab6ef..85f0abc2ead2d78a7189abaac8f803b70328a21b 100644 +index a0cad0bdb8245b19f4ff983245d61d7b237a4042..c56fa00f9443b6a3a44f0b89da9dcfb6a4faf1c8 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -290,6 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop= 0 && i <= maxSize) { diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index b6cfd764273a2102525a66955ab2217071d0154d..0ccfbee593fc16073484b1d4ed9458406b8cce50 100644 +index 008530bf0f09180ba365fc514b51d22630564de2..7bc07d120ca3b8cffa6b1147f1687b5a4023b709 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -1788,6 +1788,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Sun, 6 Jul 2025 01:49:27 +0300 -Subject: [PATCH] Parchment: Make FixLight use action bar - -Original license: GPLv3 -Original project: https://github.com/ProjectEdenGG/Parchment - -diff --git a/io/papermc/paper/command/subcommands/FixLightCommand.java b/io/papermc/paper/command/subcommands/FixLightCommand.java -index 85950a1aa732ab8c01ad28bec9e0de140e1a172e..fbc38577599dd0e606e2d225ce98943ab49e74f7 100644 --- a/io/papermc/paper/command/subcommands/FixLightCommand.java +++ b/io/papermc/paper/command/subcommands/FixLightCommand.java -@@ -95,17 +95,23 @@ public final class FixLightCommand implements PaperSubcommand { +@@ -95,17 +_,23 @@ ((StarLightLightingProvider)lightengine).starlight$serverRelightChunks(chunks, (final ChunkPos chunkPos) -> { ++relitChunks[0]; diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch index 949f7c4..cfe26cd 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -1,5 +1,19 @@ --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java +@@ -989,6 +_,13 @@ + if (this.hasStopped) return; + this.hasStopped = true; + } ++ // DivineMC start - Respawn players that were dead on server restart ++ for (ServerPlayer player : this.playerList.players) { ++ if (player.isDeadOrDying() || (player.isRemoved() && player.getRemovalReason() == net.minecraft.world.entity.Entity.RemovalReason.KILLED)) { ++ this.playerList.respawn(player, false, net.minecraft.world.entity.Entity.RemovalReason.KILLED, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.DEATH); ++ } ++ } ++ // DivineMC end - Respawn players that were dead on server restart + if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging + shutdownThread = Thread.currentThread(); // Paper - Improved watchdog support + org.spigotmc.WatchdogThread.doStop(); // Paper - Improved watchdog support @@ -1080,6 +_,7 @@ // Paper end - rewrite chunk system // Paper start - Improved watchdog support - move final shutdown items here diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch new file mode 100644 index 0000000..567cd83 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/server/level/ChunkMap.java ++++ b/net/minecraft/server/level/ChunkMap.java +@@ -1302,7 +_,7 @@ + flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); + // Paper end - Configurable entity tracking range by Y + // CraftBukkit start - respect vanish API +- if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits ++ if (flag && !player.getBukkitEntity().canSeeChunkMapUpdatePlayer(this.entity.getBukkitEntity())) { // Paper - only consider hits // DivineMC - SparklyPaper: Optimize "canSee" checks + flag = false; + } + // CraftBukkit end diff --git a/divinemc-server/minecraft-patches/features/0074-Leaves-Syncmatica-Protocol.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch similarity index 67% rename from divinemc-server/minecraft-patches/features/0074-Leaves-Syncmatica-Protocol.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 6acc478..11d79d4 100644 --- a/divinemc-server/minecraft-patches/features/0074-Leaves-Syncmatica-Protocol.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -1,16 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Thu, 10 Jul 2025 22:17:00 +0300 -Subject: [PATCH] Leaves: Syncmatica Protocol - -Original project: https://github.com/LeavesMC/Leaves -Original license: GPLv3 - -diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index e8fd78e2898931f65e783ad46b5b73ce3fbde235..75d9d06066c750ac9a176adc021410f1265cd36f 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -313,6 +313,7 @@ public class ServerGamePacketListenerImpl +@@ -313,6 +_,7 @@ private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper - Limit client sign length private final io.papermc.paper.event.packet.ClientTickEndEvent tickEndEvent; // Paper - add client tick end event public final io.papermc.paper.connection.PaperPlayerGameConnection playerGameConnection; // Paper @@ -18,7 +8,7 @@ index e8fd78e2898931f65e783ad46b5b73ce3fbde235..75d9d06066c750ac9a176adc021410f1 public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie cookie) { super(server, connection, cookie); -@@ -324,6 +325,7 @@ public class ServerGamePacketListenerImpl +@@ -324,6 +_,7 @@ this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat this.tickEndEvent = new io.papermc.paper.event.packet.ClientTickEndEvent(player.getBukkitEntity()); // Paper - add client tick end event this.playerGameConnection = new io.papermc.paper.connection.PaperPlayerGameConnection(this); // Paper diff --git a/divinemc-server/minecraft-patches/features/0019-Don-t-respond-ping-before-start-fully.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch similarity index 66% rename from divinemc-server/minecraft-patches/features/0019-Don-t-respond-ping-before-start-fully.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch index c48b23c..8db46a9 100644 --- a/divinemc-server/minecraft-patches/features/0019-Don-t-respond-ping-before-start-fully.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch @@ -1,15 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:48:57 +0300 -Subject: [PATCH] Don't respond ping before start fully - -This is rewritten Purpur patch, to make this configurable - -diff --git a/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/net/minecraft/server/network/ServerStatusPacketListenerImpl.java -index 1b966dc52b067cd9d1fa9f500b692e3f75f1cc90..ff4857522fc9bd5cdd01e3d0161418eef88886fc 100644 --- a/net/minecraft/server/network/ServerStatusPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerStatusPacketListenerImpl.java -@@ -37,7 +37,10 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene +@@ -37,7 +_,10 @@ } else { this.hasRequestedStatus = true; // this.connection.send(new ClientboundStatusResponsePacket(this.status)); // Paper diff --git a/divinemc-server/minecraft-patches/features/0073-Leaves-Xaero-s-Map-Protocol.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch similarity index 59% rename from divinemc-server/minecraft-patches/features/0073-Leaves-Xaero-s-Map-Protocol.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch index eff7fd8..614157e 100644 --- a/divinemc-server/minecraft-patches/features/0073-Leaves-Xaero-s-Map-Protocol.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -1,16 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Thu, 10 Jul 2025 22:15:39 +0300 -Subject: [PATCH] Leaves: Xaero's Map Protocol - -Original project: https://github.com/LeavesMC/Leaves -Original license: GPLv3 - -diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index a695a3152dbc72f1b20c713574763455b2569e1c..96af2c75b526c59510965665da0b2ca00bf657b3 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -1172,6 +1172,7 @@ public abstract class PlayerList { +@@ -1143,6 +_,7 @@ player.connection.send(new ClientboundInitializeBorderPacket(worldBorder)); player.connection.send(new ClientboundSetTimePacket(level.getGameTime(), level.getDayTime(), level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getSharedSpawnPos(), level.getSharedSpawnAngle())); diff --git a/divinemc-server/minecraft-patches/features/0013-SparklyPaper-Clear-dirty-stats-after-copying.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch similarity index 59% rename from divinemc-server/minecraft-patches/features/0013-SparklyPaper-Clear-dirty-stats-after-copying.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch index 68a3fe9..e2245e0 100644 --- a/divinemc-server/minecraft-patches/features/0013-SparklyPaper-Clear-dirty-stats-after-copying.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch @@ -1,15 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:10:59 +0300 -Subject: [PATCH] SparklyPaper: Clear dirty stats after copying - -Original project: https://github.com/SparklyPower/SparklyPaper - -diff --git a/net/minecraft/stats/ServerStatsCounter.java b/net/minecraft/stats/ServerStatsCounter.java -index 16e06085ed3c0f6a0b35c730b63b75824f44a905..b2d8f5d146ec10d34a4e71cbfc975fb68e5a8d04 100644 --- a/net/minecraft/stats/ServerStatsCounter.java +++ b/net/minecraft/stats/ServerStatsCounter.java -@@ -98,12 +98,6 @@ public class ServerStatsCounter extends StatsCounter { +@@ -98,12 +_,6 @@ this.dirty.add(stat); } @@ -22,7 +13,7 @@ index 16e06085ed3c0f6a0b35c730b63b75824f44a905..b2d8f5d146ec10d34a4e71cbfc975fb6 public void parseLocal(DataFixer fixerUpper, String json) { try { JsonElement jsonElement = StrictJsonParser.parse(json); -@@ -139,10 +133,12 @@ public class ServerStatsCounter extends StatsCounter { +@@ -139,9 +_,11 @@ public void sendStats(ServerPlayer player) { Object2IntMap> map = new Object2IntOpenHashMap<>(); @@ -30,9 +21,8 @@ index 16e06085ed3c0f6a0b35c730b63b75824f44a905..b2d8f5d146ec10d34a4e71cbfc975fb6 + for (Stat stat : this.dirty) { // DivineMC - SparklyPaper: Skip dirty stats copy when requesting player stats map.put(stat, this.getValue(stat)); } - -+ this.dirty.clear(); // DivineMC - SparklyPaper: Clear dirty stats after copying + ++ this.dirty.clear(); // DivineMC - SparklyPaper: Clear dirty stats after copying + player.connection.send(new ClientboundAwardStatsPacket(map)); } - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch index 61cf3bd..4175c94 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -16,6 +16,14 @@ final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity // Paper start - detailed watchdog information ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); +@@ -4219,6 +_,7 @@ + } + + public boolean canTeleport(Level fromLevel, Level toLevel) { ++ if (!fromLevel.divineConfig.allowEntityPortalWithPassenger && (this.isPassenger() || this.isVehicle())) return false; // DivineMC - Allow entity teleport with passenger + if (!this.isAlive() || !this.valid) return false; // Paper - Fix item duplication and teleport issues + if (fromLevel.dimension() == Level.END && toLevel.dimension() == Level.OVERWORLD) { + for (Entity entity : this.getPassengers()) { @@ -4448,6 +_,7 @@ } diff --git a/divinemc-server/minecraft-patches/features/0012-Re-Fix-MC-117075.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch similarity index 74% rename from divinemc-server/minecraft-patches/features/0012-Re-Fix-MC-117075.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch index 003704e..5432eec 100644 --- a/divinemc-server/minecraft-patches/features/0012-Re-Fix-MC-117075.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch @@ -1,14 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 1 Feb 2025 19:43:42 +0300 -Subject: [PATCH] Re-Fix MC-117075 - - -diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 9625213b7c1295b813071dbedea5366510c7072f..bf38e3bfcb0b96c4529d5e535893043512f52b02 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -104,7 +104,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -106,7 +_,7 @@ public static final int TICKS_PER_DAY = 24000; public static final int MAX_ENTITY_SPAWN_Y = 20000000; public static final int MIN_ENTITY_SPAWN_Y = -20000000; @@ -17,7 +9,7 @@ index 9625213b7c1295b813071dbedea5366510c7072f..bf38e3bfcb0b96c4529d5e5358930435 protected final NeighborUpdater neighborUpdater; private final List pendingBlockEntityTickers = Lists.newArrayList(); private boolean tickingBlockEntities; -@@ -1510,13 +1510,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1501,13 +_,11 @@ boolean runsNormally = this.tickRateManager().runsNormally(); int tickedEntities = 0; // Paper - rewrite chunk system @@ -32,7 +24,7 @@ index 9625213b7c1295b813071dbedea5366510c7072f..bf38e3bfcb0b96c4529d5e5358930435 } else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) { tickingBlockEntity.tick(); // Paper start - rewrite chunk system -@@ -1526,7 +1524,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1517,7 +_,7 @@ // Paper end - rewrite chunk system } } @@ -40,4 +32,4 @@ index 9625213b7c1295b813071dbedea5366510c7072f..bf38e3bfcb0b96c4529d5e5358930435 + this.blockEntityTickers.removeMarkedEntries(); // DivineMC - optimize block entity removals - Fix MC-117075 this.tickingBlockEntities = false; - this.spigotConfig.currentPrimedTnt = 0; // Spigot + profilerFiller.pop(); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/SlimeBlock.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/SlimeBlock.java.patch new file mode 100644 index 0000000..07460b9 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/SlimeBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/SlimeBlock.java ++++ b/net/minecraft/world/level/block/SlimeBlock.java +@@ -42,6 +_,7 @@ + Vec3 deltaMovement = entity.getDeltaMovement(); + if (deltaMovement.y < 0.0) { + double d = entity instanceof LivingEntity ? 1.0 : 0.8; ++ if (org.bxteam.divinemc.config.DivineConfig.FixesCategory.fixIncorrectBounceLogic) entity.setOnGround(deltaMovement.y > -0.15); // DivineMC - Carpet-Fixes: Fix Slime Block Bounce Logic + entity.setDeltaMovement(deltaMovement.x, -deltaMovement.y * d, deltaMovement.z); + } + } diff --git a/divinemc-server/minecraft-patches/features/0022-Configurable-MC-59471.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch similarity index 76% rename from divinemc-server/minecraft-patches/features/0022-Configurable-MC-59471.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch index c6d5cfc..4e2c08c 100644 --- a/divinemc-server/minecraft-patches/features/0022-Configurable-MC-59471.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch @@ -1,17 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Wed, 5 Mar 2025 18:08:25 +0300 -Subject: [PATCH] Configurable MC-59471 - -Bring back MC-59471, MC-129055 on 1.21.2+, which fixed in 1.21.2 snapshots 24w33a and 24w36a - -P.S: This setting is different from skip-tripwire-hook-placement-validation in Paper - -diff --git a/net/minecraft/world/level/block/TripWireHookBlock.java b/net/minecraft/world/level/block/TripWireHookBlock.java -index 8a3a8b0fdf9545a41501dc992c6982d9c8ce7b66..52fa81fdce9d7998f4c2d3b90dfc08391218f7fd 100644 --- a/net/minecraft/world/level/block/TripWireHookBlock.java +++ b/net/minecraft/world/level/block/TripWireHookBlock.java -@@ -187,7 +187,6 @@ public class TripWireHookBlock extends Block { +@@ -187,7 +_,6 @@ if (!cancelledEmitterHook) { // Paper - Call BlockRedstoneEvent emitState(level, pos, flag2, flag3, flag, flag1); if (!attaching) { @@ -19,7 +8,7 @@ index 8a3a8b0fdf9545a41501dc992c6982d9c8ce7b66..52fa81fdce9d7998f4c2d3b90dfc0839 level.setBlock(pos, blockState1.setValue(FACING, direction), 3); if (shouldNotifyNeighbours) { notifyNeighbors(block, level, pos, direction); -@@ -200,10 +199,18 @@ public class TripWireHookBlock extends Block { +@@ -200,10 +_,18 @@ BlockPos blockPos1 = pos.relative(direction, i2); BlockState blockState2 = blockStates[i2]; if (blockState2 != null) { diff --git a/divinemc-server/minecraft-patches/features/0029-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch similarity index 59% rename from divinemc-server/minecraft-patches/features/0029-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch index a98f5f5..032fe81 100644 --- a/divinemc-server/minecraft-patches/features/0029-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch @@ -1,16 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 12 Apr 2025 17:40:53 +0300 -Subject: [PATCH] SparklyPaper: Allow throttling hopper checks if the target - container is full - -Original project: https://github.com/SparklyPower/SparklyPaper - -diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index 800b7e78ae989868ed0b9e060c80dcd002759412..3c9843979baff7ed419d4ae2124d7ccf47b95b5b 100644 --- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java +++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java -@@ -423,6 +423,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -423,6 +_,11 @@ } else { Direction opposite = blockEntity.facing.getOpposite(); if (isFullContainer(attachedContainer, opposite)) { diff --git a/divinemc-server/minecraft-patches/features/0018-Optimize-block-state-lookup.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch similarity index 63% rename from divinemc-server/minecraft-patches/features/0018-Optimize-block-state-lookup.patch rename to divinemc-server/minecraft-patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch index b64344c..564feb3 100644 --- a/divinemc-server/minecraft-patches/features/0018-Optimize-block-state-lookup.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch @@ -1,24 +1,18 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 6 Jul 2025 02:47:58 +0300 -Subject: [PATCH] Optimize block state lookup - - -diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index b88254fb3c12b99684c6ede1ae8a6671ffbe9ad6..dbb4142ea38cdf484e74c81103cebb024ae8813d 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -270,11 +270,18 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -272,11 +_,18 @@ public BlockState getBlockStateFinal(final int x, final int y, final int z) { // Copied and modified from below final int sectionIndex = this.getSectionIndex(y); - if (sectionIndex < 0 || sectionIndex >= this.sections.length - || this.sections[sectionIndex].nonEmptyBlockCount == 0) { +- return Blocks.AIR.defaultBlockState(); +- } +- return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15); + // DivineMC start - Optimize block state lookup + if (sectionIndex < 0 || sectionIndex >= this.sections.length) { - return Blocks.AIR.defaultBlockState(); - } -- return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15); ++ return Blocks.AIR.defaultBlockState(); ++ } + + final LevelChunkSection section = this.sections[sectionIndex]; + if (section.nonEmptyBlockCount == 0) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch new file mode 100644 index 0000000..df5c780 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java ++++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +@@ -160,6 +_,7 @@ + } + + this.vanillaRender.buffer = colors.array(); // Paper - Use Vanilla map renderer when possible ++ this.setDirty(false); // DivineMC - SparklyPaper: Reset dirty flag when loading maps from the disk + } + + public static MapItemSavedData createFresh( diff --git a/divinemc-server/paper-patches/features/0001-Rebrand.patch b/divinemc-server/paper-patches/features/0001-Rebrand.patch index 3272a05..e43dfab 100644 --- a/divinemc-server/paper-patches/features/0001-Rebrand.patch +++ b/divinemc-server/paper-patches/features/0001-Rebrand.patch @@ -231,25 +231,10 @@ index 62e2d5704c348955bc8284dc2d54c933b7bcdd06..341f13e57896f03058ea3ec68e69b7cb public void executeAsync(final Runnable runnable) { MCUtil.scheduleAsyncTask(this.catching(runnable, "asynchronous")); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 748bd9650da4a209743b7a5dde584b2e19c5a578..7e90142cb65937103aa99fd011540086449c45c8 100644 +index 748bd9650da4a209743b7a5dde584b2e19c5a578..3a4239d6f5768f7e2b6025477670dd2eb9f8cbc4 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -1,14 +1,8 @@ - package org.bukkit.craftbukkit; - - import java.io.File; --import java.io.IOException; - import java.text.SimpleDateFormat; --import java.util.Calendar; --import java.util.Date; --import java.util.logging.Level; --import java.util.logging.Logger; - import joptsimple.OptionParser; --import joptsimple.OptionSet; - import joptsimple.util.PathConverter; - - import static java.util.Arrays.asList; -@@ -24,7 +18,7 @@ public class Main { +@@ -24,7 +24,7 @@ public class Main { } // Paper end - Reset loggers after shutdown @@ -258,7 +243,7 @@ index 748bd9650da4a209743b7a5dde584b2e19c5a578..7e90142cb65937103aa99fd011540086 if (System.getProperty("jdk.nio.maxCachedBufferSize") == null) System.setProperty("jdk.nio.maxCachedBufferSize", "262144"); // Paper - cap per-thread NIO cache size; https://www.evanjones.ca/java-bytebuffer-leak.html OptionParser parser = new OptionParser() { { -@@ -180,77 +174,6 @@ public class Main { +@@ -180,77 +180,6 @@ public class Main { } }; diff --git a/divinemc-server/paper-patches/features/0002-Configuration.patch b/divinemc-server/paper-patches/features/0002-Configuration.patch index ff40032..19f5613 100644 --- a/divinemc-server/paper-patches/features/0002-Configuration.patch +++ b/divinemc-server/paper-patches/features/0002-Configuration.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Configuration diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 592e8a4c04ef5acda9fdfd1405d8ff4952396ada..c8c7fa0304e8eaf0d444fc0c9a36c00bb27ccc71 100644 +index 53702f1e87e143a6b4260a21c858643746814146..906865cdb2ddde3d9e018cd9cca0fa3bdcc9b4d8 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1060,6 +1060,7 @@ public final class CraftServer implements Server { @@ -31,10 +31,10 @@ index 592e8a4c04ef5acda9fdfd1405d8ff4952396ada..c8c7fa0304e8eaf0d444fc0c9a36c00b Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 7e90142cb65937103aa99fd011540086449c45c8..7653ba0259ddc930dc4e2af84636641d3dba6e7f 100644 +index 3a4239d6f5768f7e2b6025477670dd2eb9f8cbc4..0838fcfaa950300f7a394295509be86cab824f99 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -166,6 +166,14 @@ public class Main { +@@ -172,6 +172,14 @@ public class Main { .describedAs("Yml file"); // Purpur end - Purpur config files diff --git a/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch b/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch index dfe2382..9b23a97 100644 --- a/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch +++ b/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch @@ -30,10 +30,10 @@ index 70413fddd23ca1165cb5090cce4fddcb1bbca93f..ae70b84e6473fa2ed94416bf4bef8849 @SuppressWarnings("unchecked") java.util.List files = ((java.util.List) optionSet.valuesOf("add-plugin")).stream().map(File::toPath).toList(); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 7653ba0259ddc930dc4e2af84636641d3dba6e7f..1a3a5e8a9119af8ed9d13a61bc5dc7b3ee0b7a65 100644 +index 0838fcfaa950300f7a394295509be86cab824f99..d9bf383c9cb4fedcea84044f7db0da68b05fab76 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -174,6 +174,14 @@ public class Main { +@@ -180,6 +180,14 @@ public class Main { .describedAs("Yml file"); // DivineMC end - Configuration diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java index b182414..bb12442 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/DivineBootstrap.java @@ -66,9 +66,10 @@ public class DivineBootstrap { SharedConstants.tryDetectVersion(); getStartupVersionMessages().forEach(LOGGER::info); } catch (Throwable t) { - t.printStackTrace(); + LOGGER.error("Failed to initialize the server", t); } } + return options; } diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java index b6c094c..0e1cb86 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/region/type/BufferedRegionFile.java @@ -37,6 +37,7 @@ import java.util.Set; *

For conversion tools between MCA and buffered region file formats, see: * LinearRegionFileFormatTools */ +@SuppressWarnings({"unused", "FieldMayBeFinal"}) public class BufferedRegionFile implements IRegionFile { private static final double AUTO_COMPACT_PERCENT = 3.0 / 5.0; // 60% private static final long AUTO_COMPACT_SIZE = 1024 * 1024; // 1 MiB @@ -751,7 +752,7 @@ public class BufferedRegionFile implements IRegionFile { } } - private class Sector{ + private class Sector { private final int index; private long offset; private long length; From e6f2fb48e557047e86f8f9fb6b9f42387877f1e3 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 20 Jul 2025 16:12:09 +0300 Subject: [PATCH 61/67] Fire ServerListPingEvent for secondary motd send --- ...rverListPingEvent-for-secondary-motd.patch | 32 ++++++++++++ ...rverListPingEvent-for-secondary-motd.patch | 50 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 divinemc-server/minecraft-patches/features/0067-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch create mode 100644 divinemc-server/paper-patches/features/0020-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch diff --git a/divinemc-server/minecraft-patches/features/0067-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch b/divinemc-server/minecraft-patches/features/0067-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch new file mode 100644 index 0000000..992853c --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0067-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 20 Jul 2025 16:09:38 +0300 +Subject: [PATCH] Paper PR: Fire ServerListPingEvent for secondary motd send + +Original license: GPLv3 +Original project: https://github.com/PaperMC/Paper +Paper pull request: https://github.com/PaperMC/Paper/pull/8074 + +diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java +index b59078273bb6214295a448d5607538557d7eb1ee..c097afcdece95e33486c833063dc2aed159d93f7 100644 +--- a/net/minecraft/server/players/PlayerList.java ++++ b/net/minecraft/server/players/PlayerList.java +@@ -304,10 +304,15 @@ public abstract class PlayerList { + mutableComponent.withStyle(ChatFormatting.YELLOW); + Component joinMessage = mutableComponent; // Paper - Adventure + serverGamePacketListenerImpl.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); +- ServerStatus status = this.server.getStatus(); +- if (status != null && !cookie.transferred()) { +- player.sendServerStatus(status); ++ // DivineMC start - Paper PR: Fire ServerListPingEvent for secondary motd send ++ if (!cookie.transferred()) { ++ io.papermc.paper.util.MCUtil.scheduleAsyncTask(() -> { ++ if (player.hasDisconnected()) return; ++ net.minecraft.network.protocol.status.ServerStatus status = com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.getEventResponse(this.server, player.connection.connection); ++ if (status != null) player.sendServerStatus(status); ++ }); + } ++ // DivineMC end - Paper PR: Fire ServerListPingEvent for secondary motd send + + // player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players)); // CraftBukkit - replaced with loop below + this.players.add(player); diff --git a/divinemc-server/paper-patches/features/0020-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch b/divinemc-server/paper-patches/features/0020-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch new file mode 100644 index 0000000..e89431b --- /dev/null +++ b/divinemc-server/paper-patches/features/0020-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Sun, 20 Jul 2025 16:10:25 +0300 +Subject: [PATCH] Paper PR: Fire ServerListPingEvent for secondary motd send + +Original license: GPLv3 +Original project: https://github.com/PaperMC/Paper +Paper pull request: https://github.com/PaperMC/Paper/pull/8074 + +diff --git a/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java +index 30a19d10869f73d67b794e8e4c035bc5c10209e6..95acdc0e849c4bb36bab33ee8bc9a9d4e8667829 100644 +--- a/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java ++++ b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java +@@ -64,13 +64,24 @@ public final class StandardPaperServerListPingEventImpl extends PaperServerListP + } + + public static void processRequest(MinecraftServer server, Connection networkManager) { ++ // DivineMC start - Paper PR: Fire ServerListPingEvent for secondary motd send ++ ServerStatus ping = getEventResponse(server, networkManager); ++ if (ping == null) { ++ networkManager.disconnect((Component) null); ++ return; ++ } ++ ++ networkManager.send(new ClientboundStatusResponsePacket(ping)); ++ } ++ ++ public static ServerStatus getEventResponse(MinecraftServer server, Connection networkManager) { ++ // DivineMC end - Paper PR: Fire ServerListPingEvent for secondary motd send + StandardPaperServerListPingEventImpl event = new StandardPaperServerListPingEventImpl(server, networkManager, server.getStatus()); + server.server.getPluginManager().callEvent(event); + + // Close connection immediately if event is cancelled + if (event.isCancelled()) { +- networkManager.disconnect((Component) null); +- return; ++ return null; // DivineMC - Paper PR: Fire ServerListPingEvent for secondary motd send + } + + // Setup response +@@ -98,8 +109,6 @@ public final class StandardPaperServerListPingEventImpl extends PaperServerListP + } + final ServerStatus ping = new ServerStatus(description, players, Optional.of(version), favicon, server.enforceSecureProfile()); + +- // Send response +- networkManager.send(new ClientboundStatusResponsePacket(ping)); ++ return ping; // DivineMC - Paper PR: Fire ServerListPingEvent for secondary motd send + } +- + } From 9952017a762522ddbf755c98f35992fc41c079bd Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 20 Jul 2025 17:19:24 +0300 Subject: [PATCH 62/67] Don't use snapshots for acquiring blockstate --- .../world/level/block/entity/BlockEntity.java.patch | 11 +++++++++++ .../bukkit/craftbukkit/block/CraftBlock.java.patch | 11 +++++++++++ .../craftbukkit/block/CraftBlockStates.java.patch | 11 +++++++++++ .../java/org/bxteam/divinemc/config/DivineConfig.java | 4 ++++ 4 files changed, 37 insertions(+) create mode 100644 divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch create mode 100644 divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java.patch create mode 100644 divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java.patch diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch new file mode 100644 index 0000000..e8548e3 --- /dev/null +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/entity/BlockEntity.java ++++ b/net/minecraft/world/level/block/entity/BlockEntity.java +@@ -386,7 +_,7 @@ + + // CraftBukkit start - add method + public org.bukkit.inventory.InventoryHolder getOwner() { +- return getOwner(true); ++ return getOwner(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.createSnapshotOnRetrievingBlockState); // DivineMC - EMC: Don't use snapshots for acquiring blockstate + } + + public org.bukkit.inventory.InventoryHolder getOwner(boolean useSnapshot) { diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java.patch new file mode 100644 index 0000000..3e6e3d4 --- /dev/null +++ b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -332,7 +_,7 @@ + + @Override + public BlockState getState() { +- return CraftBlockStates.getBlockState(this); ++ return CraftBlockStates.getBlockState(this, org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.createSnapshotOnRetrievingBlockState); // DivineMC - EMC: Don't use snapshots for acquiring blockstate + } + + // Paper start diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java.patch new file mode 100644 index 0000000..054d95e --- /dev/null +++ b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +@@ -185,7 +_,7 @@ + } + + public static BlockState getBlockState(Block block) { +- return CraftBlockStates.getBlockState(block, true); ++ return CraftBlockStates.getBlockState(block, org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.createSnapshotOnRetrievingBlockState); // DivineMC - EMC: Don't use snapshots for acquiring blockstate + } + + public static BlockState getBlockState(Block block, boolean useSnapshot) { diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index 3bff625..c4ff9ef 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -389,6 +389,7 @@ public class DivineConfig { public static boolean sheepOptimization = true; public static boolean optimizedDragonRespawn = false; public static boolean reduceChuckLoadAndLookup = true; + public static boolean createSnapshotOnRetrievingBlockState = true; public static boolean hopperThrottleWhenFull = false; public static int hopperThrottleSkipTicks = 0; @@ -484,6 +485,9 @@ public class DivineConfig { "When enabled, improving performance and reducing lag during the dragon’s resurrection event."); reduceChuckLoadAndLookup = getBoolean(ConfigCategory.PERFORMANCE.key("optimizations.reduce-chunk-load-and-lookup"), reduceChuckLoadAndLookup, "If enabled, optimizes chunk loading and block state lookups by reducing the number of chunk accesses required during operations such as Enderman teleportation."); + createSnapshotOnRetrievingBlockState = getBoolean(ConfigCategory.PERFORMANCE.key("optimizations.create-snapshot-on-retrieving-block-state"), createSnapshotOnRetrievingBlockState, + "Whether to create a snapshot (copy) of BlockState data when plugins retrieve them.", + "If false, plugins get direct BlockState access for better performance but risk data corruption from poor plugin design."); hopperThrottleWhenFull = getBoolean(ConfigCategory.PERFORMANCE.key("optimizations.hopper-throttle-when-full.enabled"), hopperThrottleWhenFull, "When enabled, hoppers will throttle if target container is full."); From e0e76be411b0feba9db9bd5eefefb06da6b8002f Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 20 Jul 2025 17:28:12 +0300 Subject: [PATCH 63/67] remove useless methods --- .../bxteam/divinemc/config/DivineConfig.java | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java index c4ff9ef..931ee95 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/config/DivineConfig.java @@ -7,8 +7,6 @@ import net.minecraft.world.entity.EntityType; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.MemoryConfiguration; import org.bxteam.divinemc.config.annotations.Experimental; import org.bxteam.divinemc.async.pathfinding.PathfindTaskRejectPolicy; import org.bxteam.divinemc.region.EnumRegionFileExtension; @@ -30,7 +28,7 @@ import java.util.List; import java.util.Locale; import java.util.Random; -@SuppressWarnings({"unused", "SameParameterValue"}) +@SuppressWarnings({"SameParameterValue", "ConstantValue", "DataFlowIssue"}) public class DivineConfig { private static final String HEADER = """ This is the main configuration file for DivineMC. @@ -47,22 +45,6 @@ public class DivineConfig { private static File configFile; public static final YamlFile config = new YamlFile(); - private static ConfigurationSection convertToBukkit(org.simpleyaml.configuration.ConfigurationSection section) { - ConfigurationSection newSection = new MemoryConfiguration(); - for (String key : section.getKeys(false)) { - if (section.isConfigurationSection(key)) { - newSection.set(key, convertToBukkit(section.getConfigurationSection(key))); - } else { - newSection.set(key, section.get(key)); - } - } - return newSection; - } - - public static ConfigurationSection getConfigCopy() { - return convertToBukkit(config); - } - public static void init(File configFile) { try { long begin = System.nanoTime(); From 156b3bd7cf61ddd70ece7788d6b3cfb03341dab8 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 20 Jul 2025 18:01:15 +0300 Subject: [PATCH 64/67] update simd impl --- .../pufferfish/simd/SIMDChecker.java | 25 +++++++++++-------- .../pufferfish/simd/SIMDDetection.java | 13 ++++++---- .../features/0002-Configuration.patch | 6 ++--- ...-SparklyPaper-Parallel-world-ticking.patch | 4 +-- .../dedicated/DedicatedServer.java.patch | 10 ++++---- 5 files changed, 33 insertions(+), 25 deletions(-) diff --git a/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java index 9c428a7..84fb183 100644 --- a/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java +++ b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java @@ -1,22 +1,24 @@ package gg.pufferfish.pufferfish.simd; -import org.slf4j.Logger; -import jdk.incubator.vector.FloatVector; -import jdk.incubator.vector.IntVector; import jdk.incubator.vector.VectorSpecies; +import org.slf4j.Logger; -@Deprecated public class SIMDChecker { - public static boolean canEnable(Logger logger) { + private final VectorSpecies ISPEC; + private final VectorSpecies FSPEC; + + public SIMDChecker(VectorSpecies ISPEC, VectorSpecies FSPEC) { + this.ISPEC = ISPEC; + this.FSPEC = FSPEC; + } + + public boolean canEnable(Logger logger) { try { - if (SIMDDetection.getJavaVersion() < 17) { + if ((SIMDDetection.getJavaVersion() < SIMDDetection.MIN_JAVA_VERSION || SIMDDetection.getJavaVersion() > SIMDDetection.MAX_JAVA_VERSION)) { return false; } else { SIMDDetection.testRun = true; - VectorSpecies ISPEC = IntVector.SPECIES_PREFERRED; - VectorSpecies FSPEC = FloatVector.SPECIES_PREFERRED; - logger.info("Max SIMD vector size on this system is {} bits (int)", ISPEC.vectorBitSize()); logger.info("Max SIMD vector size on this system is {} bits (float)", FSPEC.vectorBitSize()); @@ -27,7 +29,10 @@ public class SIMDChecker { return true; } - } catch (NoClassDefFoundError | Exception ignored) {} // Basically, we don't do anything. This lets us detect if it's not functional and disable it. + } catch (NoClassDefFoundError | Exception ignored) { + // Basically, we don't do anything. This lets us detect if it's not functional and disable it. + } + return false; } } diff --git a/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java index 026617f..eed53db 100644 --- a/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java +++ b/divinemc-api/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java @@ -1,27 +1,30 @@ package gg.pufferfish.pufferfish.simd; +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.IntVector; import org.slf4j.Logger; -@Deprecated public class SIMDDetection { public static boolean isEnabled = false; public static boolean versionLimited = false; public static boolean testRun = false; - @Deprecated + public static final int MAX_JAVA_VERSION = 25; + public static final int MIN_JAVA_VERSION = 21; + public static boolean canEnable(Logger logger) { try { - return SIMDChecker.canEnable(logger); + SIMDChecker checker = new SIMDChecker(IntVector.SPECIES_PREFERRED, FloatVector.SPECIES_PREFERRED); + return checker.canEnable(logger); } catch (NoClassDefFoundError | Exception ignored) { return false; } } - @Deprecated public static int getJavaVersion() { // https://stackoverflow.com/a/2591122 String version = System.getProperty("java.version"); - if(version.startsWith("1.")) { + if (version.startsWith("1.")) { version = version.substring(2, 3); } else { int dot = version.indexOf("."); diff --git a/divinemc-server/minecraft-patches/features/0002-Configuration.patch b/divinemc-server/minecraft-patches/features/0002-Configuration.patch index fe4f162..013460a 100644 --- a/divinemc-server/minecraft-patches/features/0002-Configuration.patch +++ b/divinemc-server/minecraft-patches/features/0002-Configuration.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Configuration diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 512eeef7a770fa8264acbe4194a0debb23f8c3c1..80d04f4eb5122d571409a50f5921c3403dacf31f 100644 +index 536a3da1d87e1d4087977196c5766f6550a95e47..bbe93d1861541991215d32186eec82fa8602fea2 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java @@ -162,6 +162,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @@ -24,9 +24,9 @@ index 512eeef7a770fa8264acbe4194a0debb23f8c3c1..80d04f4eb5122d571409a50f5921c340 + org.bxteam.divinemc.command.DivineCommands.registerCommands(this); // DivineMC - Configuration com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now - // DivineMC start - Pufferfish SIMD + // DivineMC start - Pufferfish: SIMD Support diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index dccfd0f30111316c9c82004358c2a7051cbd5cdb..1ad419b4a2ad4610a0a8d18b26665a7ec0ccc960 100644 +index 848f936a26429d844ad439ca336dbcb8d81f09e8..2c60b1c8ecb54c4c9526a2b2f6e6698b77359065 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -161,6 +161,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl diff --git a/divinemc-server/minecraft-patches/features/0050-SparklyPaper-Parallel-world-ticking.patch b/divinemc-server/minecraft-patches/features/0050-SparklyPaper-Parallel-world-ticking.patch index eefe374..301216d 100644 --- a/divinemc-server/minecraft-patches/features/0050-SparklyPaper-Parallel-world-ticking.patch +++ b/divinemc-server/minecraft-patches/features/0050-SparklyPaper-Parallel-world-ticking.patch @@ -333,12 +333,12 @@ index 3836d60ce84fb26f30a609486a5755d3fd1c94f1..1aab02441e4dfa7703963855d77bb918 } } else if (this.visible.remove(advancementHolder)) { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index dcd004749846aa9e650be438b0f097e414c2ec76..5a2b9632a1e46b512a1379923765c1b8a28250b9 100644 +index 46adbe6ccf1e4291e33a52a6612f624558c18f96..374abd7e1502edefb78cd6451a36c3b8ad6d8f8f 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java @@ -218,6 +218,13 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface } - // DivineMC end - Pufferfish SIMD + // DivineMC end - Pufferfish: SIMD Support + // DivineMC start - Parallel world ticking + if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableParallelWorldTicking) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch index 34470f9..9ca57ed 100644 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch +++ b/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -4,25 +4,25 @@ // Purpur end - Purpur config files com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now -+ // DivineMC start - Pufferfish SIMD ++ // DivineMC start - Pufferfish: SIMD Support + try { + gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled = gg.pufferfish.pufferfish.simd.SIMDDetection.canEnable(LOGGER); -+ gg.pufferfish.pufferfish.simd.SIMDDetection.versionLimited = gg.pufferfish.pufferfish.simd.SIMDDetection.getJavaVersion() < 17 || gg.pufferfish.pufferfish.simd.SIMDDetection.getJavaVersion() > 21; -+ } catch (NoClassDefFoundError | Exception ignored) { ++ gg.pufferfish.pufferfish.simd.SIMDDetection.versionLimited = gg.pufferfish.pufferfish.simd.SIMDDetection.getJavaVersion() < gg.pufferfish.pufferfish.simd.SIMDDetection.MIN_JAVA_VERSION || gg.pufferfish.pufferfish.simd.SIMDDetection.getJavaVersion() > gg.pufferfish.pufferfish.simd.SIMDDetection.MAX_JAVA_VERSION; ++ } catch (final NoClassDefFoundError | Exception ignored) { + ignored.printStackTrace(); + } + + if (gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled) { + LOGGER.info("SIMD operations detected as functional. Will replace some operations with faster versions."); + } else if (gg.pufferfish.pufferfish.simd.SIMDDetection.versionLimited) { -+ LOGGER.warn("Will not enable SIMD! These optimizations are only safely supported on Java 17 and higher."); ++ LOGGER.warn("Will not enable SIMD! These optimizations are only safely supported on Java {}-{}", gg.pufferfish.pufferfish.simd.SIMDDetection.MIN_JAVA_VERSION, gg.pufferfish.pufferfish.simd.SIMDDetection.MAX_JAVA_VERSION); + } else { + LOGGER.warn("SIMD operations are available for your server, but are not configured!"); + LOGGER.warn("To enable additional optimizations, add \"--add-modules=jdk.incubator.vector\" to your startup flags, BEFORE the \"-jar\"."); + LOGGER.warn("If you have already added this flag, then SIMD operations are not supported on your JVM or CPU."); + LOGGER.warn("Debug: Java: {}, test run: {}", System.getProperty("java.version"), gg.pufferfish.pufferfish.simd.SIMDDetection.testRun); + } -+ // DivineMC end - Pufferfish SIMD ++ // DivineMC end - Pufferfish: SIMD Support + this.setPvpAllowed(properties.pvp); this.setFlightAllowed(properties.allowFlight); From e1069714c6ec51b97126536bc6108518cdb91779 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 20 Jul 2025 20:15:35 +0300 Subject: [PATCH 65/67] update varint patch --- ...33-Optimize-VarInt-and-VarLong-write.patch | 213 ++++++++++++++++++ .../0033-Use-switch-for-VarInt-write.patch | 68 ------ 2 files changed, 213 insertions(+), 68 deletions(-) create mode 100644 divinemc-server/minecraft-patches/features/0033-Optimize-VarInt-and-VarLong-write.patch delete mode 100644 divinemc-server/minecraft-patches/features/0033-Use-switch-for-VarInt-write.patch diff --git a/divinemc-server/minecraft-patches/features/0033-Optimize-VarInt-and-VarLong-write.patch b/divinemc-server/minecraft-patches/features/0033-Optimize-VarInt-and-VarLong-write.patch new file mode 100644 index 0000000..1ead46e --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0033-Optimize-VarInt-and-VarLong-write.patch @@ -0,0 +1,213 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Wed, 9 Jul 2025 02:08:35 +0300 +Subject: [PATCH] Optimize VarInt and VarLong write + +This patch is based on the following commit: +"Reapply "Optimize varint writing"" +By: Andrew Steinborn +As part of: Velocity (https://github.com/PaperMC/Velocity) +Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) + +diff --git a/net/minecraft/network/VarInt.java b/net/minecraft/network/VarInt.java +index 4897ff4648083ebe737ae5b32bae344af27357e4..e138b64c4b09d83e5f38d7421fc23e9cc5e5d5a7 100644 +--- a/net/minecraft/network/VarInt.java ++++ b/net/minecraft/network/VarInt.java +@@ -50,28 +50,45 @@ public class VarInt { + return i; + } + +- public static ByteBuf write(ByteBuf buffer, int value) { +- // Paper start - Optimize VarInts +- // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes +- // that the proxy will write, to improve inlining. +- if ((value & (0xFFFFFFFF << 7)) == 0) { +- buffer.writeByte(value); +- } else if ((value & (0xFFFFFFFF << 14)) == 0) { +- int w = (value & 0x7F | 0x80) << 8 | (value >>> 7); +- buffer.writeShort(w); +- } else { +- writeOld(buffer, value); +- } +- return buffer; +- } +- public static ByteBuf writeOld(ByteBuf buffer, int value) { +- // Paper end - Optimize VarInts +- while ((value & -128) != 0) { +- buffer.writeByte(value & 127 | 128); +- value >>>= 7; ++ // DivineMC start - Optimize VarInt ++ public static ByteBuf write(ByteBuf buffer, int value) { ++ int bytesNeeded = getByteSize(value); ++ ++ switch (bytesNeeded) { ++ case 1: ++ buffer.writeByte(value); ++ break; ++ case 2: ++ int w2 = ((value & 0x7F) << 8) | (value >>> 7) | 0x00008000; ++ buffer.writeShort(w2); ++ break; ++ case 3: ++ int w3 = (value & 0x7F) << 16 ++ | (value & 0x3F80) << 1 ++ | (value >>> 14) ++ | 0x00808000; ++ buffer.writeMedium(w3); ++ break; ++ case 4: ++ int w4 = (value & 0x7F) << 24 ++ | ((value & 0x3F80) << 9) ++ | (value & 0x1FC000) >> 6 ++ | (value >>> 21) ++ | 0x80808000; ++ buffer.writeInt(w4); ++ break; ++ case 5: ++ int w5 = (value & 0x7F) << 24 ++ | (value & 0x3F80) << 9 ++ | (value & 0x1FC000) >> 6 ++ | ((value >>> 21) & 0x7F) ++ | 0x80808080; ++ buffer.writeInt(w5); ++ buffer.writeByte(value >>> 28); ++ break; + } + +- buffer.writeByte(value); + return buffer; + } ++ // DivineMC end - Optimize VarInt + } +diff --git a/net/minecraft/network/VarLong.java b/net/minecraft/network/VarLong.java +index df9a85b19a9767c85f02837af6835f7ddb6c7dc3..77f090bc1b9225dd5a61d8c57c902fcdea8ed7cd 100644 +--- a/net/minecraft/network/VarLong.java ++++ b/net/minecraft/network/VarLong.java +@@ -38,13 +38,122 @@ public class VarLong { + return l; + } + ++ // DivineMC start - Optimize VarLong + public static ByteBuf write(ByteBuf buffer, long value) { +- while ((value & -128L) != 0L) { +- buffer.writeByte((int)(value & 127L) | 128); +- value >>>= 7; ++ if ((value & 0xFFFFFFFFFFFFFF80L) == 0) { ++ buffer.writeByte((int) value); ++ } else if (value < 0) { ++ int least7bits = (int) (value & 0xFFFFFFFL); ++ int w = (least7bits & 0x7F) << 24 ++ | (least7bits & 0x3F80) << 9 ++ | (least7bits & 0x1FC000) >> 6 ++ | ((least7bits >>> 21) & 0x7F) ++ | 0x80808080; ++ long nonLeast7Bits = value >>> 28; ++ int secondLeast7bits = (int) (nonLeast7Bits & 0xFFFFFFFL); ++ int w2 = (secondLeast7bits & 0x7F) << 24 ++ | ((secondLeast7bits & 0x3F80) << 9) ++ | (secondLeast7bits & 0x1FC000) >> 6 ++ | (secondLeast7bits >>> 21) ++ | 0x80808080; ++ int thirdLeast7Bits = (int) (nonLeast7Bits >>> 28); ++ int w3 = (thirdLeast7Bits & 0x7F) << 8 ++ | (thirdLeast7Bits >>> 7) ++ | 0x00008000; ++ buffer.writeInt(w); ++ buffer.writeInt(w2); ++ buffer.writeShort(w3); ++ } else if ((value & 0xFFFFFFFFFFFFC000L) == 0) { ++ int least7bits = (int) value; ++ int w = (least7bits & 0x7F) << 8 ++ | (least7bits >>> 7) ++ | 0x00008000; ++ buffer.writeShort(w); ++ } else if ((value & 0xFFFFFFFFFFE00000L) == 0) { ++ int least7bits = (int) value; ++ int w = (least7bits & 0x7F) << 16 ++ | (least7bits & 0x3F80) << 1 ++ | (least7bits >>> 14) ++ | 0x00808000; ++ buffer.writeMedium(w); ++ } else if ((value & 0xFFFFFFFFF0000000L) == 0) { ++ int least7bits = (int) value; ++ int w = (least7bits & 0x7F) << 24 ++ | ((least7bits & 0x3F80) << 9) ++ | (least7bits & 0x1FC000) >> 6 ++ | (least7bits >>> 21) ++ | 0x80808000; ++ buffer.writeInt(w); ++ } else if ((value & 0xFFFFFFF800000000L) == 0) { ++ int least7bits = (int) (value & 0xFFFFFFFL); ++ int w = (least7bits & 0x7F) << 24 ++ | (least7bits & 0x3F80) << 9 ++ | (least7bits & 0x1FC000) >> 6 ++ | ((least7bits >>> 21) & 0x7F) ++ | 0x80808080; ++ buffer.writeInt(w); ++ buffer.writeByte((int) (value >>> 28)); ++ } else if ((value & 0xFFFFFC0000000000L) == 0) { ++ int least7bits = (int) (value & 0xFFFFFFFL); ++ int w = (least7bits & 0x7F) << 24 ++ | (least7bits & 0x3F80) << 9 ++ | (least7bits & 0x1FC000) >> 6 ++ | ((least7bits >>> 21) & 0x7F) ++ | 0x80808080; ++ int secondLeast7bits = (int) (value >>> 28); ++ int w2 = (secondLeast7bits & 0x7F) << 8 ++ | (secondLeast7bits >>> 7) ++ | 0x00008000; ++ buffer.writeInt(w); ++ buffer.writeShort(w2); ++ } else if ((value & 0xFFFE000000000000L) == 0) { ++ int least7bits = (int) (value & 0xFFFFFFFL); ++ int w = (least7bits & 0x7F) << 24 ++ | (least7bits & 0x3F80) << 9 ++ | (least7bits & 0x1FC000) >> 6 ++ | ((least7bits >>> 21) & 0x7F) ++ | 0x80808080; ++ int secondLeast7bits = (int) (value >>> 28); ++ int w2 = (secondLeast7bits & 0x7F) << 16 ++ | (secondLeast7bits & 0x3F80) << 1 ++ | (secondLeast7bits >>> 14) ++ | 0x00808000; ++ buffer.writeInt(w); ++ buffer.writeMedium(w2); ++ } else if ((value & 0xFF00000000000000L) == 0) { ++ int least7bits = (int) (value & 0xFFFFFFFL); ++ int w = (least7bits & 0x7F) << 24 ++ | (least7bits & 0x3F80) << 9 ++ | (least7bits & 0x1FC000) >> 6 ++ | ((least7bits >>> 21) & 0x7F) ++ | 0x80808080; ++ int secondLeast7bits = (int) (value >>> 28); ++ int w2 = (secondLeast7bits & 0x7F) << 24 ++ | ((secondLeast7bits & 0x3F80) << 9) ++ | (secondLeast7bits & 0x1FC000) >> 6 ++ | (secondLeast7bits >>> 21) ++ | 0x80808000; ++ buffer.writeInt(w); ++ buffer.writeInt(w2); ++ } else { ++ int least7bits = (int) (value & 0xFFFFFFFL); ++ int w = (least7bits & 0x7F) << 24 ++ | (least7bits & 0x3F80) << 9 ++ | (least7bits & 0x1FC000) >> 6 ++ | ((least7bits >>> 21) & 0x7F) ++ | 0x80808080; ++ long nonLeast7Bits = value >>> 28; ++ int secondLeast7bits = (int) (nonLeast7Bits & 0xFFFFFFFL); ++ int w2 = (secondLeast7bits & 0x7F) << 24 ++ | ((secondLeast7bits & 0x3F80) << 9) ++ | (secondLeast7bits & 0x1FC000) >> 6 ++ | (secondLeast7bits >>> 21) ++ | 0x80808080; ++ buffer.writeInt(w); ++ buffer.writeInt(w2); ++ buffer.writeByte((int) (nonLeast7Bits >>> 28)); + } +- +- buffer.writeByte((int)value); + return buffer; + } ++ // DivineMC end - Optimize VarLong + } diff --git a/divinemc-server/minecraft-patches/features/0033-Use-switch-for-VarInt-write.patch b/divinemc-server/minecraft-patches/features/0033-Use-switch-for-VarInt-write.patch deleted file mode 100644 index 6421a49..0000000 --- a/divinemc-server/minecraft-patches/features/0033-Use-switch-for-VarInt-write.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Wed, 9 Jul 2025 02:08:35 +0300 -Subject: [PATCH] Use switch for VarInt#write - - -diff --git a/net/minecraft/network/VarInt.java b/net/minecraft/network/VarInt.java -index 4897ff4648083ebe737ae5b32bae344af27357e4..dddabc57f5415077b905cb59c5b47db1a621807f 100644 ---- a/net/minecraft/network/VarInt.java -+++ b/net/minecraft/network/VarInt.java -@@ -51,21 +51,46 @@ public class VarInt { - } - - public static ByteBuf write(ByteBuf buffer, int value) { -- // Paper start - Optimize VarInts -- // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes -- // that the proxy will write, to improve inlining. -- if ((value & (0xFFFFFFFF << 7)) == 0) { -- buffer.writeByte(value); -- } else if ((value & (0xFFFFFFFF << 14)) == 0) { -- int w = (value & 0x7F | 0x80) << 8 | (value >>> 7); -- buffer.writeShort(w); -- } else { -- writeOld(buffer, value); -+ // DivineMC start - Use switch for VarInt#write -+ int bytesNeeded = getByteSize(value); -+ -+ switch (bytesNeeded) { -+ case 1: -+ buffer.writeByte(value); -+ break; -+ case 2: -+ int w2 = ((value & 0x7F) << 8) | (value >>> 7) | 0x00008000; -+ buffer.writeShort(w2); -+ break; -+ case 3: -+ int w3 = (value & 0x7F) << 16 -+ | (value & 0x3F80) << 1 -+ | (value >>> 14) -+ | 0x00808000; -+ buffer.writeMedium(w3); -+ break; -+ case 4: -+ int w4 = (value & 0x7F) << 24 -+ | ((value & 0x3F80) << 9) -+ | (value & 0x1FC000) >> 6 -+ | (value >>> 21) -+ | 0x80808000; -+ buffer.writeInt(w4); -+ break; -+ case 5: -+ int w5 = (value & 0x7F) << 24 -+ | (value & 0x3F80) << 9 -+ | (value & 0x1FC000) >> 6 -+ | ((value >>> 21) & 0x7F) -+ | 0x80808080; -+ buffer.writeInt(w5); -+ buffer.writeByte(value >>> 28); -+ break; - } -+ // DivineMC end - Use switch for VarInt#write - return buffer; - } - public static ByteBuf writeOld(ByteBuf buffer, int value) { -- // Paper end - Optimize VarInts - while ((value & -128) != 0) { - buffer.writeByte(value & 127 | 128); - value >>>= 7; From 6a795e24cc473a156f1cdcc43b97b0374f5975e2 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sun, 20 Jul 2025 21:37:07 +0300 Subject: [PATCH 66/67] update spectator packet impl --- build-data/divinemc.at | 1 - ...-Do-not-send-spectator-change-packet.patch | 140 +++++++++++++----- 2 files changed, 107 insertions(+), 34 deletions(-) diff --git a/build-data/divinemc.at b/build-data/divinemc.at index fdbd156..dda3c44 100644 --- a/build-data/divinemc.at +++ b/build-data/divinemc.at @@ -6,7 +6,6 @@ private-f net.minecraft.world.level.levelgen.NoiseChunk$FlatCache noiseFiller private-f net.minecraft.world.level.levelgen.NoiseChunk$NoiseInterpolator noiseFiller private-f net.minecraft.world.level.levelgen.RandomState router private-f net.minecraft.world.level.levelgen.RandomState sampler -public net.minecraft.server.level.ServerPlayerGameMode gameModeForPlayer public net.minecraft.util.Mth SIN public net.minecraft.world.entity.ai.Brain sensors public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities lineOfSightTest diff --git a/divinemc-server/minecraft-patches/features/0066-Do-not-send-spectator-change-packet.patch b/divinemc-server/minecraft-patches/features/0066-Do-not-send-spectator-change-packet.patch index 6d27a4d..b589241 100644 --- a/divinemc-server/minecraft-patches/features/0066-Do-not-send-spectator-change-packet.patch +++ b/divinemc-server/minecraft-patches/features/0066-Do-not-send-spectator-change-packet.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Do not send spectator change packet diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java -index 6e7ed7451a45f4525946563617ccf0a55851449b..6a2f8a798f46b337d611c14556ab5ecc1f2584cd 100644 +index 6e7ed7451a45f4525946563617ccf0a55851449b..518d670d2f8535679d5d22cb1f15cb85e5bb50f0 100644 --- a/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -75,10 +75,18 @@ public class ServerPlayerGameMode { +@@ -75,10 +75,7 @@ public class ServerPlayerGameMode { // CraftBukkit end this.setGameModeForPlayer(gameModeForPlayer, this.gameModeForPlayer); // Paper - Fix MC-259571 this.player.onUpdateAbilities(); @@ -16,55 +16,129 @@ index 6e7ed7451a45f4525946563617ccf0a55851449b..6a2f8a798f46b337d611c14556ab5ecc - .getServer() - .getPlayerList() - .broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); // CraftBukkit -+ -+ // DivineMC start - Do not send spectator change packet -+ if (!org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket) { -+ this.level.getServer().getPlayerList().broadcastPlayerInfoWithoutSpectatorName(this.player); -+ } else { -+ this.level -+ .getServer() -+ .getPlayerList() -+ .broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); -+ } -+ // DivineMC end - Do not send spectator change packet -+ ++ this.sendGameModeUpdatePacket(gameModeForPlayer); // DivineMC - Do not send spectator change packet this.level.updateSleepingPlayerList(); if (gameModeForPlayer == GameType.CREATIVE) { this.player.resetCurrentImpulseContext(); +@@ -571,4 +568,17 @@ public class ServerPlayerGameMode { + return false; + } + // Purpur end - Shift right click to use exp for mending ++ ++ // DivineMC start - Do not send spectator change packet ++ private void sendGameModeUpdatePacket(GameType newGameMode) { ++ ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket( ++ ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player); ++ ++ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket || newGameMode != GameType.SPECTATOR) { ++ this.level.getServer().getPlayerList().broadcastAll(packet, this.player); ++ } else { ++ this.player.connection.send(packet); ++ } ++ } ++ // DivineMC end - Do not send spectator change packet + } diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 96af2c75b526c59510965665da0b2ca00bf657b3..b59078273bb6214295a448d5607538557d7eb1ee 100644 +index 96af2c75b526c59510965665da0b2ca00bf657b3..baa682c9ba48427edb10f5610a5a0a9e21da0581 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -1473,4 +1473,32 @@ public abstract class PlayerList { +@@ -359,6 +359,8 @@ public abstract class PlayerList { + // CraftBukkit start - sendAll above replaced with this loop + ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)); // Paper - Add Listing API for Player + ++ ClientboundPlayerInfoUpdatePacket modifiedPacket = this.createSpectatorFilteredPacket(packet); // DivineMC - Do not send spectator change packet ++ + final List onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - Use single player info update packet on join + for (int i = 0; i < this.players.size(); ++i) { + ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i); +@@ -367,7 +369,7 @@ public abstract class PlayerList { + // Paper start - Add Listing API for Player + if (entityplayer1.getBukkitEntity().isListed(bukkitPlayer)) { + // Paper end - Add Listing API for Player +- entityplayer1.connection.send(packet); ++ this.sendPlayerInfoPacket(entityplayer1, player, packet, modifiedPacket); // DivineMC - Do not send spectator change packet + // Paper start - Add Listing API for Player + } else { + entityplayer1.connection.send(ClientboundPlayerInfoUpdatePacket.createSinglePlayerInitializing(player, false)); +@@ -383,7 +385,10 @@ public abstract class PlayerList { + } + // Paper start - Use single player info update packet on join + if (!onlinePlayers.isEmpty()) { +- player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers, player)); // Paper - Add Listing API for Player ++ // DivineMC start - Do not send spectator change packet ++ ClientboundPlayerInfoUpdatePacket updatePacket = this.createFilteredPlayerListPacket(onlinePlayers, player); ++ player.connection.send(updatePacket); // Paper - Add Listing API for Player ++ // DivineMC end - Do not send spectator change packet + } + // Paper end - Use single player info update packet on join + player.sentListPacket = true; +@@ -1473,4 +1478,69 @@ public abstract class PlayerList { public boolean isAllowCommandsForAllPlayers() { return this.allowCommandsForAllPlayers; } + + // DivineMC start - Do not send spectator change packet -+ public void broadcastPlayerInfoWithoutSpectatorName(ServerPlayer player) { -+ net.minecraft.world.level.GameType displayMode = player.gameMode.getGameModeForPlayer() == net.minecraft.world.level.GameType.SPECTATOR ? net.minecraft.world.level.GameType.SURVIVAL : player.gameMode.getGameModeForPlayer(); ++ @Nullable ++ private ClientboundPlayerInfoUpdatePacket createSpectatorFilteredPacket(ClientboundPlayerInfoUpdatePacket originalPacket) { ++ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket) { ++ return null; ++ } + -+ for (ServerPlayer otherPlayer : this.players) { -+ if (otherPlayer != player && otherPlayer.getBukkitEntity().canSee(player.getBukkitEntity())) { -+ ClientboundPlayerInfoUpdatePacket packet = createPlayerInfoPacketWithoutSpectatorName(player, displayMode); -+ otherPlayer.connection.send(packet); -+ } ++ ClientboundPlayerInfoUpdatePacket.Entry entry = originalPacket.entries().getFirst(); ++ if (entry.gameMode() != net.minecraft.world.level.GameType.SPECTATOR) { ++ return null; ++ } ++ ++ ClientboundPlayerInfoUpdatePacket.Entry filteredEntry = new ClientboundPlayerInfoUpdatePacket.Entry( ++ entry.profileId(), ++ entry.profile(), ++ entry.listed(), ++ entry.latency(), ++ net.minecraft.world.level.GameType.SURVIVAL, ++ entry.displayName(), ++ entry.showHat(), ++ entry.listOrder(), ++ entry.chatSession()); ++ ++ return new ClientboundPlayerInfoUpdatePacket(originalPacket.actions(), List.of(filteredEntry)); ++ } ++ ++ private void sendPlayerInfoPacket(ServerPlayer receiver, ServerPlayer joiningPlayer, ++ ClientboundPlayerInfoUpdatePacket originalPacket, ++ @Nullable ClientboundPlayerInfoUpdatePacket filteredPacket) { ++ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket || ++ receiver == joiningPlayer || ++ filteredPacket == null) { ++ receiver.connection.send(originalPacket); ++ } else { ++ receiver.connection.send(filteredPacket); + } + } + -+ private ClientboundPlayerInfoUpdatePacket createPlayerInfoPacketWithoutSpectatorName(ServerPlayer player, net.minecraft.world.level.GameType displayMode) { -+ net.minecraft.world.level.GameType originalMode = player.gameMode.gameModeForPlayer; ++ private ClientboundPlayerInfoUpdatePacket createFilteredPlayerListPacket(List onlinePlayers, ServerPlayer joiningPlayer) { ++ ClientboundPlayerInfoUpdatePacket updatePacket = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers, joiningPlayer); + -+ player.gameMode.gameModeForPlayer = displayMode; ++ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket) { ++ return updatePacket; ++ } + -+ ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket( -+ ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, -+ player -+ ); ++ List newEntries = new java.util.ArrayList<>(); ++ for (ClientboundPlayerInfoUpdatePacket.Entry entry : updatePacket.entries()) { ++ ClientboundPlayerInfoUpdatePacket.Entry newEntry = new ClientboundPlayerInfoUpdatePacket.Entry( ++ entry.profileId(), ++ entry.profile(), ++ entry.listed(), ++ entry.latency(), ++ entry.gameMode() == net.minecraft.world.level.GameType.SPECTATOR ? ++ net.minecraft.world.level.GameType.SURVIVAL : entry.gameMode(), ++ entry.displayName(), ++ entry.showHat(), ++ entry.listOrder(), ++ entry.chatSession()); ++ newEntries.add(newEntry); ++ } + -+ player.gameMode.gameModeForPlayer = originalMode; -+ -+ return packet; ++ return new ClientboundPlayerInfoUpdatePacket(updatePacket.actions(), newEntries); + } + // DivineMC end - Do not send spectator change packet } From b56751aafcaa853eb5bcd4d77710ae96a4dc786c Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Mon, 21 Jul 2025 17:02:14 +0300 Subject: [PATCH 67/67] hide sentry dsn key in spark --- .../org/bxteam/divinemc/spark/DivineServerConfigProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/spark/DivineServerConfigProvider.java b/divinemc-server/src/main/java/org/bxteam/divinemc/spark/DivineServerConfigProvider.java index 40e642a..7773297 100644 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/spark/DivineServerConfigProvider.java +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/spark/DivineServerConfigProvider.java @@ -131,6 +131,7 @@ public class DivineServerConfigProvider extends ServerConfigProvider { .add("world-settings.*.seed-*") .add("feature-seeds") .add("seed-*") + .add("sentry.dsn") .addAll(getSystemPropertyList("spark.serverconfigs.hiddenpaths")); FILES = files.build();