From b39fa92d5dab99b0dbf0a1aa126ff7ac491447b1 Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Wed, 24 Nov 2021 23:47:39 -0800 Subject: [PATCH] even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even more patches --- ...2-Add-Raw-Byte-Entity-Serialization.patch} | 0 .../1.18}/0793-Fix-Codec-log-spam.patch | 0 ...rializing-mismatching-chunk-coordina.patch | 16 +- ...ze-NibbleArray-to-use-pooled-buffers.patch | 4 +- ...erver-load-chunks-from-newer-version.patch | 4 +- ...7-Add-Raw-Byte-Entity-Serialization.patch} | 7 +- ...28-Vanilla-command-permission-fixes.patch} | 0 ...-Make-CallbackExecutor-strict-again.patch} | 0 ...server-to-unload-chunks-at-request-.patch} | 0 ...logic-for-inventories-on-chunk-unlo.patch} | 0 ...e-recursion-for-chunkholder-updates.patch} | 0 ...ocking-from-state-access-in-UserCac.patch} | 0 ...hunks-refusing-to-unload-at-low-TPS.patch} | 0 ...et-level-changes-while-unloading-pl.patch} | 0 ...et-level-changes-when-updating-chun.patch} | 0 ...profile-lookups-to-worldgen-threads.patch} | 0 ...g-when-the-async-catcher-is-tripped.patch} | 0 ...tize-ResourceLocation-error-logging.patch} | 0 ...=> 0740-Optimise-general-POI-access.patch} | 0 ...rolled-flushing-for-network-manager.patch} | 0 ...tch => 0742-Add-more-async-catchers.patch} | 0 ...te-entity-bounding-box-lookup-calls.patch} | 4 +- ...> 0744-Execute-chunk-tasks-mid-tick.patch} | 0 ... => 0745-Do-not-copy-visible-chunks.patch} | 0 ...ulate-regionfile-header-if-it-is-co.patch} | 4 +- ...ementation-for-blockstate-state-loo.patch} | 0 ...-more-information-in-watchdog-dumps.patch} | 6 +- ...lly-inline-methods-in-BlockPosition.patch} | 0 ... 0750-Distance-manager-tick-timings.patch} | 0 ...ler-threads-according-to-the-plugin.patch} | 0 ...-getChunkAt-has-inlined-logic-for-l.patch} | 0 ...h => 0753-Add-packet-limiter-config.patch} | 0 ... 0754-Lag-compensate-block-breaking.patch} | 0 ...Stem-registry-when-loading-default-.patch} | 0 ...our-chunk-data-off-disk-when-conver.patch} | 0 ...sh-calls-for-entity-tracker-packets.patch} | 0 ...-lookup-fluid-state-when-raytracing.patch} | 0 ...atch => 0759-Time-scoreboard-search.patch} | 0 ...packets-for-hard-colliding-entities.patch} | 0 ...1-Do-not-run-raytrace-logic-for-AIR.patch} | 0 ...rimise-map-impl-for-tracked-players.patch} | 0 ...imise-BlockSoil-nearby-water-lookup.patch} | 0 ...ition-of-entities-to-entity-ticklis.patch} | 0 ... 0765-Optimise-random-block-ticking.patch} | 0 ...6-Optimise-non-flush-packet-sending.patch} | 4 +- ...0767-Optimise-nearby-player-lookups.patch} | 105 +- .../0768-Optimise-WorldServer-notify.patch} | 32 +- ...0769-Remove-streams-for-villager-AI.patch} | 159 +- .../0770-Rewrite-dataconverter-system.patch} | 2285 +++++++++++++++-- todo.txt | 2 + 50 files changed, 2250 insertions(+), 382 deletions(-) rename patches/{unapplied/api/0341-Add-Raw-Byte-Entity-Serialization.patch => api/0342-Add-Raw-Byte-Entity-Serialization.patch} (100%) rename patches/{unapplied/server => removed/1.18}/0793-Fix-Codec-log-spam.patch (100%) rename patches/{removed/1.18/0726-Add-Raw-Byte-Entity-Serialization.patch => server/0727-Add-Raw-Byte-Entity-Serialization.patch} (91%) rename patches/server/{0727-Vanilla-command-permission-fixes.patch => 0728-Vanilla-command-permission-fixes.patch} (100%) rename patches/server/{0728-Make-CallbackExecutor-strict-again.patch => 0729-Make-CallbackExecutor-strict-again.patch} (100%) rename patches/server/{0729-Do-not-allow-the-server-to-unload-chunks-at-request-.patch => 0730-Do-not-allow-the-server-to-unload-chunks-at-request-.patch} (100%) rename patches/server/{0730-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch => 0731-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch} (100%) rename patches/server/{0731-Correctly-handle-recursion-for-chunkholder-updates.patch => 0732-Correctly-handle-recursion-for-chunkholder-updates.patch} (100%) rename patches/server/{0732-Separate-lookup-locking-from-state-access-in-UserCac.patch => 0733-Separate-lookup-locking-from-state-access-in-UserCac.patch} (100%) rename patches/server/{0733-Fix-chunks-refusing-to-unload-at-low-TPS.patch => 0734-Fix-chunks-refusing-to-unload-at-low-TPS.patch} (100%) rename patches/server/{0734-Do-not-allow-ticket-level-changes-while-unloading-pl.patch => 0735-Do-not-allow-ticket-level-changes-while-unloading-pl.patch} (100%) rename patches/server/{0735-Do-not-allow-ticket-level-changes-when-updating-chun.patch => 0736-Do-not-allow-ticket-level-changes-when-updating-chun.patch} (100%) rename patches/server/{0736-Do-not-submit-profile-lookups-to-worldgen-threads.patch => 0737-Do-not-submit-profile-lookups-to-worldgen-threads.patch} (100%) rename patches/server/{0737-Log-when-the-async-catcher-is-tripped.patch => 0738-Log-when-the-async-catcher-is-tripped.patch} (100%) rename patches/server/{0738-Sanitize-ResourceLocation-error-logging.patch => 0739-Sanitize-ResourceLocation-error-logging.patch} (100%) rename patches/server/{0739-Optimise-general-POI-access.patch => 0740-Optimise-general-POI-access.patch} (100%) rename patches/server/{0740-Allow-controlled-flushing-for-network-manager.patch => 0741-Allow-controlled-flushing-for-network-manager.patch} (100%) rename patches/server/{0741-Add-more-async-catchers.patch => 0742-Add-more-async-catchers.patch} (100%) rename patches/server/{0742-Rewrite-entity-bounding-box-lookup-calls.patch => 0743-Rewrite-entity-bounding-box-lookup-calls.patch} (99%) rename patches/server/{0743-Execute-chunk-tasks-mid-tick.patch => 0744-Execute-chunk-tasks-mid-tick.patch} (100%) rename patches/server/{0744-Do-not-copy-visible-chunks.patch => 0745-Do-not-copy-visible-chunks.patch} (100%) rename patches/server/{0745-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch => 0746-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch} (99%) rename patches/server/{0746-Custom-table-implementation-for-blockstate-state-loo.patch => 0747-Custom-table-implementation-for-blockstate-state-loo.patch} (100%) rename patches/server/{0747-Detail-more-information-in-watchdog-dumps.patch => 0748-Detail-more-information-in-watchdog-dumps.patch} (98%) rename patches/server/{0748-Manually-inline-methods-in-BlockPosition.patch => 0749-Manually-inline-methods-in-BlockPosition.patch} (100%) rename patches/server/{0749-Distance-manager-tick-timings.patch => 0750-Distance-manager-tick-timings.patch} (100%) rename patches/server/{0750-Name-craft-scheduler-threads-according-to-the-plugin.patch => 0751-Name-craft-scheduler-threads-according-to-the-plugin.patch} (100%) rename patches/server/{0751-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch => 0752-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch} (100%) rename patches/server/{0752-Add-packet-limiter-config.patch => 0753-Add-packet-limiter-config.patch} (100%) rename patches/server/{0753-Lag-compensate-block-breaking.patch => 0754-Lag-compensate-block-breaking.patch} (100%) rename patches/server/{0754-Use-correct-LevelStem-registry-when-loading-default-.patch => 0755-Use-correct-LevelStem-registry-when-loading-default-.patch} (100%) rename patches/server/{0755-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch => 0756-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch} (100%) rename patches/server/{0756-Consolidate-flush-calls-for-entity-tracker-packets.patch => 0757-Consolidate-flush-calls-for-entity-tracker-packets.patch} (100%) rename patches/server/{0757-Don-t-lookup-fluid-state-when-raytracing.patch => 0758-Don-t-lookup-fluid-state-when-raytracing.patch} (100%) rename patches/server/{0758-Time-scoreboard-search.patch => 0759-Time-scoreboard-search.patch} (100%) rename patches/server/{0759-Send-full-pos-packets-for-hard-colliding-entities.patch => 0760-Send-full-pos-packets-for-hard-colliding-entities.patch} (100%) rename patches/server/{0760-Do-not-run-raytrace-logic-for-AIR.patch => 0761-Do-not-run-raytrace-logic-for-AIR.patch} (100%) rename patches/server/{0761-Oprimise-map-impl-for-tracked-players.patch => 0762-Oprimise-map-impl-for-tracked-players.patch} (100%) rename patches/server/{0762-Optimise-BlockSoil-nearby-water-lookup.patch => 0763-Optimise-BlockSoil-nearby-water-lookup.patch} (100%) rename patches/server/{0763-Allow-removal-addition-of-entities-to-entity-ticklis.patch => 0764-Allow-removal-addition-of-entities-to-entity-ticklis.patch} (100%) rename patches/server/{0764-Optimise-random-block-ticking.patch => 0765-Optimise-random-block-ticking.patch} (100%) rename patches/{unapplied/server/0791-Optimise-non-flush-packet-sending.patch => server/0766-Optimise-non-flush-packet-sending.patch} (94%) rename patches/{unapplied/server/0792-Optimise-nearby-player-lookups.patch => server/0767-Optimise-nearby-player-lookups.patch} (81%) rename patches/{unapplied/server/0794-Optimise-WorldServer-notify.patch => server/0768-Optimise-WorldServer-notify.patch} (93%) rename patches/{unapplied/server/0795-Remove-streams-for-villager-AI.patch => server/0769-Remove-streams-for-villager-AI.patch} (57%) rename patches/{unapplied/server/0796-Rewrite-dataconverter-system.patch => server/0770-Rewrite-dataconverter-system.patch} (94%) diff --git a/patches/unapplied/api/0341-Add-Raw-Byte-Entity-Serialization.patch b/patches/api/0342-Add-Raw-Byte-Entity-Serialization.patch similarity index 100% rename from patches/unapplied/api/0341-Add-Raw-Byte-Entity-Serialization.patch rename to patches/api/0342-Add-Raw-Byte-Entity-Serialization.patch diff --git a/patches/unapplied/server/0793-Fix-Codec-log-spam.patch b/patches/removed/1.18/0793-Fix-Codec-log-spam.patch similarity index 100% rename from patches/unapplied/server/0793-Fix-Codec-log-spam.patch rename to patches/removed/1.18/0793-Fix-Codec-log-spam.patch diff --git a/patches/server/0351-Guard-against-serializing-mismatching-chunk-coordina.patch b/patches/server/0351-Guard-against-serializing-mismatching-chunk-coordina.patch index 9bbe141d96..b625771c77 100644 --- a/patches/server/0351-Guard-against-serializing-mismatching-chunk-coordina.patch +++ b/patches/server/0351-Guard-against-serializing-mismatching-chunk-coordina.patch @@ -6,23 +6,29 @@ Subject: [PATCH] Guard against serializing mismatching chunk coordinate Should help if something dumb happens diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 992a7d6c4372942711a1381ac08ee13910a62cb0..37855d2183212cb043b30418740c0fd047dbc07f 100644 +index 384ee6fbc65baff381d875665fd2462dbc99683e..980c784b8e5365b62cbeef7f32af9f4383cc01e6 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -75,6 +75,12 @@ public class ChunkSerializer { +@@ -75,6 +75,18 @@ public class ChunkSerializer { public ChunkSerializer() {} + // Paper start - guard against serializing mismatching coordinates + // TODO Note: This needs to be re-checked each update + public static ChunkPos getChunkCoordinate(CompoundTag chunkData) { -+ return new ChunkPos(chunkData.getInt("xPos"), chunkData.getInt("zPos")); ++ final int dataVersion = ChunkStorage.getVersion(chunkData); ++ if (dataVersion < 2842) { // Level tag is removed after this version ++ final CompoundTag levelData = chunkData.getCompound("Level"); ++ return new ChunkPos(levelData.getInt("xPos"), levelData.getInt("zPos")); ++ } else { ++ return new ChunkPos(chunkData.getInt("xPos"), chunkData.getInt("zPos")); ++ } + } + // Paper end // Paper start public static final class InProgressChunkHolder { -@@ -100,7 +106,7 @@ public class ChunkSerializer { +@@ -100,7 +112,7 @@ public class ChunkSerializer { public static InProgressChunkHolder loadChunk(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt, boolean distinguish) { java.util.ArrayDeque tasksToExecuteOnMain = new java.util.ArrayDeque<>(); // Paper end @@ -32,7 +38,7 @@ index 992a7d6c4372942711a1381ac08ee13910a62cb0..37855d2183212cb043b30418740c0fd0 if (!Objects.equals(chunkPos, chunkcoordintpair1)) { ChunkSerializer.LOGGER.error("Chunk file at {} is in the wrong location; relocating. (Expected {}, got {})", chunkPos, chunkPos, chunkcoordintpair1); diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -index 1fc202caf9051f12192ed479898b01b0a02eebbd..0631a5b1af38ace5ad167d1986271081bd2ee7a6 100644 +index 2eba8c2d1e978f677eaedac2e09cd1124f1d03db..a750b40be3ba5ba258ca2540ab0398deac5a6c5e 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java @@ -132,6 +132,13 @@ public class ChunkStorage implements AutoCloseable { diff --git a/patches/server/0458-Optimize-NibbleArray-to-use-pooled-buffers.patch b/patches/server/0458-Optimize-NibbleArray-to-use-pooled-buffers.patch index 50f950e9e5..e85cb4e1ec 100644 --- a/patches/server/0458-Optimize-NibbleArray-to-use-pooled-buffers.patch +++ b/patches/server/0458-Optimize-NibbleArray-to-use-pooled-buffers.patch @@ -256,10 +256,10 @@ index 81701abd11fbc4671393a76a42973f53835ca234..e8cf0088e94925934acd02ba05b9411b public String toString() { diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 0980efbc9ef092f56713c7ef776f78fd89cca818..634e44c3eac516f080b565a3b4c7691e31a3eb38 100644 +index 980c784b8e5365b62cbeef7f32af9f4383cc01e6..46beea026eec707c69194da6d1d51dc66b61f54e 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -496,11 +496,11 @@ public class ChunkSerializer { +@@ -502,11 +502,11 @@ public class ChunkSerializer { } if (nibblearray != null && !nibblearray.isEmpty()) { diff --git a/patches/server/0478-Do-not-let-the-server-load-chunks-from-newer-version.patch b/patches/server/0478-Do-not-let-the-server-load-chunks-from-newer-version.patch index 4826293d24..2fa64e3aff 100644 --- a/patches/server/0478-Do-not-let-the-server-load-chunks-from-newer-version.patch +++ b/patches/server/0478-Do-not-let-the-server-load-chunks-from-newer-version.patch @@ -9,10 +9,10 @@ the game, immediately stop the server to prevent data corruption. You can override this functionality at your own peril. diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 5c21871c7bdfce191db499860725da769dc9caac..d44ce73ea91abd7199695c417c534b6e4ca34e6a 100644 +index 46beea026eec707c69194da6d1d51dc66b61f54e..a5bd7d9a7440887d8997a96efebaf3db155263be 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -103,9 +103,22 @@ public class ChunkSerializer { +@@ -109,9 +109,22 @@ public class ChunkSerializer { return holder.protoChunk; } diff --git a/patches/removed/1.18/0726-Add-Raw-Byte-Entity-Serialization.patch b/patches/server/0727-Add-Raw-Byte-Entity-Serialization.patch similarity index 91% rename from patches/removed/1.18/0726-Add-Raw-Byte-Entity-Serialization.patch rename to patches/server/0727-Add-Raw-Byte-Entity-Serialization.patch index 3f8b6c847d..6eeb7bafe0 100644 --- a/patches/removed/1.18/0726-Add-Raw-Byte-Entity-Serialization.patch +++ b/patches/server/0727-Add-Raw-Byte-Entity-Serialization.patch @@ -45,10 +45,10 @@ index ee50ea695585639d0ff184b675f3fb3b205b9f86..0bd800e1aeda87689a6c56ee6fadda38 // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 691b110e8a64081b68868456089908fe38fbc1cf..673b5192c32ee1b3c0d15462d3fadb0f31cd6a03 100644 +index 691b110e8a64081b68868456089908fe38fbc1cf..3eb5e7f7d449ccd862f42e2e131ebcddbdf79afb 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -421,6 +421,29 @@ public final class CraftMagicNumbers implements UnsafeValues { +@@ -421,6 +421,30 @@ public final class CraftMagicNumbers implements UnsafeValues { return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.of((CompoundTag) converted.getValue())); } @@ -69,7 +69,8 @@ index 691b110e8a64081b68868456089908fe38fbc1cf..673b5192c32ee1b3c0d15462d3fadb0f + + CompoundTag compound = deserializeNbtFromBytes(data); + int dataVersion = compound.getInt("DataVersion"); -+ compound = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY, compound, dataVersion, getDataVersion()); ++ Dynamic converted = DataFixers.getDataFixer().update(References.ENTITY_TREE, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, getDataVersion()); ++ compound = (CompoundTag) converted.getValue(); + if (!preserveUUID) compound.remove("UUID"); // Generate a new UUID so we don't have to worry about deserializing the same entity twice + return net.minecraft.world.entity.EntityType.create(compound, ((org.bukkit.craftbukkit.CraftWorld) world).getHandle()) + .orElseThrow(() -> new IllegalArgumentException("An ID was not found for the data. Did you downgrade?")).getBukkitEntity(); diff --git a/patches/server/0727-Vanilla-command-permission-fixes.patch b/patches/server/0728-Vanilla-command-permission-fixes.patch similarity index 100% rename from patches/server/0727-Vanilla-command-permission-fixes.patch rename to patches/server/0728-Vanilla-command-permission-fixes.patch diff --git a/patches/server/0728-Make-CallbackExecutor-strict-again.patch b/patches/server/0729-Make-CallbackExecutor-strict-again.patch similarity index 100% rename from patches/server/0728-Make-CallbackExecutor-strict-again.patch rename to patches/server/0729-Make-CallbackExecutor-strict-again.patch diff --git a/patches/server/0729-Do-not-allow-the-server-to-unload-chunks-at-request-.patch b/patches/server/0730-Do-not-allow-the-server-to-unload-chunks-at-request-.patch similarity index 100% rename from patches/server/0729-Do-not-allow-the-server-to-unload-chunks-at-request-.patch rename to patches/server/0730-Do-not-allow-the-server-to-unload-chunks-at-request-.patch diff --git a/patches/server/0730-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch b/patches/server/0731-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch similarity index 100% rename from patches/server/0730-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch rename to patches/server/0731-Do-not-run-close-logic-for-inventories-on-chunk-unlo.patch diff --git a/patches/server/0731-Correctly-handle-recursion-for-chunkholder-updates.patch b/patches/server/0732-Correctly-handle-recursion-for-chunkholder-updates.patch similarity index 100% rename from patches/server/0731-Correctly-handle-recursion-for-chunkholder-updates.patch rename to patches/server/0732-Correctly-handle-recursion-for-chunkholder-updates.patch diff --git a/patches/server/0732-Separate-lookup-locking-from-state-access-in-UserCac.patch b/patches/server/0733-Separate-lookup-locking-from-state-access-in-UserCac.patch similarity index 100% rename from patches/server/0732-Separate-lookup-locking-from-state-access-in-UserCac.patch rename to patches/server/0733-Separate-lookup-locking-from-state-access-in-UserCac.patch diff --git a/patches/server/0733-Fix-chunks-refusing-to-unload-at-low-TPS.patch b/patches/server/0734-Fix-chunks-refusing-to-unload-at-low-TPS.patch similarity index 100% rename from patches/server/0733-Fix-chunks-refusing-to-unload-at-low-TPS.patch rename to patches/server/0734-Fix-chunks-refusing-to-unload-at-low-TPS.patch diff --git a/patches/server/0734-Do-not-allow-ticket-level-changes-while-unloading-pl.patch b/patches/server/0735-Do-not-allow-ticket-level-changes-while-unloading-pl.patch similarity index 100% rename from patches/server/0734-Do-not-allow-ticket-level-changes-while-unloading-pl.patch rename to patches/server/0735-Do-not-allow-ticket-level-changes-while-unloading-pl.patch diff --git a/patches/server/0735-Do-not-allow-ticket-level-changes-when-updating-chun.patch b/patches/server/0736-Do-not-allow-ticket-level-changes-when-updating-chun.patch similarity index 100% rename from patches/server/0735-Do-not-allow-ticket-level-changes-when-updating-chun.patch rename to patches/server/0736-Do-not-allow-ticket-level-changes-when-updating-chun.patch diff --git a/patches/server/0736-Do-not-submit-profile-lookups-to-worldgen-threads.patch b/patches/server/0737-Do-not-submit-profile-lookups-to-worldgen-threads.patch similarity index 100% rename from patches/server/0736-Do-not-submit-profile-lookups-to-worldgen-threads.patch rename to patches/server/0737-Do-not-submit-profile-lookups-to-worldgen-threads.patch diff --git a/patches/server/0737-Log-when-the-async-catcher-is-tripped.patch b/patches/server/0738-Log-when-the-async-catcher-is-tripped.patch similarity index 100% rename from patches/server/0737-Log-when-the-async-catcher-is-tripped.patch rename to patches/server/0738-Log-when-the-async-catcher-is-tripped.patch diff --git a/patches/server/0738-Sanitize-ResourceLocation-error-logging.patch b/patches/server/0739-Sanitize-ResourceLocation-error-logging.patch similarity index 100% rename from patches/server/0738-Sanitize-ResourceLocation-error-logging.patch rename to patches/server/0739-Sanitize-ResourceLocation-error-logging.patch diff --git a/patches/server/0739-Optimise-general-POI-access.patch b/patches/server/0740-Optimise-general-POI-access.patch similarity index 100% rename from patches/server/0739-Optimise-general-POI-access.patch rename to patches/server/0740-Optimise-general-POI-access.patch diff --git a/patches/server/0740-Allow-controlled-flushing-for-network-manager.patch b/patches/server/0741-Allow-controlled-flushing-for-network-manager.patch similarity index 100% rename from patches/server/0740-Allow-controlled-flushing-for-network-manager.patch rename to patches/server/0741-Allow-controlled-flushing-for-network-manager.patch diff --git a/patches/server/0741-Add-more-async-catchers.patch b/patches/server/0742-Add-more-async-catchers.patch similarity index 100% rename from patches/server/0741-Add-more-async-catchers.patch rename to patches/server/0742-Add-more-async-catchers.patch diff --git a/patches/server/0742-Rewrite-entity-bounding-box-lookup-calls.patch b/patches/server/0743-Rewrite-entity-bounding-box-lookup-calls.patch similarity index 99% rename from patches/server/0742-Rewrite-entity-bounding-box-lookup-calls.patch rename to patches/server/0743-Rewrite-entity-bounding-box-lookup-calls.patch index 85256bd18b..2d7fa25573 100644 --- a/patches/server/0742-Rewrite-entity-bounding-box-lookup-calls.patch +++ b/patches/server/0743-Rewrite-entity-bounding-box-lookup-calls.patch @@ -953,7 +953,7 @@ index 5d189257f494eb12b5fd98b12da6dd09ca14f972..913b56361dece6c699ed7fad7e580d40 + // Paper end } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index dcfc726ab96dccc05848219e824ad7612dbfbdab..db6c11694e6316c50a3f0a138e09542fdae45718 100644 +index 7713f26d4a97df94c27694d28881d298e4c54147..3110f8cbf65ba0fefbf78f90915ee358694d20ca 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -386,6 +386,56 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i @@ -1013,7 +1013,7 @@ index dcfc726ab96dccc05848219e824ad7612dbfbdab..db6c11694e6316c50a3f0a138e09542f public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); this.passengers = ImmutableList.of(); -@@ -2233,11 +2283,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i +@@ -2242,11 +2292,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i return InteractionResult.PASS; } diff --git a/patches/server/0743-Execute-chunk-tasks-mid-tick.patch b/patches/server/0744-Execute-chunk-tasks-mid-tick.patch similarity index 100% rename from patches/server/0743-Execute-chunk-tasks-mid-tick.patch rename to patches/server/0744-Execute-chunk-tasks-mid-tick.patch diff --git a/patches/server/0744-Do-not-copy-visible-chunks.patch b/patches/server/0745-Do-not-copy-visible-chunks.patch similarity index 100% rename from patches/server/0744-Do-not-copy-visible-chunks.patch rename to patches/server/0745-Do-not-copy-visible-chunks.patch diff --git a/patches/server/0745-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch b/patches/server/0746-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch similarity index 99% rename from patches/server/0745-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch rename to patches/server/0746-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch index a8ae16c3cb..749c4fc580 100644 --- a/patches/server/0745-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch +++ b/patches/server/0746-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch @@ -10,7 +10,7 @@ hoping that at least then we don't swap chunks, and maybe recover them all. diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index f58050eaa1354ace7b3558d528ab8effdd1432aa..23b3203d04cf1dd2fc3c42e2c7b287a949c81699 100644 +index a5bd7d9a7440887d8997a96efebaf3db155263be..c1f22e3e9b3ab91f05556707ace46e9c627b025e 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java @@ -66,6 +66,12 @@ import org.apache.logging.log4j.LogManager; @@ -26,7 +26,7 @@ index f58050eaa1354ace7b3558d528ab8effdd1432aa..23b3203d04cf1dd2fc3c42e2c7b287a9 public static final Codec> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); private static final Logger LOGGER = LogManager.getLogger(); -@@ -437,7 +443,7 @@ public class ChunkSerializer { +@@ -443,7 +449,7 @@ public class ChunkSerializer { nbttagcompound.putInt("xPos", chunkcoordintpair.x); nbttagcompound.putInt("yPos", chunk.getMinSection()); nbttagcompound.putInt("zPos", chunkcoordintpair.z); diff --git a/patches/server/0746-Custom-table-implementation-for-blockstate-state-loo.patch b/patches/server/0747-Custom-table-implementation-for-blockstate-state-loo.patch similarity index 100% rename from patches/server/0746-Custom-table-implementation-for-blockstate-state-loo.patch rename to patches/server/0747-Custom-table-implementation-for-blockstate-state-loo.patch diff --git a/patches/server/0747-Detail-more-information-in-watchdog-dumps.patch b/patches/server/0748-Detail-more-information-in-watchdog-dumps.patch similarity index 98% rename from patches/server/0747-Detail-more-information-in-watchdog-dumps.patch rename to patches/server/0748-Detail-more-information-in-watchdog-dumps.patch index f03e054f56..5a422cba90 100644 --- a/patches/server/0747-Detail-more-information-in-watchdog-dumps.patch +++ b/patches/server/0748-Detail-more-information-in-watchdog-dumps.patch @@ -123,7 +123,7 @@ index 5d4f20a31ad99b4e808bb9a7aaa2153666af493f..928ac2d5b93b93aa7494374f4f344655 private void tickPassenger(Entity vehicle, Entity passenger) { diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index db6c11694e6316c50a3f0a138e09542fdae45718..62fe626aa198d19ccfb48f47b8f771b6037cff9c 100644 +index 3110f8cbf65ba0fefbf78f90915ee358694d20ca..96794dcb87c3606e9d112d4159be8be31ad4329e 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -860,7 +860,42 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i @@ -183,7 +183,7 @@ index db6c11694e6316c50a3f0a138e09542fdae45718..62fe626aa198d19ccfb48f47b8f771b6 } protected boolean isHorizontalCollisionMinor(Vec3 adjustedMovement) { -@@ -3798,7 +3840,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i +@@ -3807,7 +3849,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i } public void setDeltaMovement(Vec3 velocity) { @@ -193,7 +193,7 @@ index db6c11694e6316c50a3f0a138e09542fdae45718..62fe626aa198d19ccfb48f47b8f771b6 } public void setDeltaMovement(double x, double y, double z) { -@@ -3874,7 +3918,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i +@@ -3883,7 +3927,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i } // Paper end - fix MC-4 if (this.position.x != x || this.position.y != y || this.position.z != z) { diff --git a/patches/server/0748-Manually-inline-methods-in-BlockPosition.patch b/patches/server/0749-Manually-inline-methods-in-BlockPosition.patch similarity index 100% rename from patches/server/0748-Manually-inline-methods-in-BlockPosition.patch rename to patches/server/0749-Manually-inline-methods-in-BlockPosition.patch diff --git a/patches/server/0749-Distance-manager-tick-timings.patch b/patches/server/0750-Distance-manager-tick-timings.patch similarity index 100% rename from patches/server/0749-Distance-manager-tick-timings.patch rename to patches/server/0750-Distance-manager-tick-timings.patch diff --git a/patches/server/0750-Name-craft-scheduler-threads-according-to-the-plugin.patch b/patches/server/0751-Name-craft-scheduler-threads-according-to-the-plugin.patch similarity index 100% rename from patches/server/0750-Name-craft-scheduler-threads-according-to-the-plugin.patch rename to patches/server/0751-Name-craft-scheduler-threads-according-to-the-plugin.patch diff --git a/patches/server/0751-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch b/patches/server/0752-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch similarity index 100% rename from patches/server/0751-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch rename to patches/server/0752-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch diff --git a/patches/server/0752-Add-packet-limiter-config.patch b/patches/server/0753-Add-packet-limiter-config.patch similarity index 100% rename from patches/server/0752-Add-packet-limiter-config.patch rename to patches/server/0753-Add-packet-limiter-config.patch diff --git a/patches/server/0753-Lag-compensate-block-breaking.patch b/patches/server/0754-Lag-compensate-block-breaking.patch similarity index 100% rename from patches/server/0753-Lag-compensate-block-breaking.patch rename to patches/server/0754-Lag-compensate-block-breaking.patch diff --git a/patches/server/0754-Use-correct-LevelStem-registry-when-loading-default-.patch b/patches/server/0755-Use-correct-LevelStem-registry-when-loading-default-.patch similarity index 100% rename from patches/server/0754-Use-correct-LevelStem-registry-when-loading-default-.patch rename to patches/server/0755-Use-correct-LevelStem-registry-when-loading-default-.patch diff --git a/patches/server/0755-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch b/patches/server/0756-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch similarity index 100% rename from patches/server/0755-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch rename to patches/server/0756-Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch diff --git a/patches/server/0756-Consolidate-flush-calls-for-entity-tracker-packets.patch b/patches/server/0757-Consolidate-flush-calls-for-entity-tracker-packets.patch similarity index 100% rename from patches/server/0756-Consolidate-flush-calls-for-entity-tracker-packets.patch rename to patches/server/0757-Consolidate-flush-calls-for-entity-tracker-packets.patch diff --git a/patches/server/0757-Don-t-lookup-fluid-state-when-raytracing.patch b/patches/server/0758-Don-t-lookup-fluid-state-when-raytracing.patch similarity index 100% rename from patches/server/0757-Don-t-lookup-fluid-state-when-raytracing.patch rename to patches/server/0758-Don-t-lookup-fluid-state-when-raytracing.patch diff --git a/patches/server/0758-Time-scoreboard-search.patch b/patches/server/0759-Time-scoreboard-search.patch similarity index 100% rename from patches/server/0758-Time-scoreboard-search.patch rename to patches/server/0759-Time-scoreboard-search.patch diff --git a/patches/server/0759-Send-full-pos-packets-for-hard-colliding-entities.patch b/patches/server/0760-Send-full-pos-packets-for-hard-colliding-entities.patch similarity index 100% rename from patches/server/0759-Send-full-pos-packets-for-hard-colliding-entities.patch rename to patches/server/0760-Send-full-pos-packets-for-hard-colliding-entities.patch diff --git a/patches/server/0760-Do-not-run-raytrace-logic-for-AIR.patch b/patches/server/0761-Do-not-run-raytrace-logic-for-AIR.patch similarity index 100% rename from patches/server/0760-Do-not-run-raytrace-logic-for-AIR.patch rename to patches/server/0761-Do-not-run-raytrace-logic-for-AIR.patch diff --git a/patches/server/0761-Oprimise-map-impl-for-tracked-players.patch b/patches/server/0762-Oprimise-map-impl-for-tracked-players.patch similarity index 100% rename from patches/server/0761-Oprimise-map-impl-for-tracked-players.patch rename to patches/server/0762-Oprimise-map-impl-for-tracked-players.patch diff --git a/patches/server/0762-Optimise-BlockSoil-nearby-water-lookup.patch b/patches/server/0763-Optimise-BlockSoil-nearby-water-lookup.patch similarity index 100% rename from patches/server/0762-Optimise-BlockSoil-nearby-water-lookup.patch rename to patches/server/0763-Optimise-BlockSoil-nearby-water-lookup.patch diff --git a/patches/server/0763-Allow-removal-addition-of-entities-to-entity-ticklis.patch b/patches/server/0764-Allow-removal-addition-of-entities-to-entity-ticklis.patch similarity index 100% rename from patches/server/0763-Allow-removal-addition-of-entities-to-entity-ticklis.patch rename to patches/server/0764-Allow-removal-addition-of-entities-to-entity-ticklis.patch diff --git a/patches/server/0764-Optimise-random-block-ticking.patch b/patches/server/0765-Optimise-random-block-ticking.patch similarity index 100% rename from patches/server/0764-Optimise-random-block-ticking.patch rename to patches/server/0765-Optimise-random-block-ticking.patch diff --git a/patches/unapplied/server/0791-Optimise-non-flush-packet-sending.patch b/patches/server/0766-Optimise-non-flush-packet-sending.patch similarity index 94% rename from patches/unapplied/server/0791-Optimise-non-flush-packet-sending.patch rename to patches/server/0766-Optimise-non-flush-packet-sending.patch index c5f1223f87..f8dc75ba8c 100644 --- a/patches/unapplied/server/0791-Optimise-non-flush-packet-sending.patch +++ b/patches/server/0766-Optimise-non-flush-packet-sending.patch @@ -20,7 +20,7 @@ up on this optimisation before he came along. Locally this patch drops the entity tracker tick by a full 1.5x. diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index 300cd4d2861c7f155cc6a5bb5a0c47b0b77ff240..7c66d5d51efd3ec55f5170cf828db22e26131517 100644 +index 241b086bd096a4bc2175835b2505deda1c143f09..a1aafb037fd340dc93dd2afb758ffc7457d15f84 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java @@ -49,6 +49,8 @@ import org.apache.logging.log4j.Logger; @@ -32,7 +32,7 @@ index 300cd4d2861c7f155cc6a5bb5a0c47b0b77ff240..7c66d5d51efd3ec55f5170cf828db22e public class Connection extends SimpleChannelInboundHandler> { private static final float AVERAGE_PACKETS_SMOOTHING = 0.75F; -@@ -409,9 +411,19 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -387,9 +389,19 @@ public class Connection extends SimpleChannelInboundHandler> { if (this.channel.eventLoop().inEventLoop()) { this.doSendPacket(packet, callback, enumprotocol, enumprotocol1, flush); // Paper - add flush parameter } else { diff --git a/patches/unapplied/server/0792-Optimise-nearby-player-lookups.patch b/patches/server/0767-Optimise-nearby-player-lookups.patch similarity index 81% rename from patches/unapplied/server/0792-Optimise-nearby-player-lookups.patch rename to patches/server/0767-Optimise-nearby-player-lookups.patch index 7ac99c624f..0d6a80476c 100644 --- a/patches/unapplied/server/0792-Optimise-nearby-player-lookups.patch +++ b/patches/server/0767-Optimise-nearby-player-lookups.patch @@ -9,13 +9,13 @@ since the penalty of a map lookup could outweigh the benefits of searching less players (as it basically did in the outside range patch). diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 4588ae8037407b81c99135863eb0c4e97c564c24..2a33071c4b69cb7b5a7e296e8fd903e3a528b210 100644 +index 7418245d5d08706ca2a1378e769abfb0de1076ed..8a7cc96f563c3fb8807d4a8a3249fc0892710d17 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -242,6 +242,12 @@ public class ChunkHolder { - long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos); - this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key); - this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); +@@ -94,6 +94,12 @@ public class ChunkHolder { + this.setTicketLevel(level); + this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()]; + this.chunkMap = (ChunkMap)playersWatchingChunkProvider; // Paper + // Paper start - optimise checkDespawn + LevelChunk chunk = this.getFullChunkUnchecked(); + if (chunk != null) { @@ -23,16 +23,16 @@ index 4588ae8037407b81c99135863eb0c4e97c564c24..2a33071c4b69cb7b5a7e296e8fd903e3 + } + // Paper end - optimise checkDespawn } - // Paper end - optimise isOutsideOfRange - long lastAutoSaveTime; // Paper - incremental autosave + + // CraftBukkit start diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 6522eb4b72c50be3ff7d1b094066a1cbec88634d..10d1e1f728519ad49379895c7fd3668badcbfd5a 100644 +index 925da0baa59f742dbe727c6323cc90b65159f314..3b2db473e5eacbcf55ae8786aff5ac71388a98ee 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -217,6 +217,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick - public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap; - // Paper end - optimise PlayerChunkMap#isOutsideRange +@@ -190,21 +190,36 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper + // Paper start - distance maps + private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); + // Paper start - optimise checkDespawn + public static final int GENERAL_AREA_MAP_SQUARE_RADIUS = 40; + public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE = 16.0 * (GENERAL_AREA_MAP_SQUARE_RADIUS - 1); @@ -42,40 +42,34 @@ index 6522eb4b72c50be3ff7d1b094066a1cbec88634d..10d1e1f728519ad49379895c7fd3668b void addPlayerToDistanceMaps(ServerPlayer player) { int chunkX = MCUtil.getChunkCoordinate(player.getX()); -@@ -237,6 +243,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); - // Paper end - optimise PlayerChunkMap#isOutsideRange - this.playerChunkManager.addPlayer(player); // Paper - replace chunk loader + int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); + // Note: players need to be explicitly added to distance maps before they can be updated + // Paper start - optimise checkDespawn + this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); + // Paper end - optimise checkDespawn } void removePlayerFromDistanceMaps(ServerPlayer player) { -@@ -250,6 +259,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerChunkTickRangeMap.remove(player); - // Paper end - optimise PlayerChunkMap#isOutsideRange - this.playerChunkManager.removePlayer(player); // Paper - replace chunk loader + + // Paper start - optimise checkDespawn + this.playerGeneralAreaMap.remove(player); + // Paper end - optimise checkDespawn } void updateMaps(ServerPlayer player) { -@@ -268,6 +280,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); - // Paper end - optimise PlayerChunkMap#isOutsideRange - this.playerChunkManager.updatePlayer(player); // Paper - replace chunk loader + int chunkX = MCUtil.getChunkCoordinate(player.getX()); + int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); + // Note: players need to be explicitly added to distance maps before they can be updated + // Paper start - optimise checkDespawn + this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); + // Paper end - optimise checkDespawn } // Paper end // Paper start -@@ -426,6 +441,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - }); - // Paper end - optimise PlayerChunkMap#isOutsideRange +@@ -280,6 +295,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + this.regionManagers.add(this.dataRegionManager); + // Paper end + this.playerMobDistanceMap = this.level.paperConfig.perPlayerMobSpawns ? new com.destroystokyo.paper.util.PlayerMobDistanceMap() : null; // Paper + // Paper start - optimise checkDespawn + this.playerGeneralAreaMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, + (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, @@ -95,32 +89,15 @@ index 6522eb4b72c50be3ff7d1b094066a1cbec88634d..10d1e1f728519ad49379895c7fd3668b + // Paper end - optimise checkDespawn } - // Paper start - Chunk Prioritization -@@ -739,7 +771,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } else { - if (holder != null) { - holder.setTicketLevel(level); -- holder.updateRanges(); // Paper - optimise isOutsideOfRange -+ // Paper - move to correct place - } - - if (holder != null) { -@@ -754,6 +786,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - holder = (ChunkHolder) this.pendingUnloads.remove(pos); - if (holder != null) { - holder.setTicketLevel(level); -+ holder.updateRanges(); // Paper - optimise isOutsideOfRange // Paper - move to correct place - } else { - holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); - // Paper start + protected ChunkGenerator generator() { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index ed696ed93251e644c2b71e468e2556d24b273933..3afb8b91dceb86e88b848462a5b8dbd5c8365239 100644 +index 5935c442a6534ad51d191a72bc8d2043fa25e2ac..8a219ecabe49d8f2564a365968891b214a090f6d 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -392,6 +392,83 @@ public class ServerLevel extends Level implements WorldGenLevel { - } +@@ -396,6 +396,83 @@ public class ServerLevel extends Level implements WorldGenLevel { + return this.getServer().getPlayerList().getPlayer(uuid); } - // Paper end - rewrite ticklistserver + // Paper end + // Paper start - optimise checkDespawn + public final List playersAffectingSpawning = new java.util.ArrayList<>(); + // Paper end - optimise checkDespawn @@ -201,7 +178,7 @@ index ed696ed93251e644c2b71e468e2556d24b273933..3afb8b91dceb86e88b848462a5b8dbd5 // Add env and gen to constructor, WorldData -> WorldDataServer public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, ServerLevelData iworlddataserver, ResourceKey resourcekey, DimensionType dimensionmanager, ChunkProgressListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { -@@ -492,6 +569,14 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -484,6 +561,14 @@ public class ServerLevel extends Level implements WorldGenLevel { } public void tick(BooleanSupplier shouldKeepTicking) { @@ -217,10 +194,10 @@ index ed696ed93251e644c2b71e468e2556d24b273933..3afb8b91dceb86e88b848462a5b8dbd5 this.handlingTick = true; diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 5f4556505d831ea45e576a4c4e10f99e1353684e..55d07e70a67e08bab3a7a66076c980986736e5b8 100644 +index 697c2663c4deeb8f2ad603c979ab0884ac027930..0b46066d35d9bb38d98a9d6e5ca8dbdc0ba1dc5a 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -789,7 +789,12 @@ public abstract class Mob extends LivingEntity { +@@ -792,7 +792,12 @@ public abstract class Mob extends LivingEntity { if (this.level.getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) { this.discard(); } else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) { @@ -233,12 +210,12 @@ index 5f4556505d831ea45e576a4c4e10f99e1353684e..55d07e70a67e08bab3a7a66076c98098 + // Paper end - optimise checkDespawn if (entityhuman != null) { - double d0 = entityhuman.distanceToSqr((Entity) this); // CraftBukkit - decompile error + double d0 = entityhuman.distanceToSqr((Entity) this); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 64d5e71a8a26116385cee195d86fce1ef1574a8c..f936e9f9a9fa655fa997d6862b5ed54c04169d35 100644 +index 6be462975523dae9ff436ba1643b2042ec66e554..929f48675a10fdd64cb351305389d680a16963fb 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -247,6 +247,69 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -243,6 +243,69 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return ret; } // Paper end @@ -306,13 +283,13 @@ index 64d5e71a8a26116385cee195d86fce1ef1574a8c..f936e9f9a9fa655fa997d6862b5ed54c + } + // Paper end - optimise checkDespawn - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, final DimensionType dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper - Anti-Xray - Pass executor + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, final DimensionType dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env) { this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 4d8251a961a9c52456db997506dd9691beaec022..55dd04816886d27a62856ac952d2fc5d15bf40e6 100644 +index 63ba93538d990fdd4c9e8c491bb715adc8d57986..e9a37fc6791366ea421f2766a36dc2e014ab7951 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -267,7 +267,7 @@ public final class NaturalSpawner { +@@ -269,7 +269,7 @@ public final class NaturalSpawner { blockposition_mutableblockposition.set(l, i, i1); double d0 = (double) l + 0.5D; double d1 = (double) i1 + 0.5D; @@ -321,7 +298,7 @@ index 4d8251a961a9c52456db997506dd9691beaec022..55dd04816886d27a62856ac952d2fc5d if (entityhuman != null) { double d2 = entityhuman.distanceToSqr(d0, (double) i, d1); -@@ -340,7 +340,7 @@ public final class NaturalSpawner { +@@ -342,7 +342,7 @@ public final class NaturalSpawner { } private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel world, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double squaredDistance) { @@ -331,10 +308,10 @@ index 4d8251a961a9c52456db997506dd9691beaec022..55dd04816886d27a62856ac952d2fc5d private static Boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { // Paper diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 9e75ee7f43722f05dd5df4ef00f7d3e271f4c6e5..86686c24b0b7de4b4bfadbc77419a8872a8e86ee 100644 +index b92da719a5d35a60a2e13ccb0f55c41b242f9b50..a9807f9182a4d70e09486612606c7c1d0a6734ac 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -369,6 +369,93 @@ public class LevelChunk implements ChunkAccess { +@@ -231,6 +231,93 @@ public class LevelChunk extends ChunkAccess { } } // Paper end @@ -426,5 +403,5 @@ index 9e75ee7f43722f05dd5df4ef00f7d3e271f4c6e5..86686c24b0b7de4b4bfadbc77419a887 + } + // Paper end - optimise checkDespawn - public LevelChunk(ServerLevel worldserver, ProtoChunk protoChunk, @Nullable Consumer consumer) { - this(worldserver, protoChunk.getPos(), protoChunk.getBiomes(), protoChunk.getUpgradeData(), protoChunk.getBlockTicks(), protoChunk.getLiquidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), consumer); + public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor chunk_c) { + this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), chunk_c, protoChunk.getBlendingData()); diff --git a/patches/unapplied/server/0794-Optimise-WorldServer-notify.patch b/patches/server/0768-Optimise-WorldServer-notify.patch similarity index 93% rename from patches/unapplied/server/0794-Optimise-WorldServer-notify.patch rename to patches/server/0768-Optimise-WorldServer-notify.patch index 8657ce3d53..9e09b42d3b 100644 --- a/patches/unapplied/server/0794-Optimise-WorldServer-notify.patch +++ b/patches/server/0768-Optimise-WorldServer-notify.patch @@ -8,10 +8,10 @@ Instead, only iterate over navigators in the current region that are eligible for repathing. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index bef7d5b4c8b99d2fbcd975127b16653e0f391338..19a853ceeded1c8803d182d035f0362abfa29933 100644 +index 3b2db473e5eacbcf55ae8786aff5ac71388a98ee..6fc7c1cf269466362dce91fa2cf525e67bee6c15 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -290,15 +290,81 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -227,15 +227,81 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public final io.papermc.paper.chunk.SingleThreadChunkRegionManager dataRegionManager; public static final class DataRegionData implements io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionData { @@ -93,7 +93,7 @@ index bef7d5b4c8b99d2fbcd975127b16653e0f391338..19a853ceeded1c8803d182d035f0362a } @Override -@@ -308,6 +374,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -245,6 +311,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData; final DataRegionData oldRegionData = oldRegion == null ? null : (DataRegionData)oldRegion.regionData; final DataRegionData newRegionData = (DataRegionData)newRegion.regionData; @@ -110,10 +110,10 @@ index bef7d5b4c8b99d2fbcd975127b16653e0f391338..19a853ceeded1c8803d182d035f0362a } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 89a8138e97ab6a399cfbc69cab0ecaa70bb2fe8d..c01b5611fe6946a24fe21eac6a80e3ddadf9f3c1 100644 +index 8a219ecabe49d8f2564a365968891b214a090f6d..8837c9793eb25ad88bdb4b0f6198dc7ae353b9b2 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1079,6 +1079,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1090,6 +1090,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public void tickNonPassenger(Entity entity) { // Paper start - log detailed entity tick information io.papermc.paper.util.TickThread.ensureTickThread("Cannot tick an entity off-main"); @@ -121,7 +121,7 @@ index 89a8138e97ab6a399cfbc69cab0ecaa70bb2fe8d..c01b5611fe6946a24fe21eac6a80e3dd try { if (currentlyTickingEntity.get() == null) { currentlyTickingEntity.lazySet(entity); -@@ -1524,9 +1525,19 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1504,9 +1505,19 @@ public class ServerLevel extends Level implements WorldGenLevel { VoxelShape voxelshape1 = newState.getCollisionShape(this, pos); if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) { @@ -143,7 +143,7 @@ index 89a8138e97ab6a399cfbc69cab0ecaa70bb2fe8d..c01b5611fe6946a24fe21eac6a80e3dd // CraftBukkit start - fix SPIGOT-6362 Mob entityinsentient; try { -@@ -1545,6 +1556,11 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1525,6 +1536,11 @@ public class ServerLevel extends Level implements WorldGenLevel { navigationabstract.recomputePath(pos); } } @@ -155,7 +155,7 @@ index 89a8138e97ab6a399cfbc69cab0ecaa70bb2fe8d..c01b5611fe6946a24fe21eac6a80e3dd } } // Paper -@@ -2324,10 +2340,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2317,10 +2333,12 @@ public class ServerLevel extends Level implements WorldGenLevel { public void onTickingStart(Entity entity) { ServerLevel.this.entityTickList.add(entity); @@ -169,7 +169,7 @@ index 89a8138e97ab6a399cfbc69cab0ecaa70bb2fe8d..c01b5611fe6946a24fe21eac6a80e3dd public void onTrackingStart(Entity entity) { diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index 61080352ef305a1f276dbc297aa680b3175a5da2..10505f32b71b723ed8dbfd9e1348a1691c9f7f18 100644 +index 5884fb42f0880585dee843b98a6ea470a1508e46..4651c2e78089ed28220e767654261c735d2c5eb1 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java @@ -27,7 +27,7 @@ import net.minecraft.world.phys.Vec3; @@ -189,8 +189,8 @@ index 61080352ef305a1f276dbc297aa680b3175a5da2..10505f32b71b723ed8dbfd9e1348a169 + protected boolean hasDelayedRecomputation; protected final boolean needsPathRecalculation() { return this.hasDelayedRecomputation; } // Paper - public accessor protected long timeLastRecompute; protected NodeEvaluator nodeEvaluator; - private BlockPos targetPos; -@@ -49,6 +49,13 @@ public abstract class PathNavigation { + @Nullable +@@ -50,6 +50,13 @@ public abstract class PathNavigation { public final PathFinder pathFinder; private boolean isStuck; @@ -204,7 +204,7 @@ index 61080352ef305a1f276dbc297aa680b3175a5da2..10505f32b71b723ed8dbfd9e1348a169 public PathNavigation(Mob mob, Level world) { this.mob = mob; this.level = world; -@@ -405,7 +412,7 @@ public abstract class PathNavigation { +@@ -415,7 +422,7 @@ public abstract class PathNavigation { } public void recomputePath(BlockPos pos) { @@ -214,7 +214,7 @@ index 61080352ef305a1f276dbc297aa680b3175a5da2..10505f32b71b723ed8dbfd9e1348a169 Vec3 vec3 = new Vec3(((double)node.x + this.mob.getX()) / 2.0D, ((double)node.y + this.mob.getY()) / 2.0D, ((double)node.z + this.mob.getZ()) / 2.0D); if (pos.closerThan(vec3, (double)(this.path.getNodeCount() - this.path.getNextNodeIndex()))) { diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -index 976d206a17add01a31ae38b966913368cf386cb1..28c1f144f2cc8675ed61dc814456859309970480 100644 +index 1d61807768dd883cb82bda5d529055bc50e4d1a9..d963243431e1a75f95e673e1268faa7c2320c6b6 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java @@ -71,6 +71,65 @@ public class PersistentEntitySectionManager implements A @@ -283,7 +283,7 @@ index 976d206a17add01a31ae38b966913368cf386cb1..28c1f144f2cc8675ed61dc8144568593 void removeSectionIfEmpty(long sectionPos, EntitySection section) { if (section.isEmpty()) { this.sectionStorage.remove(sectionPos); -@@ -462,11 +521,25 @@ public class PersistentEntitySectionManager implements A +@@ -451,11 +510,25 @@ public class PersistentEntitySectionManager implements A @Override public void onMove() { BlockPos blockposition = this.entity.blockPosition(); @@ -311,8 +311,8 @@ index 976d206a17add01a31ae38b966913368cf386cb1..28c1f144f2cc8675ed61dc8144568593 if (!this.currentSection.remove(this.entity)) { PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (moving to {})", this.entity, SectionPos.of(this.currentSectionKey), i); -@@ -478,6 +551,11 @@ public class PersistentEntitySectionManager implements A - entitysection.add(this.entity); // CraftBukkit - decompile error +@@ -467,6 +540,11 @@ public class PersistentEntitySectionManager implements A + entitysection.add(this.entity); this.currentSection = entitysection; this.currentSectionKey = i; + // Paper start diff --git a/patches/unapplied/server/0795-Remove-streams-for-villager-AI.patch b/patches/server/0769-Remove-streams-for-villager-AI.patch similarity index 57% rename from patches/unapplied/server/0795-Remove-streams-for-villager-AI.patch rename to patches/server/0769-Remove-streams-for-villager-AI.patch index 227d34f188..8257c2de40 100644 --- a/patches/unapplied/server/0795-Remove-streams-for-villager-AI.patch +++ b/patches/server/0769-Remove-streams-for-villager-AI.patch @@ -5,17 +5,17 @@ Subject: [PATCH] Remove streams for villager AI diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java -index 09998d160a6d79fdb5a5041a5d572649a1532e6a..84bd9298840ba60abbdb0675cda0458e0d6a534a 100644 +index e644bdd3a6f7c09a44149da03587b796674fa568..c67c448e0d8bdd788b94189651304110694c95da 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java @@ -30,11 +30,19 @@ public class GateBehavior extends Behavior { @Override protected boolean canStillUse(ServerLevel world, E entity, long time) { -- return this.behaviors.stream().filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.RUNNING; -- }).anyMatch((behavior) -> { -- return behavior.canStillUse(world, entity, time); +- return this.behaviors.stream().filter((task) -> { +- return task.getStatus() == Behavior.Status.RUNNING; +- }).anyMatch((task) -> { +- return task.canStillUse(world, entity, time); - }); + // Paper start - remove streams + List>> entries = this.behaviors.entries; @@ -43,10 +43,10 @@ index 09998d160a6d79fdb5a5041a5d572649a1532e6a..84bd9298840ba60abbdb0675cda0458e @Override protected void tick(ServerLevel world, E entity, long time) { -- this.behaviors.stream().filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.RUNNING; -- }).forEach((behavior) -> { -- behavior.tickOrStop(world, entity, time); +- this.behaviors.stream().filter((task) -> { +- return task.getStatus() == Behavior.Status.RUNNING; +- }).forEach((task) -> { +- task.tickOrStop(world, entity, time); - }); + // Paper start - remove streams + List>> entries = this.behaviors.entries; @@ -62,10 +62,10 @@ index 09998d160a6d79fdb5a5041a5d572649a1532e6a..84bd9298840ba60abbdb0675cda0458e @Override protected void stop(ServerLevel world, E entity, long time) { -- this.behaviors.stream().filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.RUNNING; -- }).forEach((behavior) -> { -- behavior.doStop(world, entity, time); +- this.behaviors.stream().filter((task) -> { +- return task.getStatus() == Behavior.Status.RUNNING; +- }).forEach((task) -> { +- task.doStop(world, entity, time); - }); + // Paper start - remove streams + List>> entries = this.behaviors.entries; @@ -85,10 +85,10 @@ index 09998d160a6d79fdb5a5041a5d572649a1532e6a..84bd9298840ba60abbdb0675cda0458e RUN_ONE { @Override - public void apply(Stream> tasks, ServerLevel world, E entity, long time) { -- tasks.filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.STOPPED; -- }).filter((behavior) -> { -- return behavior.tryStart(world, entity, time); +- tasks.filter((task) -> { +- return task.getStatus() == Behavior.Status.STOPPED; +- }).filter((task) -> { +- return task.tryStart(world, entity, time); - }).findFirst(); + // Paper start - remove streams + public void apply(List>> tasks, ServerLevel world, E entity, long time) { @@ -105,10 +105,10 @@ index 09998d160a6d79fdb5a5041a5d572649a1532e6a..84bd9298840ba60abbdb0675cda0458e TRY_ALL { @Override - public void apply(Stream> tasks, ServerLevel world, E entity, long time) { -- tasks.filter((behavior) -> { -- return behavior.getStatus() == Behavior.Status.STOPPED; -- }).forEach((behavior) -> { -- behavior.tryStart(world, entity, time); +- tasks.filter((task) -> { +- return task.getStatus() == Behavior.Status.STOPPED; +- }).forEach((task) -> { +- task.tryStart(world, entity, time); - }); + // Paper start - remove streams + public void apply(List>> tasks, ServerLevel world, E entity, long time) { @@ -127,64 +127,8 @@ index 09998d160a6d79fdb5a5041a5d572649a1532e6a..84bd9298840ba60abbdb0675cda0458e + public abstract void apply(List>> tasks, ServerLevel world, E entity, long time); // Paper - remove streams } } -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java b/src/main/java/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java -index 1f59e790d62f0be8e505e339a6699ca3964aea0d..ee783bb7cbec2f58549cb95fde7cbc4c47efa1cb 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/SetLookAndInteract.java -@@ -34,21 +34,42 @@ public class SetLookAndInteract extends Behavior { - - @Override - public boolean checkExtraStartConditions(ServerLevel world, LivingEntity entity) { -- return this.selfFilter.test(entity) && this.getVisibleEntities(entity).stream().anyMatch(this::isMatchingTarget); -+ // Paper start - remove streams -+ if (!this.selfFilter.test(entity)) { -+ return false; -+ } -+ -+ List visibleEntities = this.getVisibleEntities(entity); -+ for (int i = 0; i < visibleEntities.size(); i++) { -+ LivingEntity livingEntity = visibleEntities.get(i); -+ if (this.isMatchingTarget(livingEntity)) { -+ return true; -+ } -+ } -+ return false; -+ // Paper end - remove streams - } - - @Override - public void start(ServerLevel world, LivingEntity entity, long time) { - super.start(world, entity, time); - Brain brain = entity.getBrain(); -- brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).ifPresent((list) -> { -- list.stream().filter((livingEntity2) -> { -- return livingEntity2.distanceToSqr(entity) <= (double)this.interactionRangeSqr; -- }).filter(this::isMatchingTarget).findFirst().ifPresent((livingEntity) -> { -- brain.setMemory(MemoryModuleType.INTERACTION_TARGET, livingEntity); -- brain.setMemory(MemoryModuleType.LOOK_TARGET, new EntityTracker(livingEntity, true)); -- }); -- }); -+ // Paper start - remove streams -+ List list = brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).orElse(null); -+ if (list != null) { -+ double maxRangeSquared = (double)this.interactionRangeSqr; -+ for (int i = 0; i < list.size(); i++) { -+ LivingEntity livingEntity2 = list.get(i); -+ if (livingEntity2.distanceToSqr(entity) <= maxRangeSquared) { -+ if (this.isMatchingTarget(livingEntity2)) { -+ brain.setMemory(MemoryModuleType.INTERACTION_TARGET, livingEntity2); -+ brain.setMemory(MemoryModuleType.LOOK_TARGET, new EntityTracker(livingEntity2, true)); -+ break; -+ } -+ } -+ } -+ } -+ // Paper end - remove streams - } - - private boolean isMatchingTarget(LivingEntity entity) { diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java -index 4fa64b1e2004810906bb0b174436c8e687a75ada..aaff4038867820ab2694f036dcd3c419657be6b8 100644 +index 1bc34453933bc7590af45a5559a4fc75eb3e0c5c..204ca4fbd89bdadd902529f1f191df46fce3cace 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java @@ -12,7 +12,7 @@ import java.util.Random; @@ -225,44 +169,17 @@ index 49f3b25d28072b61f5cc97260df61df892a58714..71f2692c83feafbb31f45427e6c738cb brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, Optional.ofNullable(nearest)); // Paper end } -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java -index ffd83db0a419ab589e89feeddd3fb038d6ed5839..c6947aa93b7d2fbc23b0c0e76eed061eb03140c7 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java -@@ -18,12 +18,19 @@ public class NearestLivingEntitySensor extends Sensor { - List list = world.getEntitiesOfClass(LivingEntity.class, aABB, (livingEntity2) -> { - return livingEntity2 != entity && livingEntity2.isAlive(); - }); -- list.sort(Comparator.comparingDouble(entity::distanceToSqr)); -+ // Paper start - remove streams -+ list.sort((e1, e2) -> Double.compare(entity.distanceToSqr(e1), entity.distanceToSqr(e2))); - Brain brain = entity.getBrain(); - brain.setMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES, list); - // Paper start - remove streams in favour of lists -- List visibleMobs = new java.util.ArrayList<>(list); -- visibleMobs.removeIf(otherEntityLiving -> !Sensor.isEntityTargetable(entity, otherEntityLiving)); -+ List visibleMobs = new java.util.ArrayList<>(); -+ for (int i = 0, len = list.size(); i < len; i++) { -+ LivingEntity nearby = list.get(i); -+ if (Sensor.isEntityTargetable(entity, nearby)) { -+ visibleMobs.add(nearby); -+ } -+ } -+ // Paper end - remove streams - brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, visibleMobs); - // Paper end - } diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java -index 457ea75137b8b02dc32bf1769ae8d57c470da470..217c8fd1edf664dc568ee0559a38e0bd2a36696c 100644 +index 312775d0430f793720211dc29bb293503e799d11..75d9c4f011b5a97def215784c92bb57bbb35d06b 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java -@@ -21,25 +21,31 @@ public class PlayerSensor extends Sensor { +@@ -21,25 +21,30 @@ public class PlayerSensor extends Sensor { @Override protected void doTick(ServerLevel world, LivingEntity entity) { -- // Paper start - remove streams in favour of lists - List players = new java.util.ArrayList<>(world.players()); -- players.removeIf(player -> !EntitySelector.NO_SPECTATORS.test(player) || !entity.closerThan(player, 16.0D)); // Paper - removeIf only re-allocates once compared to iterator +- players.removeIf(player -> !EntitySelector.NO_SPECTATORS.test(player) || !entity.closerThan(player, 16.0D)); +- players.sort(Comparator.comparingDouble(entity::distanceTo)); + // Paper start - remove streams + List players = (List)world.getNearbyPlayers(entity, entity.getX(), entity.getY(), entity.getZ(), 16.0D, EntitySelector.NO_SPECTATORS); + players.sort((e1, e2) -> Double.compare(entity.distanceToSqr(e1), entity.distanceToSqr(e2))); @@ -296,32 +213,8 @@ index 457ea75137b8b02dc32bf1769ae8d57c470da470..217c8fd1edf664dc568ee0559a38e0bd - brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER, nearest); - brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, nearestTargetable); - // Paper end -+ + brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER, firstTargetable); + brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, Optional.ofNullable(firstAttackable)); + // Paper end - remove streams } } -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java -index 478010bc291fa3276aab0f66ce6283403af710ec..de39b608856bdf9bef7120a6922c01c5745f3771 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java -@@ -22,7 +22,17 @@ public class VillagerBabiesSensor extends Sensor { - } - - private List getNearestVillagerBabies(LivingEntity entities) { -- return this.getVisibleEntities(entities).stream().filter(this::isVillagerBaby).collect(Collectors.toList()); -+ // Paper start - remove streams -+ List list = new java.util.ArrayList<>(); -+ List visibleEntities = this.getVisibleEntities(entities); -+ for (int i = 0; i < visibleEntities.size(); i++) { -+ LivingEntity livingEntity = visibleEntities.get(i); -+ if (this.isVillagerBaby(livingEntity)) { -+ list.add(livingEntity); -+ } -+ } -+ return list; -+ // Paper end - remove streams - } - - private boolean isVillagerBaby(LivingEntity entity) { diff --git a/patches/unapplied/server/0796-Rewrite-dataconverter-system.patch b/patches/server/0770-Rewrite-dataconverter-system.patch similarity index 94% rename from patches/unapplied/server/0796-Rewrite-dataconverter-system.patch rename to patches/server/0770-Rewrite-dataconverter-system.patch index cc35e27dfc..c95c2b73e9 100644 --- a/patches/unapplied/server/0796-Rewrite-dataconverter-system.patch +++ b/patches/server/0770-Rewrite-dataconverter-system.patch @@ -111,10 +111,10 @@ index 0000000000000000000000000000000000000000..cf9fae4451ead4860343b915fb70e3a7 +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCDataConverter.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCDataConverter.java new file mode 100644 -index 0000000000000000000000000000000000000000..64f442922a9ca26a723653acb7a5398fca6076fd +index 0000000000000000000000000000000000000000..25f1f4c355c1b4aca12e366f100922c53b4db1c6 --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCDataConverter.java -@@ -0,0 +1,69 @@ +@@ -0,0 +1,90 @@ +package ca.spottedleaf.dataconverter.minecraft; + +import ca.spottedleaf.dataconverter.converters.DataConverter; @@ -130,6 +130,27 @@ index 0000000000000000000000000000000000000000..64f442922a9ca26a723653acb7a5398f + + private static final LongArrayList BREAKPOINTS = MCVersionRegistry.getBreakpoints(); + ++ public static T copy(final T type) { ++ if (type instanceof CompoundTag) { ++ return (T)((CompoundTag)type).copy(); ++ } else if (type instanceof JsonObject) { ++ return (T)((JsonObject)type).deepCopy(); ++ } ++ ++ return type; ++ } ++ ++ public static R convertUnwrapped(final DataType type, final T data, final boolean compressedJson, final int fromVersion, final int toVersion) { ++ if (data instanceof CompoundTag) { ++ return (R)convertTag((MCDataType)type, (CompoundTag)data, fromVersion, toVersion); ++ } ++ if (data instanceof JsonObject) { ++ return (R)convertJson((MCDataType)type, (JsonObject)data, compressedJson, fromVersion, toVersion); ++ } ++ ++ return convert(type, data, fromVersion, toVersion); ++ } ++ + public static CompoundTag convertTag(final MCDataType type, final CompoundTag data, final int fromVersion, final int toVersion) { + final NBTMapType wrapped = new NBTMapType(data); + @@ -186,10 +207,10 @@ index 0000000000000000000000000000000000000000..64f442922a9ca26a723653acb7a5398f +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersionRegistry.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersionRegistry.java new file mode 100644 -index 0000000000000000000000000000000000000000..321b69f2353202b08de6c364d13340a80c0e077d +index 0000000000000000000000000000000000000000..016420effa89f3243479a966bf7aed286e82be1c --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersionRegistry.java -@@ -0,0 +1,332 @@ +@@ -0,0 +1,343 @@ +package ca.spottedleaf.dataconverter.minecraft; + +import ca.spottedleaf.dataconverter.converters.DataConverter; @@ -356,6 +377,7 @@ index 0000000000000000000000000000000000000000..321b69f2353202b08de6c364d13340a8 + 2688, + 2690, + 2691, ++ 2693, + 2696, + 2700, + 2701, @@ -363,8 +385,18 @@ index 0000000000000000000000000000000000000000..321b69f2353202b08de6c364d13340a8 + 2704, + 2707, + 2710, -+ 2717 -+ // All up to 1.17.1 ++ 2717, ++ 2825, ++ 2831, ++ 2832, ++ 2833, ++ 2838, ++ 2841, ++ 2842, ++ 2843, ++ 2846, ++ 2852, ++ // All up to 1.18-pre6 + }; + Arrays.sort(converterVersions); + @@ -382,7 +414,7 @@ index 0000000000000000000000000000000000000000..321b69f2353202b08de6c364d13340a8 + registerSubVersion(MCVersions.V17W47A, 7); + + // register breakpoints here -+ // for all major releases after 1.16, add them here. this reduces the work required to determine if a breakpoint ++ // for all major releases after 1.16, add them. this reduces the work required to determine if a breakpoint + // is needed for new converters + + // Too much changed in this version. @@ -524,10 +556,10 @@ index 0000000000000000000000000000000000000000..321b69f2353202b08de6c364d13340a8 +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersions.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersions.java new file mode 100644 -index 0000000000000000000000000000000000000000..6b954f25089aa8bb66359280d4aca596e3f8530f +index 0000000000000000000000000000000000000000..ba8c1f056aa77d3812fb02f2a60ddd192e68984f --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/MCVersions.java -@@ -0,0 +1,366 @@ +@@ -0,0 +1,380 @@ +package ca.spottedleaf.dataconverter.minecraft; + +@SuppressWarnings("unused") @@ -893,16 +925,177 @@ index 0000000000000000000000000000000000000000..6b954f25089aa8bb66359280d4aca596 + public static final int V1_17_1_RC1 = 2728; + public static final int V1_17_1_RC2 = 2729; + public static final int V1_17_1 = 2730; ++ public static final int V21W37A = 2834; ++ public static final int V21W38A = 2835; ++ public static final int V21W39A = 2836; ++ public static final int V21W40A = 2838; ++ public static final int V21W41A = 2839; ++ public static final int V21W42A = 2840; ++ public static final int V21W43A = 2844; ++ public static final int V21W44A = 2845; ++ public static final int V1_18_PRE1 = 2847; ++ public static final int V1_18_PRE2 = 2848; ++ public static final int V1_18_PRE3 = 2849; ++ public static final int V1_18_PRE4 = 2850; ++ public static final int V1_18_PRE5 = 2851; ++ public static final int V1_18_PRE6 = 2853; ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/ReplacedDataFixerUpper.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/ReplacedDataFixerUpper.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5ddf54649fc0ddcee1b1f6bdc6e8d7be7ae46618 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/ReplacedDataFixerUpper.java +@@ -0,0 +1,140 @@ ++package ca.spottedleaf.dataconverter.minecraft; ++ ++import ca.spottedleaf.dataconverter.converters.datatypes.DataType; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import com.mojang.datafixers.DSL; ++import com.mojang.datafixers.DataFixer; ++import com.mojang.datafixers.schemas.Schema; ++import com.mojang.serialization.Dynamic; ++import net.minecraft.SharedConstants; ++import net.minecraft.util.datafix.fixes.References; ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.Logger; ++import java.util.Set; ++import java.util.concurrent.ConcurrentHashMap; ++ ++public class ReplacedDataFixerUpper implements DataFixer { ++ ++ protected static final Set WARNED_TYPES = ConcurrentHashMap.newKeySet(); ++ ++ private static final Logger LOGGER = LogManager.getLogger(); ++ ++ public final DataFixer wrapped; ++ ++ public ReplacedDataFixerUpper(final DataFixer wrapped) { ++ this.wrapped = wrapped; ++ } ++ ++ @Override ++ public Dynamic update(final DSL.TypeReference type, final Dynamic input, final int version, final int newVersion) { ++ DataType equivType = null; ++ boolean warn = true; ++ ++ if (type == References.LEVEL) { ++ warn = false; ++ } ++ if (type == References.PLAYER) { ++ equivType = MCTypeRegistry.PLAYER; ++ } ++ if (type == References.CHUNK) { ++ equivType = MCTypeRegistry.CHUNK; ++ } ++ if (type == References.HOTBAR) { ++ warn = false; ++ } ++ if (type == References.OPTIONS) { ++ warn = false; ++ } ++ if (type == References.STRUCTURE) { ++ equivType = MCTypeRegistry.STRUCTURE; ++ } ++ if (type == References.STATS) { ++ warn = false; ++ } ++ if (type == References.SAVED_DATA) { ++ equivType = MCTypeRegistry.SAVED_DATA; ++ } ++ if (type == References.ADVANCEMENTS) { ++ warn = false; ++ } ++ if (type == References.POI_CHUNK) { ++ equivType = MCTypeRegistry.POI_CHUNK; ++ } ++ if (type == References.ENTITY_CHUNK) { ++ equivType = MCTypeRegistry.ENTITY_CHUNK; ++ } ++ if (type == References.BLOCK_ENTITY) { ++ equivType = MCTypeRegistry.TILE_ENTITY; ++ } ++ if (type == References.ITEM_STACK) { ++ equivType = MCTypeRegistry.ITEM_STACK; ++ } ++ if (type == References.BLOCK_STATE) { ++ equivType = MCTypeRegistry.BLOCK_STATE; ++ } ++ if (type == References.ENTITY_NAME) { ++ equivType = MCTypeRegistry.ENTITY_NAME; ++ } ++ if (type == References.ENTITY_TREE) { ++ equivType = MCTypeRegistry.ENTITY; ++ } ++ if (type == References.ENTITY) { ++ // NO EQUIV TYPE (this is ENTITY without passengers/riding) ++ // Only used internally for DFU, so we shouldn't get here ++ } ++ if (type == References.BLOCK_NAME) { ++ equivType = MCTypeRegistry.BLOCK_NAME; ++ } ++ if (type == References.ITEM_NAME) { ++ equivType = MCTypeRegistry.ITEM_NAME; ++ } ++ if (type == References.UNTAGGED_SPAWNER) { ++ equivType = MCTypeRegistry.UNTAGGED_SPAWNER; ++ } ++ if (type == References.STRUCTURE_FEATURE) { ++ equivType = MCTypeRegistry.STRUCTURE_FEATURE; ++ } ++ if (type == References.OBJECTIVE) { ++ warn = false; ++ } ++ if (type == References.TEAM) { ++ warn = false; ++ } ++ if (type == References.RECIPE) { ++ warn = false; ++ } ++ if (type == References.BIOME) { ++ equivType = MCTypeRegistry.BIOME; ++ } ++ if (type == References.WORLD_GEN_SETTINGS) { ++ warn = false; ++ } ++ ++ if (equivType != null) { ++ if (newVersion > version) { ++ try { ++ final Dynamic ret = new Dynamic<>(input.getOps(), (T)MCDataConverter.copy(MCDataConverter.convertUnwrapped((DataType)equivType, input.getValue(), false, version, newVersion))); ++ return ret; ++ } catch (final Exception ex) { ++ LOGGER.error("Failed to convert data using DataConverter, falling back to DFU", new Throwable()); ++ // In dev environment this should hard fail ++ } ++ ++ return this.wrapped.update(type, input, version, newVersion); ++ } else { ++ return input; ++ } ++ } else { ++ if (warn && WARNED_TYPES.add(type)) { ++ LOGGER.error("No equiv type for " + type, new Throwable()); ++ } ++ ++ return this.wrapped.update(type, input, version, newVersion); ++ } ++ } ++ ++ @Override ++ public Schema getSchema(final int key) { ++ return this.wrapped.getSchema(key); ++ } +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/advancements/ConverterAbstractAdvancementsRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/advancements/ConverterAbstractAdvancementsRename.java new file mode 100644 -index 0000000000000000000000000000000000000000..c92e198b1cc20655e404f67b2af4ca493aad2f6d +index 0000000000000000000000000000000000000000..ae3aed21c1fccb688e9a1665e2d317a77508d157 --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/advancements/ConverterAbstractAdvancementsRename.java -@@ -0,0 +1,34 @@ +@@ -0,0 +1,28 @@ +package ca.spottedleaf.dataconverter.minecraft.converters.advancements; + +import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.RenameHelper; +import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; +import ca.spottedleaf.dataconverter.types.MapType; +import java.util.ArrayList; @@ -920,14 +1113,7 @@ index 0000000000000000000000000000000000000000..c92e198b1cc20655e404f67b2af4ca49 + MCTypeRegistry.ADVANCEMENTS.addStructureConverter(new DataConverter<>(version, subVersion) { + @Override + public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ for (final String key : new ArrayList<>(data.keys())) { -+ final String updated = renamer.apply(key); -+ if (updated != null) { -+ final Object value = data.getGeneric(key); -+ data.remove(key); -+ data.setGeneric(updated, value); -+ } -+ } ++ RenameHelper.renameKeys(data, renamer); + return null; + } + }); @@ -2456,6 +2642,42 @@ index 0000000000000000000000000000000000000000..afad2d92f78d4727ff4440ad2778f018 + return null; + } +} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/AddFlagIfAbsent.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/AddFlagIfAbsent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4ab607f946782cc483535564e86fa9753dd7897a +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/AddFlagIfAbsent.java +@@ -0,0 +1,30 @@ ++package ca.spottedleaf.dataconverter.minecraft.converters.helpers; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.types.MapType; ++ ++public final class AddFlagIfAbsent extends DataConverter, MapType> { ++ ++ public final String path; ++ public final boolean dfl; ++ ++ public AddFlagIfAbsent(final int toVersion, final String path, final boolean dfl) { ++ super(toVersion); ++ this.path = path; ++ this.dfl = dfl; ++ } ++ ++ public AddFlagIfAbsent(final int toVersion, final int versionStep, final String path, final boolean dfl) { ++ super(toVersion, versionStep); ++ this.path = path; ++ this.dfl = dfl; ++ } ++ ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ if (!data.hasKey(this.path)) { ++ data.setBoolean(this.path, this.dfl); ++ } ++ return null; ++ } ++} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/ConverterAbstractStringValueTypeRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/ConverterAbstractStringValueTypeRename.java new file mode 100644 index 0000000000000000000000000000000000000000..bc79670f47aaa413ea3e96ef6a32e14099ad8a58 @@ -4979,6 +5201,70 @@ index 0000000000000000000000000000000000000000..5008c6d28b7f9b730bfaf257a264edcb + return ID_TO_STRING[id & 255]; + } +} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/RenameHelper.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/RenameHelper.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fb235cf3b597abb8c6557def215efac7cc1a53f5 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/helpers/RenameHelper.java +@@ -0,0 +1,58 @@ ++package ca.spottedleaf.dataconverter.minecraft.converters.helpers; ++ ++import ca.spottedleaf.dataconverter.types.MapType; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.function.Function; ++ ++public final class RenameHelper { ++ ++ // assumes no two or more entries are renamed to a single value, otherwise result will be only one of them will win ++ // and there is no defined winner in such a case ++ public static void renameKeys(final MapType data, final Function renamer) { ++ boolean needsRename = false; ++ for (final String key : data.keys()) { ++ if (renamer.apply(key) != null) { ++ needsRename = true; ++ break; ++ } ++ } ++ ++ if (!needsRename) { ++ return; ++ } ++ ++ final List newKeys = new ArrayList<>(); ++ final List newValues = new ArrayList<>(); ++ ++ for (final String key : new ArrayList<>(data.keys())) { ++ final String renamed = renamer.apply(key); ++ ++ if (renamed != null) { ++ newValues.add(data.getGeneric(key)); ++ newKeys.add(renamed); ++ data.remove(key); ++ } ++ } ++ ++ // insert new keys ++ for (int i = 0, len = newKeys.size(); i < len; ++i) { ++ final String key = newKeys.get(i); ++ final Object value = newValues.get(i); ++ ++ data.setGeneric(key, value); ++ } ++ } ++ ++ // Clobbers anything in toKey if fromKey exists ++ public static void renameSingle(final MapType data, final String fromKey, final String toKey) { ++ final Object value = data.getGeneric(fromKey); ++ if (value != null) { ++ data.remove(fromKey); ++ data.setGeneric(toKey, value); ++ } ++ } ++ ++ private RenameHelper() {} ++ ++} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemname/ConverterAbstractItemRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemname/ConverterAbstractItemRename.java new file mode 100644 index 0000000000000000000000000000000000000000..94569f0ccff0d3a09eafd4ba73572d9db0a0ac5b @@ -5561,13 +5847,14 @@ index 0000000000000000000000000000000000000000..d88b12e6b9e381ba614dc04599a44e47 +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/options/ConverterAbstractOptionsRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/options/ConverterAbstractOptionsRename.java new file mode 100644 -index 0000000000000000000000000000000000000000..8bfcaac8caa858d3696ed7a430f2b246857b3ac4 +index 0000000000000000000000000000000000000000..769dd8447976b66dcfc36283ede4ae16f1e4206d --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/options/ConverterAbstractOptionsRename.java -@@ -0,0 +1,33 @@ +@@ -0,0 +1,28 @@ +package ca.spottedleaf.dataconverter.minecraft.converters.options; + +import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.RenameHelper; +import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; +import ca.spottedleaf.dataconverter.types.MapType; +import java.util.ArrayList; @@ -5585,13 +5872,7 @@ index 0000000000000000000000000000000000000000..8bfcaac8caa858d3696ed7a430f2b246 + MCTypeRegistry.OPTIONS.addStructureConverter(new DataConverter<>(version, subVersion) { + @Override + public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { -+ for (final String key : new ArrayList<>(data.keys())) { -+ final String updated = renamer.apply(key); -+ if (updated != null) { -+ data.setGeneric(updated, data.getGeneric(key)); -+ data.remove(key); -+ } -+ } ++ RenameHelper.renameKeys(data, renamer); + return null; + } + }); @@ -5683,13 +5964,14 @@ index 0000000000000000000000000000000000000000..8f35cbbd78a629712f9ae3cd5d180269 +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/stats/ConverterAbstractStatsRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/stats/ConverterAbstractStatsRename.java new file mode 100644 -index 0000000000000000000000000000000000000000..2317d6dd7e609095187168a1fb9a684ce540ec0e +index 0000000000000000000000000000000000000000..a1985c85aa9193699d7d20e6f4f11b6e9744ee70 --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/stats/ConverterAbstractStatsRename.java -@@ -0,0 +1,75 @@ +@@ -0,0 +1,66 @@ +package ca.spottedleaf.dataconverter.minecraft.converters.stats; + +import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.RenameHelper; +import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; +import ca.spottedleaf.dataconverter.types.MapType; +import java.util.ArrayList; @@ -5745,17 +6027,7 @@ index 0000000000000000000000000000000000000000..2317d6dd7e609095187168a1fb9a684c + return null; + } + -+ for (final String key : new ArrayList<>(custom.keys())) { -+ final String rename = renamer.apply(key); -+ if (rename == null) { -+ continue; -+ } -+ -+ final Object value = custom.getGeneric(key); -+ custom.remove(key); -+ -+ custom.setGeneric(rename, value); -+ } ++ RenameHelper.renameKeys(custom, renamer); + + return null; + } @@ -5864,10 +6136,10 @@ index 0000000000000000000000000000000000000000..99d2c2c84820295be1f8bb0b43784e58 +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/IDDataType.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/IDDataType.java new file mode 100644 -index 0000000000000000000000000000000000000000..885467de6a5928faafab867dda79b035868ce222 +index 0000000000000000000000000000000000000000..b2c2b4c4ae83f14639fa53e38f2c75ccd284c2d2 --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/IDDataType.java -@@ -0,0 +1,163 @@ +@@ -0,0 +1,166 @@ +package ca.spottedleaf.dataconverter.minecraft.datatypes; + +import ca.spottedleaf.dataconverter.converters.DataConverter; @@ -5953,7 +6225,7 @@ index 0000000000000000000000000000000000000000..885467de6a5928faafab867dda79b035 + break; + } + -+ final List, MapType>> hooks = this.structureHooks.getFloor(converterVersion); ++ List, MapType>> hooks = this.structureHooks.getFloor(converterVersion); + + if (hooks != null) { + for (int k = 0, klen = hooks.size(); k < klen; ++k) { @@ -5969,6 +6241,9 @@ index 0000000000000000000000000000000000000000..885467de6a5928faafab867dda79b035 + ret = data = replace; + } + ++ // possibly new data format, update hooks ++ hooks = this.structureHooks.getFloor(toVersion); ++ + if (hooks != null) { + for (int klen = hooks.size(), k = klen - 1; k >= 0; --k) { + final MapType postReplace = hooks.get(k).postHook(data, fromVersion, toVersion); @@ -6033,10 +6308,10 @@ index 0000000000000000000000000000000000000000..885467de6a5928faafab867dda79b035 +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCDataType.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCDataType.java new file mode 100644 -index 0000000000000000000000000000000000000000..e997192e13286ff910885a8e5074a283c1269ea4 +index 0000000000000000000000000000000000000000..76a6e3efa5c69150e8f5e0063cb6357bed1bffae --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCDataType.java -@@ -0,0 +1,126 @@ +@@ -0,0 +1,129 @@ +package ca.spottedleaf.dataconverter.minecraft.datatypes; + +import ca.spottedleaf.dataconverter.converters.DataConverter; @@ -6104,7 +6379,7 @@ index 0000000000000000000000000000000000000000..e997192e13286ff910885a8e5074a283 + break; + } + -+ final List, MapType>> hooks = this.structureHooks.getFloor(converterVersion); ++ List, MapType>> hooks = this.structureHooks.getFloor(converterVersion); + + if (hooks != null) { + for (int k = 0, klen = hooks.size(); k < klen; ++k) { @@ -6120,6 +6395,9 @@ index 0000000000000000000000000000000000000000..e997192e13286ff910885a8e5074a283 + ret = data = replace; + } + ++ // possibly new data format, update hooks ++ hooks = this.structureHooks.getFloor(toVersion); ++ + if (hooks != null) { + for (int klen = hooks.size(), k = klen - 1; k >= 0; --k) { + final MapType postReplace = hooks.get(k).postHook(data, fromVersion, toVersion); @@ -6165,10 +6443,10 @@ index 0000000000000000000000000000000000000000..e997192e13286ff910885a8e5074a283 +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCTypeRegistry.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCTypeRegistry.java new file mode 100644 -index 0000000000000000000000000000000000000000..2f5a9e04e3797673f49a035eebfedd1b90c81b07 +index 0000000000000000000000000000000000000000..40fa4f9b8ad8c658ec43e1b4a9d3dec7de4744da --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCTypeRegistry.java -@@ -0,0 +1,316 @@ +@@ -0,0 +1,339 @@ +package ca.spottedleaf.dataconverter.minecraft.datatypes; + +import ca.spottedleaf.dataconverter.minecraft.versions.V100; @@ -6276,6 +6554,7 @@ index 0000000000000000000000000000000000000000..2f5a9e04e3797673f49a035eebfedd1b +import ca.spottedleaf.dataconverter.minecraft.versions.V2688; +import ca.spottedleaf.dataconverter.minecraft.versions.V2690; +import ca.spottedleaf.dataconverter.minecraft.versions.V2691; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2693; +import ca.spottedleaf.dataconverter.minecraft.versions.V2696; +import ca.spottedleaf.dataconverter.minecraft.versions.V2700; +import ca.spottedleaf.dataconverter.minecraft.versions.V2701; @@ -6283,6 +6562,16 @@ index 0000000000000000000000000000000000000000..2f5a9e04e3797673f49a035eebfedd1b +import ca.spottedleaf.dataconverter.minecraft.versions.V2707; +import ca.spottedleaf.dataconverter.minecraft.versions.V2710; +import ca.spottedleaf.dataconverter.minecraft.versions.V2717; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2825; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2831; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2832; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2833; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2838; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2841; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2842; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2843; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2846; ++import ca.spottedleaf.dataconverter.minecraft.versions.V2852; +import ca.spottedleaf.dataconverter.minecraft.versions.V501; +import ca.spottedleaf.dataconverter.minecraft.versions.V502; +import ca.spottedleaf.dataconverter.minecraft.versions.V505; @@ -6473,6 +6762,7 @@ index 0000000000000000000000000000000000000000..2f5a9e04e3797673f49a035eebfedd1b + V2688.register(); + V2690.register(); + V2691.register(); ++ V2693.register(); + V2696.register(); + V2700.register(); + V2701.register(); @@ -6481,16 +6771,27 @@ index 0000000000000000000000000000000000000000..2f5a9e04e3797673f49a035eebfedd1b + V2707.register(); + V2710.register(); + V2717.register(); ++ // V1.18 ++ V2825.register(); ++ V2831.register(); ++ V2832.register(); ++ V2833.register(); ++ V2838.register(); ++ V2841.register(); ++ V2842.register(); ++ V2843.register(); ++ V2846.register(); ++ V2852.register(); + } + + private MCTypeRegistry() {} +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCValueType.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCValueType.java new file mode 100644 -index 0000000000000000000000000000000000000000..c7ace3088f8059a3bae12ec21604b2b7417a7b90 +index 0000000000000000000000000000000000000000..13c1381261909ef672fbeb665907f01f2d5c1ced --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/datatypes/MCValueType.java -@@ -0,0 +1,83 @@ +@@ -0,0 +1,86 @@ +package ca.spottedleaf.dataconverter.minecraft.datatypes; + +import ca.spottedleaf.dataconverter.converters.DataConverter; @@ -6545,7 +6846,7 @@ index 0000000000000000000000000000000000000000..c7ace3088f8059a3bae12ec21604b2b7 + break; + } + -+ final List> hooks = this.structureHooks.getFloor(converterVersion); ++ List> hooks = this.structureHooks.getFloor(converterVersion); + + if (hooks != null) { + for (int k = 0, klen = hooks.size(); k < klen; ++k) { @@ -6561,6 +6862,9 @@ index 0000000000000000000000000000000000000000..c7ace3088f8059a3bae12ec21604b2b7 + ret = converted; + } + ++ // possibly new data format, update hooks ++ hooks = this.structureHooks.getFloor(toVersion); ++ + if (hooks != null) { + for (int k = 0, klen = hooks.size(); k < klen; ++k) { + final Object replace = hooks.get(k).postHook(ret == null ? data : ret, fromVersion, toVersion); @@ -11883,7 +12187,7 @@ index 0000000000000000000000000000000000000000..d905043c4f3071e8dc340ac2afe2b81a +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2202.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2202.java new file mode 100644 -index 0000000000000000000000000000000000000000..b64183295fea0550ebd6e69e476155c8783f4120 +index 0000000000000000000000000000000000000000..0bb378ac8e8d0a087359361281644a7f39cecfbe --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2202.java @@ -0,0 +1,50 @@ @@ -11911,7 +12215,7 @@ index 0000000000000000000000000000000000000000..b64183295fea0550ebd6e69e476155c8 + + final int[] oldBiomes = level.getInts("Biomes"); + -+ if (oldBiomes == null) { ++ if (oldBiomes == null || oldBiomes.length != 256) { + return null; + } + @@ -11924,7 +12228,7 @@ index 0000000000000000000000000000000000000000..b64183295fea0550ebd6e69e476155c8 + int k = (j << 2) + 2; + int l = (n << 2) + 2; + int m = l << 4 | k; -+ newBiomes[n << 2 | j] = m < oldBiomes.length ? oldBiomes[m] : -1; ++ newBiomes[n << 2 | j] = oldBiomes[m]; + } + } + @@ -14501,6 +14805,27 @@ index 0000000000000000000000000000000000000000..3841780d52c2e242609fc076efa5902c + ConverterAbstractBlockRename.registerAndFixJigsaw(VERSION, RENAMES::get); + } +} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2693.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2693.java +new file mode 100644 +index 0000000000000000000000000000000000000000..deac34afe6a3681db9a7630ad6526f71d4dd6e1f +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2693.java +@@ -0,0 +1,15 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.AddFlagIfAbsent; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++ ++public final class V2693 { ++ ++ protected static final int VERSION = MCVersions.V21W05B + 1; ++ ++ public static void register() { ++ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureConverter(new AddFlagIfAbsent(VERSION, "has_increased_height_already", false)); ++ } ++ ++} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2696.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2696.java new file mode 100644 index 0000000000000000000000000000000000000000..0094154c1da7cb95120e01bceeb836ca7ab68e25 @@ -14568,10 +14893,10 @@ index 0000000000000000000000000000000000000000..c37142033061a3e4865686ee64d8f15f +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2701.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2701.java new file mode 100644 -index 0000000000000000000000000000000000000000..47eb9e3b454af3ae5d88be5107c68bebc001a82b +index 0000000000000000000000000000000000000000..9d6b03410c4665e19a2a35226d11f77b2cae3bbf --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2701.java -@@ -0,0 +1,209 @@ +@@ -0,0 +1,203 @@ +package ca.spottedleaf.dataconverter.minecraft.versions; + +import ca.spottedleaf.dataconverter.converters.DataConverter; @@ -14632,12 +14957,6 @@ index 0000000000000000000000000000000000000000..47eb9e3b454af3ae5d88be5107c68beb + continue; + } + -+ final String featureName = feature.getString("name"); -+ -+ if (featureName == null) { -+ continue; -+ } -+ + final String replacement = convertToString(feature); + + if (replacement != null) { @@ -14822,13 +15141,14 @@ index 0000000000000000000000000000000000000000..53e45b14c05dab35cd5725998458d47e +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2707.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2707.java new file mode 100644 -index 0000000000000000000000000000000000000000..9acd9ed381063f93bfe74cf78db5cb8b87dfbcd5 +index 0000000000000000000000000000000000000000..74c1df97036059b3a5147f7cf94752ef4516a33d --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2707.java -@@ -0,0 +1,18 @@ +@@ -0,0 +1,21 @@ +package ca.spottedleaf.dataconverter.minecraft.versions; + +import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.AddFlagIfAbsent; +import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; +import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; + @@ -14841,6 +15161,8 @@ index 0000000000000000000000000000000000000000..9acd9ed381063f93bfe74cf78db5cb8b + } + + public static void register() { ++ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureConverter(new AddFlagIfAbsent(VERSION, "has_increased_height_already", true)); ++ + registerMob("minecraft:marker"); // ????????????? + } +} @@ -14893,6 +15215,1503 @@ index 0000000000000000000000000000000000000000..8678ba95b5abe96b399a310623078f88 + } + +} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2825.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2825.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c2d2b7c10e5b988b1111b20b778c475a12bef353 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2825.java +@@ -0,0 +1,15 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.AddFlagIfAbsent; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++ ++public final class V2825 { ++ ++ protected static final int VERSION = MCVersions.V1_17_1 + 95; ++ ++ public static void register() { ++ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureConverter(new AddFlagIfAbsent(VERSION, "has_increased_height_already", false)); ++ } ++ ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2831.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2831.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d28ade80499dce882a9a84309a2a0da527fe01a0 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2831.java +@@ -0,0 +1,69 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; ++import ca.spottedleaf.dataconverter.types.ListType; ++import ca.spottedleaf.dataconverter.types.MapType; ++import ca.spottedleaf.dataconverter.types.ObjectType; ++import ca.spottedleaf.dataconverter.types.Types; ++ ++public final class V2831 { ++ ++ protected static final int VERSION = MCVersions.V1_17_1 + 101; ++ ++ public static void register() { ++ MCTypeRegistry.UNTAGGED_SPAWNER.addStructureWalker(VERSION, (final MapType root, final long fromVersion, final long toVersion) -> { ++ final ListType spawnPotentials = root.getList("SpawnPotentials", ObjectType.MAP); ++ if (spawnPotentials != null) { ++ for (int i = 0, len = spawnPotentials.size(); i < len; ++i) { ++ final MapType spawnPotential = spawnPotentials.getMap(i); ++ ++ WalkerUtils.convert(MCTypeRegistry.ENTITY, spawnPotential.getMap("data"), "entity", fromVersion, toVersion); ++ } ++ } ++ ++ WalkerUtils.convert(MCTypeRegistry.ENTITY, root.getMap("SpawnData"), "entity", fromVersion, toVersion); ++ ++ return null; ++ }); ++ ++ MCTypeRegistry.UNTAGGED_SPAWNER.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType root, final long sourceVersion, final long toVersion) { ++ final MapType spawnData = root.getMap("SpawnData"); ++ if (spawnData != null) { ++ final MapType wrapped = Types.NBT.createEmptyMap(); ++ root.setMap("SpawnData", wrapped); ++ ++ wrapped.setMap("entity", spawnData); ++ } ++ ++ final ListType spawnPotentials = root.getList("SpawnPotentials", ObjectType.MAP); ++ if (spawnPotentials != null) { ++ for (int i = 0, len = spawnPotentials.size(); i < len; ++i) { ++ final MapType spawnPotential = spawnPotentials.getMap(i); ++ ++ // new format of weighted list (SpawnPotentials): ++ // root.data -> data ++ // root.weight -> weight ++ ++ final MapType entity = spawnPotential.getMap("Entity"); ++ final int weight = spawnPotential.getInt("Weight", 1); ++ spawnPotential.remove("Entity"); ++ spawnPotential.remove("Weight"); ++ spawnPotential.setInt("weight", weight); ++ ++ final MapType data = Types.NBT.createEmptyMap(); ++ spawnPotential.setMap("data", data); ++ ++ data.setMap("entity", entity); ++ } ++ } ++ ++ return null; ++ } ++ }); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2832.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2832.java +new file mode 100644 +index 0000000000000000000000000000000000000000..68971097a9d9a1be63258518985d406d2a3392d8 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2832.java +@@ -0,0 +1,924 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.RenameHelper; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; ++import ca.spottedleaf.dataconverter.types.ListType; ++import ca.spottedleaf.dataconverter.types.MapType; ++import ca.spottedleaf.dataconverter.types.ObjectType; ++import ca.spottedleaf.dataconverter.types.Types; ++import it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap; ++import it.unimi.dsi.fastutil.ints.IntIterator; ++import it.unimi.dsi.fastutil.ints.IntOpenHashSet; ++import org.apache.commons.lang3.mutable.MutableBoolean; ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.Logger; ++import java.util.Arrays; ++import java.util.BitSet; ++import java.util.HashSet; ++import java.util.Set; ++ ++public final class V2832 { ++ ++ protected static final Logger LOGGER = LogManager.getLogger(); ++ ++ protected static final int VERSION = MCVersions.V1_17_1 + 102; ++ ++ private static final String[] BIOMES_BY_ID = new String[256]; // rip datapacks ++ static { ++ BIOMES_BY_ID[0] = "minecraft:ocean"; ++ BIOMES_BY_ID[1] = "minecraft:plains"; ++ BIOMES_BY_ID[2] = "minecraft:desert"; ++ BIOMES_BY_ID[3] = "minecraft:mountains"; ++ BIOMES_BY_ID[4] = "minecraft:forest"; ++ BIOMES_BY_ID[5] = "minecraft:taiga"; ++ BIOMES_BY_ID[6] = "minecraft:swamp"; ++ BIOMES_BY_ID[7] = "minecraft:river"; ++ BIOMES_BY_ID[8] = "minecraft:nether_wastes"; ++ BIOMES_BY_ID[9] = "minecraft:the_end"; ++ BIOMES_BY_ID[10] = "minecraft:frozen_ocean"; ++ BIOMES_BY_ID[11] = "minecraft:frozen_river"; ++ BIOMES_BY_ID[12] = "minecraft:snowy_tundra"; ++ BIOMES_BY_ID[13] = "minecraft:snowy_mountains"; ++ BIOMES_BY_ID[14] = "minecraft:mushroom_fields"; ++ BIOMES_BY_ID[15] = "minecraft:mushroom_field_shore"; ++ BIOMES_BY_ID[16] = "minecraft:beach"; ++ BIOMES_BY_ID[17] = "minecraft:desert_hills"; ++ BIOMES_BY_ID[18] = "minecraft:wooded_hills"; ++ BIOMES_BY_ID[19] = "minecraft:taiga_hills"; ++ BIOMES_BY_ID[20] = "minecraft:mountain_edge"; ++ BIOMES_BY_ID[21] = "minecraft:jungle"; ++ BIOMES_BY_ID[22] = "minecraft:jungle_hills"; ++ BIOMES_BY_ID[23] = "minecraft:jungle_edge"; ++ BIOMES_BY_ID[24] = "minecraft:deep_ocean"; ++ BIOMES_BY_ID[25] = "minecraft:stone_shore"; ++ BIOMES_BY_ID[26] = "minecraft:snowy_beach"; ++ BIOMES_BY_ID[27] = "minecraft:birch_forest"; ++ BIOMES_BY_ID[28] = "minecraft:birch_forest_hills"; ++ BIOMES_BY_ID[29] = "minecraft:dark_forest"; ++ BIOMES_BY_ID[30] = "minecraft:snowy_taiga"; ++ BIOMES_BY_ID[31] = "minecraft:snowy_taiga_hills"; ++ BIOMES_BY_ID[32] = "minecraft:giant_tree_taiga"; ++ BIOMES_BY_ID[33] = "minecraft:giant_tree_taiga_hills"; ++ BIOMES_BY_ID[34] = "minecraft:wooded_mountains"; ++ BIOMES_BY_ID[35] = "minecraft:savanna"; ++ BIOMES_BY_ID[36] = "minecraft:savanna_plateau"; ++ BIOMES_BY_ID[37] = "minecraft:badlands"; ++ BIOMES_BY_ID[38] = "minecraft:wooded_badlands_plateau"; ++ BIOMES_BY_ID[39] = "minecraft:badlands_plateau"; ++ BIOMES_BY_ID[40] = "minecraft:small_end_islands"; ++ BIOMES_BY_ID[41] = "minecraft:end_midlands"; ++ BIOMES_BY_ID[42] = "minecraft:end_highlands"; ++ BIOMES_BY_ID[43] = "minecraft:end_barrens"; ++ BIOMES_BY_ID[44] = "minecraft:warm_ocean"; ++ BIOMES_BY_ID[45] = "minecraft:lukewarm_ocean"; ++ BIOMES_BY_ID[46] = "minecraft:cold_ocean"; ++ BIOMES_BY_ID[47] = "minecraft:deep_warm_ocean"; ++ BIOMES_BY_ID[48] = "minecraft:deep_lukewarm_ocean"; ++ BIOMES_BY_ID[49] = "minecraft:deep_cold_ocean"; ++ BIOMES_BY_ID[50] = "minecraft:deep_frozen_ocean"; ++ BIOMES_BY_ID[127] = "minecraft:the_void"; ++ BIOMES_BY_ID[129] = "minecraft:sunflower_plains"; ++ BIOMES_BY_ID[130] = "minecraft:desert_lakes"; ++ BIOMES_BY_ID[131] = "minecraft:gravelly_mountains"; ++ BIOMES_BY_ID[132] = "minecraft:flower_forest"; ++ BIOMES_BY_ID[133] = "minecraft:taiga_mountains"; ++ BIOMES_BY_ID[134] = "minecraft:swamp_hills"; ++ BIOMES_BY_ID[140] = "minecraft:ice_spikes"; ++ BIOMES_BY_ID[149] = "minecraft:modified_jungle"; ++ BIOMES_BY_ID[151] = "minecraft:modified_jungle_edge"; ++ BIOMES_BY_ID[155] = "minecraft:tall_birch_forest"; ++ BIOMES_BY_ID[156] = "minecraft:tall_birch_hills"; ++ BIOMES_BY_ID[157] = "minecraft:dark_forest_hills"; ++ BIOMES_BY_ID[158] = "minecraft:snowy_taiga_mountains"; ++ BIOMES_BY_ID[160] = "minecraft:giant_spruce_taiga"; ++ BIOMES_BY_ID[161] = "minecraft:giant_spruce_taiga_hills"; ++ BIOMES_BY_ID[162] = "minecraft:modified_gravelly_mountains"; ++ BIOMES_BY_ID[163] = "minecraft:shattered_savanna"; ++ BIOMES_BY_ID[164] = "minecraft:shattered_savanna_plateau"; ++ BIOMES_BY_ID[165] = "minecraft:eroded_badlands"; ++ BIOMES_BY_ID[166] = "minecraft:modified_wooded_badlands_plateau"; ++ BIOMES_BY_ID[167] = "minecraft:modified_badlands_plateau"; ++ BIOMES_BY_ID[168] = "minecraft:bamboo_jungle"; ++ BIOMES_BY_ID[169] = "minecraft:bamboo_jungle_hills"; ++ BIOMES_BY_ID[170] = "minecraft:soul_sand_valley"; ++ BIOMES_BY_ID[171] = "minecraft:crimson_forest"; ++ BIOMES_BY_ID[172] = "minecraft:warped_forest"; ++ BIOMES_BY_ID[173] = "minecraft:basalt_deltas"; ++ BIOMES_BY_ID[174] = "minecraft:dripstone_caves"; ++ BIOMES_BY_ID[175] = "minecraft:lush_caves"; ++ BIOMES_BY_ID[177] = "minecraft:meadow"; ++ BIOMES_BY_ID[178] = "minecraft:grove"; ++ BIOMES_BY_ID[179] = "minecraft:snowy_slopes"; ++ BIOMES_BY_ID[180] = "minecraft:snowcapped_peaks"; ++ BIOMES_BY_ID[181] = "minecraft:lofty_peaks"; ++ BIOMES_BY_ID[182] = "minecraft:stony_peaks"; ++ } ++ ++ private static final String[] HEIGHTMAP_TYPES = new String[] { ++ "WORLD_SURFACE_WG", ++ "WORLD_SURFACE", ++ "WORLD_SURFACE_IGNORE_SNOW", ++ "OCEAN_FLOOR_WG", ++ "OCEAN_FLOOR", ++ "MOTION_BLOCKING", ++ "MOTION_BLOCKING_NO_LEAVES" ++ }; ++ ++ private static final Set STATUS_IS_OR_AFTER_SURFACE = new HashSet<>(Arrays.asList( ++ "surface", ++ "carvers", ++ "liquid_carvers", ++ "features", ++ "light", ++ "spawn", ++ "heightmaps", ++ "full" ++ )); ++ private static final Set STATUS_IS_OR_AFTER_NOISE = new HashSet<>(Arrays.asList( ++ "noise", ++ "surface", ++ "carvers", ++ "liquid_carvers", ++ "features", ++ "light", ++ "spawn", ++ "heightmaps", ++ "full" ++ )); ++ private static final Set BLOCKS_BEFORE_FEATURE_STATUS = new HashSet<>(Arrays.asList( ++ "minecraft:air", ++ "minecraft:basalt", ++ "minecraft:bedrock", ++ "minecraft:blackstone", ++ "minecraft:calcite", ++ "minecraft:cave_air", ++ "minecraft:coarse_dirt", ++ "minecraft:crimson_nylium", ++ "minecraft:dirt", ++ "minecraft:end_stone", ++ "minecraft:grass_block", ++ "minecraft:gravel", ++ "minecraft:ice", ++ "minecraft:lava", ++ "minecraft:mycelium", ++ "minecraft:nether_wart_block", ++ "minecraft:netherrack", ++ "minecraft:orange_terracotta", ++ "minecraft:packed_ice", ++ "minecraft:podzol", ++ "minecraft:powder_snow", ++ "minecraft:red_sand", ++ "minecraft:red_sandstone", ++ "minecraft:sand", ++ "minecraft:sandstone", ++ "minecraft:snow_block", ++ "minecraft:soul_sand", ++ "minecraft:soul_soil", ++ "minecraft:stone", ++ "minecraft:terracotta", ++ "minecraft:warped_nylium", ++ "minecraft:warped_wart_block", ++ "minecraft:water", ++ "minecraft:white_terracotta" ++ )); ++ ++ private static int getObjectsPerValue(final long[] val) { ++ return (4096 + val.length - 1) / (val.length); // expression is invalid if it returns > 64 ++ } ++ ++ private static long[] resize(final long[] val, final int oldBitsPerObject, final int newBitsPerObject) { ++ final long oldMask = (1L << oldBitsPerObject) - 1; // works even if bitsPerObject == 64 ++ final long newMask = (1L << newBitsPerObject) - 1; ++ final int oldObjectsPerValue = 64 / oldBitsPerObject; ++ final int newObjectsPerValue = 64 / newBitsPerObject; ++ ++ if (newBitsPerObject == oldBitsPerObject) { ++ return val; ++ } ++ ++ final int items = 4096; ++ ++ final long[] ret = new long[(items + newObjectsPerValue - 1) / newObjectsPerValue]; ++ ++ final int expectedSize = ((items + oldObjectsPerValue - 1) / oldObjectsPerValue); ++ if (val.length != expectedSize) { ++ throw new IllegalStateException("Expected size: " + expectedSize + ", got: " + val.length); ++ } ++ ++ int shift = 0; ++ int idx = 0; ++ long newCurr = 0L; ++ ++ int currItem = 0; ++ for (int i = 0; i < val.length; ++i) { ++ final long oldCurr = val[i]; ++ ++ for (int objIdx = 0; currItem < items && objIdx + oldBitsPerObject <= 64; objIdx += oldBitsPerObject, ++currItem) { ++ final long value = (oldCurr >> objIdx) & oldMask; ++ ++ if ((value & newMask) != value) { ++ throw new IllegalStateException("Old data storage has values that cannot be moved into new palette (would erase data)!"); ++ } ++ ++ newCurr |= value << shift; ++ shift += newBitsPerObject; ++ ++ if (shift + newBitsPerObject > 64) { // will next write overflow? ++ // must move to next idx ++ ret[idx++] = newCurr; ++ shift = 0; ++ newCurr = 0L; ++ } ++ } ++ } ++ ++ // don't forget to write the last one ++ if (shift != 0) { ++ ret[idx] = newCurr; ++ } ++ ++ return ret; ++ } ++ ++ private static void fixLithiumChunks(final MapType data) { ++ // See https://github.com/CaffeineMC/lithium-fabric/issues/279 ++ final MapType level = data.getMap("Level"); ++ if (level == null) { ++ return; ++ } ++ ++ final int chunkX = level.getInt("xPos"); ++ final int chunkZ = level.getInt("zPos"); ++ ++ final ListType sections = level.getList("Sections", ObjectType.MAP); ++ if (sections == null) { ++ return; ++ } ++ ++ for (int i = 0, len = sections.size(); i < len; ++i) { ++ final MapType section = sections.getMap(i); ++ ++ final int sectionY = section.getInt("Y"); ++ ++ final ListType palette = section.getList("Palette", ObjectType.MAP); ++ final long[] blockStates = section.getLongs("BlockStates"); ++ ++ if (palette == null || blockStates == null) { ++ continue; ++ } ++ ++ final int expectedBits = Math.max(4, ceilLog2(palette.size())); ++ final int gotObjectsPerValue = getObjectsPerValue(blockStates); ++ final int gotBits = 64 / gotObjectsPerValue; ++ ++ if (expectedBits == gotBits) { ++ continue; ++ } ++ ++ try { ++ section.setLongs("BlockStates", resize(blockStates, gotBits, expectedBits)); ++ } catch (final Exception ex) { ++ LOGGER.fatal("Failed to rewrite mismatched palette and data storage for section y: " + sectionY ++ + " for chunk [" + chunkX + "," + chunkZ + "], palette entries: " + palette.size() + ", data storage size: " ++ + blockStates.length, ++ ex ++ ); ++ } ++ } ++ } ++ ++ public static void register() { ++ // See V2551 for the layout of world gen settings ++ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ // converters were added to older versions note whether the world has increased height already or not ++ final boolean noHeightFlag = !data.hasKey("has_increased_height_already"); ++ final boolean hasIncreasedHeight = data.getBoolean("has_increased_height_already", true); ++ data.remove("has_increased_height_already"); ++ ++ final MapType dimensions = data.getMap("dimensions"); ++ if (dimensions == null) { ++ // wat ++ return null; ++ } ++ ++ // only care about overworld ++ final MapType overworld = dimensions.getMap("minecraft:overworld"); ++ if (overworld == null) { ++ // wat ++ return null; ++ } ++ ++ final MapType generator = overworld.getMap("generator"); ++ if (generator == null) { ++ // wat ++ return null; ++ } ++ ++ final String type = generator.getString("type", ""); ++ switch (type) { ++ case "minecraft:noise": { ++ final MapType biomeSource = generator.getMap("biome_source"); ++ final String sourceType = biomeSource.getString("type"); ++ ++ boolean largeBiomes = false; ++ ++ if ("minecraft:vanilla_layered".equals(sourceType) || (noHeightFlag && "minecraft:multi_noise".equals(sourceType))) { ++ largeBiomes = biomeSource.getBoolean("large_biomes"); ++ ++ final MapType newBiomeSource = Types.NBT.createEmptyMap(); ++ generator.setMap("biome_source", newBiomeSource); ++ ++ newBiomeSource.setString("preset", "minecraft:overworld"); ++ newBiomeSource.setString("type", "minecraft:multi_noise"); ++ } ++ ++ if (largeBiomes) { ++ if ("minecraft:overworld".equals(generator.getString("settings"))) { ++ generator.setString("settings", "minecraft:large_biomes"); ++ } ++ } ++ ++ break; ++ } ++ case "minecraft:flat": { ++ if (!hasIncreasedHeight) { ++ final MapType settings = generator.getMap("settings"); ++ if (settings == null) { ++ break; ++ } ++ ++ updateLayers(settings.getList("layers", ObjectType.MAP)); ++ } ++ break; ++ } ++ default: ++ // do nothing ++ break; ++ } ++ ++ return null; ++ } ++ }); ++ ++ ++ // It looks like DFU will only support worlds in the old height format or the new one, any custom one isn't supported ++ // and by not supported I mean it will just treat it as the old format... maybe at least throw in that case? ++ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ // The below covers padPaletteEntries - this was written BEFORE that code was added to the datafixer - ++ // and this still works, so I'm keeping it. Don't fix what isn't broken. ++ fixLithiumChunks(data); // See https://github.com/CaffeineMC/lithium-fabric/issues/279 ++ ++ final MapType level = data.getMap("Level"); ++ ++ if (level == null) { ++ return null; ++ } ++ ++ final MapType context = data.getMap("__context"); // Passed through by ChunkStorage ++ final String dimension = context == null ? "" : context.getString("dimension", ""); ++ final String generator = context == null ? "" : context.getString("generator", ""); ++ final boolean isOverworld = "minecraft:overworld".equals(dimension); ++ final int minSection = isOverworld ? -4 : 0; ++ final MutableBoolean isAlreadyExtended = new MutableBoolean(); ++ ++ final MapType[] newBiomes = createBiomeSections(level, isOverworld, minSection, isAlreadyExtended); ++ final MapType wrappedEmptyBlockPalette = getEmptyBlockPalette(); ++ ++ final ListType sections = level.getList("Sections", ObjectType.MAP); ++ ++ // must update sections for two things: ++ // 1. the biomes are now stored per section, so we must insert the biomes palette into each section (and create them if they don't exist) ++ // 2. each section must now have block states (or at least DFU is ensuring they do, but current code does not require) ++ V2841.SimplePaletteReader bottomSection = null; ++ final Set allBlocks = new HashSet<>(); ++ if (sections != null) { ++ final IntOpenHashSet existingSections = new IntOpenHashSet(); ++ ++ for (int i = 0, len = sections.size(); i < len; ++i) { ++ final MapType section = sections.getMap(i); ++ ++ final int y = section.getInt("Y"); ++ final int sectionIndex = y - minSection; ++ ++ existingSections.add(y); ++ ++ // add in relevant biome section ++ if (sectionIndex >= 0 && sectionIndex < newBiomes.length) { ++ // exclude out of bounds sections (i.e the light sections above and below the world) ++ section.setMap("biomes", newBiomes[sectionIndex]); ++ } ++ ++ // update palette ++ final ListType palette = section.getList("Palette", ObjectType.MAP); ++ final long[] blockStates = section.getLongs("BlockStates"); ++ ++ section.remove("Palette"); ++ section.remove("BlockStates"); ++ ++ if (palette != null) { ++ for (int j = 0, len2 = palette.size(); j < len2; ++j) { ++ allBlocks.add(V2841.getBlockId(palette.getMap(j))); ++ } ++ } ++ ++ final MapType palettedContainer; ++ if (palette != null && blockStates != null) { ++ // only if both exist, same as DFU, same as legacy chunk loading code ++ section.setMap("block_states", palettedContainer = wrapPaletteOptimised(palette, blockStates)); ++ } else { ++ section.setMap("block_states", palettedContainer = wrappedEmptyBlockPalette.copy()); // must write a palette now, copy so that later edits do not edit them all ++ } ++ ++ if (section.getInt("Y", Integer.MAX_VALUE) == 0) { ++ bottomSection = new V2841.SimplePaletteReader(palettedContainer.getList("palette", ObjectType.MAP), palettedContainer.getLongs("data")); ++ } ++ } ++ ++ // all existing sections updated, now we must create new sections just for the biomes migration ++ for (int sectionIndex = 0; sectionIndex < newBiomes.length; ++sectionIndex) { ++ final int sectionY = sectionIndex + minSection; ++ if (!existingSections.add(sectionY)) { ++ // exists already ++ continue; ++ } ++ ++ final MapType newSection = Types.NBT.createEmptyMap(); ++ sections.addMap(newSection); ++ ++ newSection.setByte("Y", (byte)sectionY); ++ // must write a palette now, copy so that later edits do not edit them all ++ newSection.setMap("block_states", wrappedEmptyBlockPalette.copy()); ++ ++ newSection.setGeneric("biomes", newBiomes[sectionIndex]); ++ } ++ } ++ ++ // update status so interpolation can take place ++ predictChunkStatusBeforeSurface(level, allBlocks); ++ ++ // done with sections, update the rest of the chunk ++ updateChunkData(level, isOverworld, isAlreadyExtended.getValue(), "minecraft:noise".equals(generator), bottomSection); ++ ++ return null; ++ } ++ }); ++ ++ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { ++ final MapType dimensions = data.getMap("dimensions"); ++ ++ if (dimensions == null) { ++ return null; ++ } ++ ++ for (final String dimension : dimensions.keys()) { ++ final MapType dimensionData = dimensions.getMap(dimension); ++ if (dimensionData == null) { ++ continue; ++ } ++ ++ final MapType generator = dimensionData.getMap("generator"); ++ if (generator == null) { ++ continue; ++ } ++ ++ final String type = generator.getString("type"); ++ if (type == null) { ++ continue; ++ } ++ ++ switch (type) { ++ case "minecraft:flat": { ++ final MapType settings = generator.getMap("settings"); ++ if (settings == null) { ++ continue; ++ } ++ ++ WalkerUtils.convert(MCTypeRegistry.BIOME, settings, "biome", fromVersion, toVersion); ++ ++ final ListType layers = settings.getList("layers", ObjectType.MAP); ++ if (layers != null) { ++ for (int i = 0, len = layers.size(); i < len; ++i) { ++ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, layers.getMap(i), "block", fromVersion, toVersion); ++ } ++ } ++ ++ break; ++ } ++ case "minecraft:noise": { ++ final MapType settings = generator.getMap("settings"); ++ if (settings != null) { ++ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, settings, "default_block", fromVersion, toVersion); ++ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, settings, "default_fluid", fromVersion, toVersion); ++ } ++ ++ final MapType biomeSource = generator.getMap("biome_source"); ++ if (biomeSource != null) { ++ final String biomeSourceType = biomeSource.getString("type", ""); ++ switch (biomeSourceType) { ++ case "minecraft:fixed": { ++ WalkerUtils.convert(MCTypeRegistry.BIOME, biomeSource, "biome", fromVersion, toVersion); ++ break; ++ } ++ ++ case "minecraft:multi_noise": { ++ // preset is absent, no type for namespaced string ++ ++ // Vanilla's schema is _still_ wrong. It should be DSL.fields("biomes", DSL.list(DSL.fields("biome"))) ++ // But it just contains the list part. That obviously can never be the case, because ++ // the root object is a compound, not a list. ++ ++ final ListType biomes = biomeSource.getList("biomes", ObjectType.MAP); ++ if (biomes != null) { ++ for (int i = 0, len = biomes.size(); i < len; ++i) { ++ WalkerUtils.convert(MCTypeRegistry.BIOME, biomes.getMap(i), "biome", fromVersion, toVersion); ++ } ++ } ++ break; ++ } ++ ++ case "minecraft:checkerboard": { ++ WalkerUtils.convertList(MCTypeRegistry.BIOME, biomeSource, "biomes", fromVersion, toVersion); ++ break; ++ } ++ } ++ } ++ ++ break; ++ } ++ } ++ } ++ ++ return null; ++ }); ++ ++ MCTypeRegistry.CHUNK.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { ++ final MapType level = data.getMap("Level"); ++ if (level == null) { ++ return null; ++ } ++ ++ WalkerUtils.convertList(MCTypeRegistry.ENTITY, level, "Entities", fromVersion, toVersion); ++ WalkerUtils.convertList(MCTypeRegistry.TILE_ENTITY, level, "TileEntities", fromVersion, toVersion); ++ ++ final ListType tileTicks = level.getList("TileTicks", ObjectType.MAP); ++ if (tileTicks != null) { ++ for (int i = 0, len = tileTicks.size(); i < len; ++i) { ++ final MapType tileTick = tileTicks.getMap(i); ++ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, tileTick, "i", fromVersion, toVersion); ++ } ++ } ++ ++ final ListType sections = level.getList("Sections", ObjectType.MAP); ++ if (sections != null) { ++ for (int i = 0, len = sections.size(); i < len; ++i) { ++ final MapType section = sections.getMap(i); ++ ++ WalkerUtils.convertList(MCTypeRegistry.BIOME, section.getMap("biomes"), "palette", fromVersion, toVersion); ++ WalkerUtils.convertList(MCTypeRegistry.BLOCK_STATE, section.getMap("block_states"), "palette", fromVersion, toVersion); ++ } ++ } ++ ++ WalkerUtils.convertValues(MCTypeRegistry.STRUCTURE_FEATURE, level.getMap("Structures"), "Starts", fromVersion, toVersion); ++ ++ return null; ++ }); ++ } ++ ++ private static void predictChunkStatusBeforeSurface(final MapType level, final Set chunkBlocks) { ++ final String status = level.getString("Status", "empty"); ++ if (STATUS_IS_OR_AFTER_SURFACE.contains(status)) { ++ return; ++ } ++ ++ chunkBlocks.remove("minecraft:air"); ++ final boolean chunkNotEmpty = !chunkBlocks.isEmpty(); ++ chunkBlocks.removeAll(BLOCKS_BEFORE_FEATURE_STATUS); ++ final boolean chunkFeatureStatus = !chunkBlocks.isEmpty(); ++ ++ final String update; ++ if (chunkFeatureStatus) { ++ update = "liquid_carvers"; ++ } else if (!"noise".equals(status) && !chunkNotEmpty) { ++ update = "biomes".equals(status) ? "structure_references" : status; ++ } else { ++ update = "noise"; ++ } ++ ++ level.setString("Status", update); ++ } ++ ++ private static MapType getEmptyBlockPalette() { ++ final MapType airBlockState = Types.NBT.createEmptyMap(); ++ airBlockState.setString("Name", "minecraft:air"); ++ ++ final ListType emptyBlockPalette = Types.NBT.createEmptyList(); ++ emptyBlockPalette.addMap(airBlockState); ++ ++ return V2832.wrapPalette(emptyBlockPalette); ++ } ++ ++ private static void shiftUpgradeData(final MapType upgradeData, final int shift) { ++ if (upgradeData == null) { ++ return; ++ } ++ ++ final MapType indices = upgradeData.getMap("Indices"); ++ if (indices == null) { ++ return; ++ } ++ ++ RenameHelper.renameKeys(indices, (final String input) -> { ++ return Integer.toString(Integer.parseInt(input) + shift); ++ }); ++ } ++ ++ private static void updateChunkData(final MapType level, final boolean wantExtendedHeight, final boolean isAlreadyExtended, ++ final boolean onNoiseGenerator, final V2841.SimplePaletteReader bottomSection) { ++ level.remove("Biomes"); ++ if (!wantExtendedHeight) { ++ padCarvingMasks(level, 16, 0); ++ return; ++ } ++ ++ if (isAlreadyExtended) { ++ padCarvingMasks(level, 24, 0); ++ return; ++ } ++ ++ offsetHeightmaps(level); ++ addEmptyListPadding(level, "Lights"); ++ addEmptyListPadding(level, "LiquidsToBeTicked"); ++ addEmptyListPadding(level, "PostProcessing"); ++ addEmptyListPadding(level, "ToBeTicked"); ++ shiftUpgradeData(level.getMap("UpgradeData"), 4); // https://bugs.mojang.com/browse/MC-238076 - fixed now, Mojang fix is identical. No change required. ++ padCarvingMasks(level, 24, 4); ++ ++ if (!onNoiseGenerator) { ++ return; ++ } ++ ++ final String status = level.getString("Status"); ++ if (status == null || "empty".equals(status)) { ++ return; ++ } ++ ++ final MapType blendingData = Types.NBT.createEmptyMap(); ++ level.setMap("blending_data", blendingData); ++ ++ blendingData.setBoolean("old_noise", STATUS_IS_OR_AFTER_NOISE.contains(status)); ++ ++ if (bottomSection == null) { ++ return; ++ } ++ ++ final BitSet missingBedrock = new BitSet(256); ++ boolean hasBedrock = status.equals("noise"); ++ ++ for (int z = 0; z <= 15; ++z) { ++ for (int x = 0; x <= 15; ++x) { ++ final MapType state = bottomSection.getState(x, 0, z); ++ final String blockId = V2841.getBlockId(state); ++ final boolean isBedrock = state != null && "minecraft:bedrock".equals(blockId); ++ final boolean isAir = state != null && "minecraft:air".equals(blockId); ++ if (isAir) { ++ missingBedrock.set((z << 4) | x); ++ } ++ ++ hasBedrock |= isBedrock; ++ } ++ } ++ ++ if (hasBedrock && missingBedrock.cardinality() != missingBedrock.size()) { ++ final String targetStatus = "full".equals(status) ? "heightmaps" : status; ++ ++ final MapType belowZeroRetrogen = Types.NBT.createEmptyMap(); ++ level.setMap("below_zero_retrogen", belowZeroRetrogen); ++ ++ belowZeroRetrogen.setString("target_status", targetStatus); ++ belowZeroRetrogen.setLongs("missing_bedrock", missingBedrock.toLongArray()); ++ ++ level.setString("Status", "empty"); ++ } ++ ++ level.setBoolean("isLightOn", false); ++ } ++ ++ private static void padCarvingMasks(final MapType level, final int newSize, final int offset) { ++ final MapType carvingMasks = level.getMap("CarvingMasks"); ++ if (carvingMasks == null) { ++ // if empty, DFU still writes ++ level.setMap("CarvingMasks", Types.NBT.createEmptyMap()); ++ return; ++ } ++ ++ for (final String key : carvingMasks.keys()) { ++ final long[] old = BitSet.valueOf(carvingMasks.getBytes(key)).toLongArray(); ++ final long[] newVal = new long[64 * newSize]; ++ ++ System.arraycopy(old, 0, newVal, 64 * offset, old.length); ++ ++ carvingMasks.setLongs(key, newVal); // no CME: key exists already ++ } ++ } ++ ++ private static void addEmptyListPadding(final MapType level, final String path) { ++ ListType list = level.getListUnchecked(path); ++ if (list != null && list.size() == 24) { ++ return; ++ } ++ ++ if (list == null) { ++ // difference from DFU: Don't create the damn thing! ++ return; ++ } ++ ++ ++ // offset the section array to the new format ++ for (int i = 0; i < 4; ++i) { ++ // always create new copies, so that modifying one doesn't modify ALL of them! ++ list.addList(0, Types.NBT.createEmptyList()); // add below ++ list.addList(Types.NBT.createEmptyList()); // add above ++ } ++ } ++ ++ private static void offsetHeightmaps(final MapType level) { ++ final MapType heightmaps = level.getMap("Heightmaps"); ++ if (heightmaps == null) { ++ return; ++ } ++ ++ for (final String key : HEIGHTMAP_TYPES) { ++ offsetHeightmap(heightmaps.getLongs(key)); ++ } ++ } ++ ++ private static void offsetHeightmap(final long[] heightmap) { ++ if (heightmap == null) { ++ return; ++ } ++ ++ // heightmaps are configured to have 9 bits per value, with 256 total values ++ // heightmaps are also relative to the lowest position ++ for (int idx = 0, len = heightmap.length; idx < len; ++idx) { ++ long curr = heightmap[idx]; ++ long next = 0L; ++ ++ for (int objIdx = 0; objIdx + 9 <= 64; objIdx += 9) { ++ final long value = (curr >> objIdx) & 511L; ++ if (value != 0L) { ++ final long offset = Math.min(511L, value + 64L); ++ ++ next |= (offset << objIdx); ++ } ++ } ++ ++ heightmap[idx] = next; ++ } ++ } ++ ++ private static MapType[] createBiomeSections(final MapType level, final boolean wantExtendedHeight, ++ final int minSection, final MutableBoolean isAlreadyExtended) { ++ final MapType[] ret = new MapType[wantExtendedHeight ? 24 : 16]; ++ ++ final int[] biomes = level.getInts("Biomes"); ++ if (biomes == null) { ++ final ListType palette = Types.NBT.createEmptyList(); ++ palette.addString("minecraft:plains"); ++ ++ for (int i = 0; i < ret.length; ++i) { ++ ret[i] = wrapPalette(palette.copy()); // copy palette so that later possible modifications don't trash all sections ++ } ++ ++ return ret; ++ } ++ ++ final boolean isExtended = biomes.length == 1536; // magic value for 24 sections of biomes (24 * 4^3) ++ isAlreadyExtended.setValue(isExtended); ++ ++ if (isExtended) { ++ for (int sectionIndex = 0; sectionIndex < 24; ++sectionIndex) { ++ ret[sectionIndex] = createBiomeSection(biomes, sectionIndex * 64, -1); // -1 is all 1s ++ } ++ } else { ++ for (int sectionY = 0; sectionY < 16; ++sectionY) { ++ ret[sectionY - minSection] = createBiomeSection(biomes, sectionY * 64, -1); // -1 is all 1s ++ } ++ ++ if (wantExtendedHeight) { ++ // must set the new sections at top and bottom ++ final MapType bottomCopy = createBiomeSection(biomes, 0, 15); // just want the biomes at y = 0 ++ final MapType topCopy = createBiomeSection(biomes, 1008, 15); // just want the biomes at y = 252 ++ ++ for (int sectionIndex = 0; sectionIndex < 4; ++sectionIndex) { ++ ret[sectionIndex] = bottomCopy.copy(); // copy palette so that later possible modifications don't trash all sections ++ } ++ ++ for (int sectionIndex = 20; sectionIndex < 24; ++sectionIndex) { ++ ret[sectionIndex] = topCopy.copy(); // copy palette so that later possible modifications don't trash all sections ++ } ++ } ++ } ++ ++ return ret; ++ } ++ ++ private static MapType createBiomeSection(final int[] biomes, final int offset, final int mask) { ++ final Int2IntLinkedOpenHashMap paletteId = new Int2IntLinkedOpenHashMap(); ++ ++ for (int idx = 0; idx < 64; ++idx) { ++ final int biome = biomes[offset + (idx & mask)]; ++ paletteId.putIfAbsent(biome, paletteId.size()); ++ } ++ ++ final ListType paletteString = Types.NBT.createEmptyList(); ++ for (final IntIterator iterator = paletteId.keySet().iterator(); iterator.hasNext();) { ++ final int biomeId = iterator.nextInt(); ++ final String biome = biomeId >= 0 && biomeId < BIOMES_BY_ID.length ? BIOMES_BY_ID[biomeId] : null; ++ paletteString.addString(biome == null ? "minecraft:plains" : biome); ++ } ++ ++ final int bitsPerObject = ceilLog2(paletteString.size()); ++ if (bitsPerObject == 0) { ++ return wrapPalette(paletteString); ++ } ++ ++ // manually create packed integer data ++ final int objectsPerValue = 64 / bitsPerObject; ++ final long[] packed = new long[(64 + objectsPerValue - 1) / objectsPerValue]; ++ ++ int shift = 0; ++ int idx = 0; ++ long curr = 0; ++ ++ for (int biome_idx = 0; biome_idx < 64; ++biome_idx) { ++ final int biome = biomes[offset + (biome_idx & mask)]; ++ ++ curr |= ((long)paletteId.get(biome)) << shift; ++ ++ shift += bitsPerObject; ++ ++ if (shift + bitsPerObject > 64) { // will next write overflow? ++ // must move to next idx ++ packed[idx++] = curr; ++ shift = 0; ++ curr = 0L; ++ } ++ } ++ ++ // don't forget to write the last one ++ if (shift != 0) { ++ packed[idx] = curr; ++ } ++ ++ return wrapPalette(paletteString, packed); ++ } ++ ++ private static MapType wrapPalette(final ListType palette) { ++ return wrapPalette(palette, null); ++ } ++ ++ private static MapType wrapPalette(final ListType palette, final long[] blockStates) { ++ final MapType ret = Types.NBT.createEmptyMap(); ++ ret.setList("palette", palette); ++ if (blockStates != null) { ++ ret.setLongs("data", blockStates); ++ } ++ ++ return ret; ++ } ++ ++ private static MapType wrapPaletteOptimised(final ListType palette, final long[] blockStates) { ++ if (palette.size() == 1) { ++ return wrapPalette(palette); ++ } ++ ++ return wrapPalette(palette, blockStates); ++ } ++ ++ public static int ceilLog2(final int value) { ++ return value == 0 ? 0 : Integer.SIZE - Integer.numberOfLeadingZeros(value - 1); // see doc of numberOfLeadingZeros ++ } ++ ++ private static void updateLayers(final ListType layers) { ++ if (layers == null) { ++ return; ++ } ++ ++ layers.addMap(0, createEmptyLayer()); // add at the bottom ++ } ++ ++ private static MapType createEmptyLayer() { ++ final MapType ret = Types.NBT.createEmptyMap(); ++ ret.setInt("height", 64); ++ ret.setString("block", "minecraft:air"); ++ ++ return ret; ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2833.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2833.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4bdac86810c51e9f87ea82ba9f6c6d8ae8ce2bdf +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2833.java +@@ -0,0 +1,30 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.types.MapType; ++ ++public final class V2833 { ++ ++ protected static final int VERSION = MCVersions.V1_17_1 + 103; ++ ++ public static void register() { ++ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final MapType dimensions = data.getMap("dimensions"); ++ ++ for (final String dimensionKey : dimensions.keys()) { ++ final MapType dimension = dimensions.getMap(dimensionKey); ++ if (!dimension.hasKey("type")) { ++ throw new IllegalStateException("Unable load old custom worlds."); ++ } ++ } ++ ++ return null; ++ } ++ }); ++ } ++ ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2838.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2838.java +new file mode 100644 +index 0000000000000000000000000000000000000000..586e711163e2bdea110442dd181289fc06f6f7f1 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2838.java +@@ -0,0 +1,56 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.ConverterAbstractStringValueTypeRename; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import com.google.common.collect.ImmutableMap; ++ ++public final class V2838 { ++ ++ protected static final int VERSION = MCVersions.V21W40A; ++ ++ public static final ImmutableMap BIOME_UPDATE = ImmutableMap.builder() ++ .put("minecraft:badlands_plateau", "minecraft:badlands") ++ .put("minecraft:bamboo_jungle_hills", "minecraft:bamboo_jungle") ++ .put("minecraft:birch_forest_hills", "minecraft:birch_forest") ++ .put("minecraft:dark_forest_hills", "minecraft:dark_forest") ++ .put("minecraft:desert_hills", "minecraft:desert") ++ .put("minecraft:desert_lakes", "minecraft:desert") ++ .put("minecraft:giant_spruce_taiga_hills", "minecraft:old_growth_spruce_taiga") ++ .put("minecraft:giant_spruce_taiga", "minecraft:old_growth_spruce_taiga") ++ .put("minecraft:giant_tree_taiga_hills", "minecraft:old_growth_pine_taiga") ++ .put("minecraft:giant_tree_taiga", "minecraft:old_growth_pine_taiga") ++ .put("minecraft:gravelly_mountains", "minecraft:windswept_gravelly_hills") ++ .put("minecraft:jungle_edge", "minecraft:sparse_jungle") ++ .put("minecraft:jungle_hills", "minecraft:jungle") ++ .put("minecraft:modified_badlands_plateau", "minecraft:badlands") ++ .put("minecraft:modified_gravelly_mountains", "minecraft:windswept_gravelly_hills") ++ .put("minecraft:modified_jungle_edge", "minecraft:sparse_jungle") ++ .put("minecraft:modified_jungle", "minecraft:jungle") ++ .put("minecraft:modified_wooded_badlands_plateau", "minecraft:wooded_badlands") ++ .put("minecraft:mountain_edge", "minecraft:windswept_hills") ++ .put("minecraft:mountains", "minecraft:windswept_hills") ++ .put("minecraft:mushroom_field_shore", "minecraft:mushroom_fields") ++ .put("minecraft:shattered_savanna", "minecraft:windswept_savanna") ++ .put("minecraft:shattered_savanna_plateau", "minecraft:windswept_savanna") ++ .put("minecraft:snowy_mountains", "minecraft:snowy_plains") ++ .put("minecraft:snowy_taiga_hills", "minecraft:snowy_taiga") ++ .put("minecraft:snowy_taiga_mountains", "minecraft:snowy_taiga") ++ .put("minecraft:snowy_tundra", "minecraft:snowy_plains") ++ .put("minecraft:stone_shore", "minecraft:stony_shore") ++ .put("minecraft:swamp_hills", "minecraft:swamp") ++ .put("minecraft:taiga_hills", "minecraft:taiga") ++ .put("minecraft:taiga_mountains", "minecraft:taiga") ++ .put("minecraft:tall_birch_forest", "minecraft:old_growth_birch_forest") ++ .put("minecraft:tall_birch_hills", "minecraft:old_growth_birch_forest") ++ .put("minecraft:wooded_badlands_plateau", "minecraft:wooded_badlands") ++ .put("minecraft:wooded_hills", "minecraft:forest") ++ .put("minecraft:wooded_mountains", "minecraft:windswept_forest") ++ .put("minecraft:lofty_peaks", "minecraft:jagged_peaks") ++ .put("minecraft:snowcapped_peaks", "minecraft:frozen_peaks") ++ .build(); ++ ++ public static void register() { ++ ConverterAbstractStringValueTypeRename.register(VERSION, MCTypeRegistry.BIOME, BIOME_UPDATE::get); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2841.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2841.java +new file mode 100644 +index 0000000000000000000000000000000000000000..41b41ff084662bbc2e323713473e4e13b8e50cd7 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2841.java +@@ -0,0 +1,205 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.types.ListType; ++import ca.spottedleaf.dataconverter.types.MapType; ++import ca.spottedleaf.dataconverter.types.ObjectType; ++import ca.spottedleaf.dataconverter.types.Types; ++import ca.spottedleaf.dataconverter.util.IntegerUtil; ++import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; ++import java.util.Arrays; ++import java.util.HashSet; ++import java.util.Set; ++ ++public final class V2841 { ++ ++ protected static final int VERSION = MCVersions.V21W42A + 1; ++ ++ protected static final Set ALWAYS_WATERLOGGED = new HashSet<>(Arrays.asList( ++ "minecraft:bubble_column", ++ "minecraft:kelp", ++ "minecraft:kelp_plant", ++ "minecraft:seagrass", ++ "minecraft:tall_seagrass" ++ )); ++ ++ public static void register() { ++ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType root, final long sourceVersion, final long toVersion) { ++ final MapType level = root.getMap("Level"); ++ if (level == null) { ++ return null; ++ } ++ ++ { ++ // Why it's renamed here and not the next data version is beyond me. ++ final MapType liquidTicks = level.getMap("LiquidTicks"); ++ if (liquidTicks != null) { ++ level.remove("LiquidTicks"); ++ level.setMap("fluid_ticks", liquidTicks); ++ } ++ } ++ ++ final Int2ObjectOpenHashMap sectionBlocks = new Int2ObjectOpenHashMap<>(); ++ final ListType sections = level.getList("Sections", ObjectType.MAP); ++ int minSection = 0; // TODO wtf is this ++ if (sections != null) { ++ for (int i = 0, len = sections.size(); i < len; ++i) { ++ final MapType section = sections.getMap(i); ++ ++ final int sectionY = section.getInt("Y"); ++ if (sectionY < minSection && section.hasKey("biomes")) { ++ minSection = sectionY; ++ } ++ ++ final MapType blockStates = section.getMap("block_states"); ++ if (blockStates == null) { ++ continue; ++ } ++ ++ sectionBlocks.put(sectionY, new SimplePaletteReader(section.getList("palette", ObjectType.MAP), section.getLongs("data"))); ++ } ++ } ++ ++ level.setByte("yPos", (byte)minSection); // TODO ??????????????????????????????????????? ++ ++ if (level.hasKey("fluid_ticks") || level.hasKey("TileTicks")) { ++ return null; ++ } ++ ++ final int sectionX = level.getInt("xPos"); ++ final int sectionZ = level.getInt("zPos"); ++ ++ final ListType fluidTicks = level.getList("LiquidsToBeTicked", ObjectType.LIST); ++ final ListType blockTicks = level.getList("ToBeTicked", ObjectType.LIST); ++ level.remove("LiquidsToBeTicked"); ++ level.remove("ToBeTicked"); ++ ++ level.setList("fluid_ticks", migrateTickList(fluidTicks, false, sectionBlocks, sectionX, minSection, sectionZ)); ++ level.setList("TileTicks", migrateTickList(blockTicks, true, sectionBlocks, sectionX, minSection, sectionZ)); ++ ++ return null; ++ } ++ }); ++ } ++ ++ public static ListType migrateTickList(final ListType ticks, final boolean blockTicks, final Int2ObjectOpenHashMap sectionBlocks, ++ final int sectionX, final int minSection, final int sectionZ) { ++ final ListType ret = Types.NBT.createEmptyList(); ++ ++ if (ticks == null) { ++ return ret; ++ } ++ ++ for (int sectionIndex = 0, totalSections = ticks.size(); sectionIndex < totalSections; ++sectionIndex) { ++ final int sectionY = sectionIndex + minSection; ++ final ListType sectionTicks = ticks.getList(sectionIndex); ++ final SimplePaletteReader palette = sectionBlocks.get(sectionY); ++ ++ for (int i = 0, len = sectionTicks.size(); i < len; ++i) { ++ final int localIndex = sectionTicks.getShort(i) & 0xFFFF; ++ final MapType blockState = palette == null ? null : palette.getState(localIndex); ++ final String subjectId = blockTicks ? getBlockId(blockState) : getLiquidId(blockState); ++ ++ ret.addMap(createNewTick(subjectId, localIndex, sectionX, sectionY, sectionZ)); ++ } ++ } ++ ++ return ret; ++ } ++ ++ public static MapType createNewTick(final String subjectId, final int localIndex, final int sectionX, final int sectionY, final int sectionZ) { ++ final int newX = (localIndex & 15) + (sectionX << 4); ++ final int newZ = ((localIndex >> 4) & 15) + (sectionZ << 4); ++ final int newY = ((localIndex >> 8) & 15) + (sectionY << 4); ++ ++ final MapType ret = Types.NBT.createEmptyMap(); ++ ++ ret.setString("i", subjectId); ++ ret.setInt("x", newX); ++ ret.setInt("y", newY); ++ ret.setInt("z", newZ); ++ ret.setInt("t", 0); ++ ret.setInt("p", 0); ++ ++ return ret; ++ } ++ ++ public static String getBlockId(final MapType blockState) { ++ return blockState == null ? "minecraft:air" : blockState.getString("Name", "minecraft:air"); ++ } ++ ++ private static String getLiquidId(final MapType blockState) { ++ if (blockState == null) { ++ return "minecraft:empty"; ++ } ++ ++ final String name = blockState.getString("Name"); ++ if (ALWAYS_WATERLOGGED.contains(name)) { ++ return "minecraft:water"; ++ } ++ ++ final MapType properties = blockState.getMap("Properties"); ++ if ("minecraft:water".equals(name)) { ++ return properties != null && properties.getInt("level") == 0 ? "minecraft:water" : "minecraft:flowing_water"; ++ } else if ("minecraft:lava".equals(name)) { ++ return properties != null && properties.getInt("level") == 0 ? "minecraft:lava" : "minecraft:flowing_lava"; ++ } ++ ++ return (properties != null && properties.getBoolean("waterlogged")) ? "minecraft:water" : "minecraft:empty"; ++ } ++ ++ public static final class SimplePaletteReader { ++ ++ public final ListType palette; ++ public final long[] data; ++ private final int bitsPerValue; ++ private final long mask; ++ private final int valuesPerLong; ++ ++ public SimplePaletteReader(final ListType palette, final long[] data) { ++ this.palette = palette == null ? null : (palette.size() == 0 ? null : palette); ++ this.data = data; ++ this.bitsPerValue = Math.max(4, IntegerUtil.ceilLog2(this.palette == null ? 0 : this.palette.size())); ++ this.mask = (1L << this.bitsPerValue) - 1L; ++ this.valuesPerLong = (int)(64L / this.bitsPerValue); ++ } ++ ++ public MapType getState(final int x, final int y, final int z) { ++ final int index = x | (z << 4) | (y << 8); ++ return this.getState(index); ++ } ++ ++ public MapType getState(final int index) { ++ final ListType palette = this.palette; ++ if (palette == null) { ++ return null; ++ } ++ ++ final int paletteSize = palette.size(); ++ if (paletteSize == 1) { ++ return palette.getMap(0); ++ } ++ ++ // x86 div computes mod. no loss here using mod ++ // if needed, can compute magic mul and shift for div values using IntegerUtil ++ final int dataIndex = index / this.valuesPerLong; ++ final int localIndex = (index % this.valuesPerLong) * this.bitsPerValue; ++ final long[] data = this.data; ++ if (dataIndex < 0 || dataIndex >= data.length) { ++ return null; ++ } ++ ++ final long value = data[dataIndex]; ++ final int paletteIndex = (int)((value >>> localIndex) & this.mask); ++ if (paletteIndex < 0 || paletteIndex >= paletteSize) { ++ return null; ++ } ++ ++ return palette.getMap(paletteIndex); ++ } ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2842.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2842.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f06e24bb87baf01b1386fb7a6af1ea04f4d6f2ef +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2842.java +@@ -0,0 +1,76 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.RenameHelper; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.minecraft.walkers.generic.WalkerUtils; ++import ca.spottedleaf.dataconverter.types.ListType; ++import ca.spottedleaf.dataconverter.types.MapType; ++import ca.spottedleaf.dataconverter.types.ObjectType; ++ ++public final class V2842 { ++ ++ protected static final int VERSION = MCVersions.V21W42A + 2; ++ ++ public static void register() { ++ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType root, final long sourceVersion, final long toVersion) { ++ final MapType level = root.getMap("Level"); ++ root.remove("Level"); ++ ++ if (!root.isEmpty()) { ++ for (final String key : root.keys()) { ++ if (level.hasKey(key)) { ++ // Don't clobber level's data ++ continue; ++ } ++ level.setGeneric(key, root.getGeneric(key)); ++ } ++ } ++ ++ // Rename top level first ++ RenameHelper.renameSingle(level, "TileEntities", "block_entities"); ++ RenameHelper.renameSingle(level, "TileTicks", "block_ticks"); ++ RenameHelper.renameSingle(level, "Entities", "entities"); ++ RenameHelper.renameSingle(level, "Sections", "sections"); ++ RenameHelper.renameSingle(level, "Structures", "structures"); ++ ++ // 2nd level ++ final MapType structures = level.getMap("structures"); ++ if (structures != null) { ++ RenameHelper.renameSingle(structures, "Starts", "starts"); ++ } ++ ++ return level; // Level is now root tag. ++ } ++ }); ++ ++ MCTypeRegistry.CHUNK.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { ++ WalkerUtils.convertList(MCTypeRegistry.ENTITY, data, "entities", fromVersion, toVersion); ++ WalkerUtils.convertList(MCTypeRegistry.TILE_ENTITY, data, "block_entities", fromVersion, toVersion); ++ ++ final ListType blockTicks = data.getList("block_ticks", ObjectType.MAP); ++ if (blockTicks != null) { ++ for (int i = 0, len = blockTicks.size(); i < len; ++i) { ++ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, blockTicks.getMap(i), "i", fromVersion, toVersion); ++ } ++ } ++ ++ final ListType sections = data.getList("sections", ObjectType.MAP); ++ if (sections != null) { ++ for (int i = 0, len = sections.size(); i < len; ++i) { ++ final MapType section = sections.getMap(i); ++ ++ WalkerUtils.convertList(MCTypeRegistry.BIOME, section.getMap("biomes"), "palette", fromVersion, toVersion); ++ WalkerUtils.convertList(MCTypeRegistry.BLOCK_STATE, section.getMap("block_states"), "palette", fromVersion, toVersion); ++ } ++ } ++ ++ WalkerUtils.convertValues(MCTypeRegistry.STRUCTURE_FEATURE, data.getMap("structures"), "starts", fromVersion, toVersion); ++ ++ return null; ++ }); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2843.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2843.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5d69a84a1d4f74a961210561c3258a4ed5e4c4d2 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2843.java +@@ -0,0 +1,15 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.ConverterAbstractStringValueTypeRename; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import java.util.Map; ++ ++public final class V2843 { ++ ++ protected static final int VERSION = MCVersions.V21W42A + 3; ++ ++ public static void register() { ++ ConverterAbstractStringValueTypeRename.register(VERSION, MCTypeRegistry.BIOME, Map.of("minecraft:deep_warm_ocean", "minecraft:warm_ocean")::get); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2846.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2846.java +new file mode 100644 +index 0000000000000000000000000000000000000000..236327249d2b95b799b90172d457601167492249 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2846.java +@@ -0,0 +1,18 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.advancements.ConverterAbstractAdvancementsRename; ++import com.google.common.collect.ImmutableMap; ++ ++public final class V2846 { ++ ++ protected static final int VERSION = MCVersions.V21W44A + 1; ++ ++ public static void register() { ++ ConverterAbstractAdvancementsRename.register(VERSION, ImmutableMap.of( ++ "minecraft:husbandry/play_jukebox_in_meadows", "minecraft:adventure/play_jukebox_in_meadows", ++ "minecraft:adventure/caves_and_cliff", "minecraft:adventure/fall_from_world_height", ++ "minecraft:adventure/ride_strider_in_overworld_lava", "minecraft:nether/ride_strider_in_overworld_lava" ++ )::get); ++ } ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2852.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2852.java +new file mode 100644 +index 0000000000000000000000000000000000000000..94ab7be8c34d2ebb557df5a0864130f7f12c2185 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V2852.java +@@ -0,0 +1,29 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.types.MapType; ++ ++public final class V2852 { ++ ++ protected static final int VERSION = MCVersions.V1_18_PRE5 + 1; ++ ++ public static void register() { ++ MCTypeRegistry.WORLD_GEN_SETTINGS.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final MapType dimensions = data.getMap("dimensions"); ++ ++ for (final String dimensionKey : dimensions.keys()) { ++ final MapType dimension = dimensions.getMap(dimensionKey); ++ if (!dimension.hasKey("type")) { ++ throw new IllegalStateException("Unable load old custom worlds."); ++ } ++ } ++ ++ return null; ++ } ++ }); ++ } ++} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V501.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V501.java new file mode 100644 index 0000000000000000000000000000000000000000..6ab2bf99d72983fc2742a1f6f2f7fa671611526d @@ -16534,12 +18353,13 @@ index 0000000000000000000000000000000000000000..e66b4e0f7cdb032b545ace7ba852ad79 +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/WalkerUtils.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/WalkerUtils.java new file mode 100644 -index 0000000000000000000000000000000000000000..8f231d4f0999a52d9c19b4669daa94c7881933d0 +index 0000000000000000000000000000000000000000..1e81a1e46a9c0ffceb564a7b1fc4d1b51009f3f7 --- /dev/null +++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/walkers/generic/WalkerUtils.java -@@ -0,0 +1,130 @@ +@@ -0,0 +1,127 @@ +package ca.spottedleaf.dataconverter.minecraft.walkers.generic; + ++import ca.spottedleaf.dataconverter.minecraft.converters.helpers.RenameHelper; +import ca.spottedleaf.dataconverter.minecraft.datatypes.MCDataType; +import ca.spottedleaf.dataconverter.minecraft.datatypes.MCValueType; +import ca.spottedleaf.dataconverter.types.ObjectType; @@ -16634,13 +18454,9 @@ index 0000000000000000000000000000000000000000..8f231d4f0999a52d9c19b4669daa94c7 + return; + } + -+ for (final String key : new ArrayList<>(data.keys())) { -+ final String updated = (String)type.convert(key, fromVersion, toVersion); -+ if (updated != null) { -+ data.setGeneric(updated, data.getGeneric(key)); -+ data.remove(key); -+ } -+ } ++ RenameHelper.renameKeys(data, (final String input) -> { ++ return (String)type.convert(input, fromVersion, toVersion); ++ }); + } + + public static void convertValues(final MCDataType type, final MapType data, final String path, final long fromVersion, final long toVersion) { @@ -19373,6 +21189,235 @@ index 0000000000000000000000000000000000000000..de9d632489609136c712a9adaee941fd + return this.val[index]; + } +} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/util/IntegerUtil.java b/src/main/java/ca/spottedleaf/dataconverter/util/IntegerUtil.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b5ebf6bbe1a3711111cf045ee8b46c934c7e4563 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/util/IntegerUtil.java +@@ -0,0 +1,223 @@ ++package ca.spottedleaf.dataconverter.util; ++ ++public final class IntegerUtil { ++ public static final int HIGH_BIT_U32 = Integer.MIN_VALUE; ++ public static final long HIGH_BIT_U64 = Long.MIN_VALUE; ++ ++ public static int ceilLog2(final int value) { ++ return Integer.SIZE - Integer.numberOfLeadingZeros(value - 1); // see doc of numberOfLeadingZeros ++ } ++ ++ public static long ceilLog2(final long value) { ++ return Long.SIZE - Long.numberOfLeadingZeros(value - 1); // see doc of numberOfLeadingZeros ++ } ++ ++ public static int floorLog2(final int value) { ++ // xor is optimized subtract for 2^n -1 ++ // note that (2^n -1) - k = (2^n -1) ^ k for k <= (2^n - 1) ++ return (Integer.SIZE - 1) ^ Integer.numberOfLeadingZeros(value); // see doc of numberOfLeadingZeros ++ } ++ ++ public static int floorLog2(final long value) { ++ // xor is optimized subtract for 2^n -1 ++ // note that (2^n -1) - k = (2^n -1) ^ k for k <= (2^n - 1) ++ return (Long.SIZE - 1) ^ Long.numberOfLeadingZeros(value); // see doc of numberOfLeadingZeros ++ } ++ ++ public static int roundCeilLog2(final int value) { ++ // optimized variant of 1 << (32 - leading(val - 1)) ++ // given ++ // 1 << n = HIGH_BIT_32 >>> (31 - n) for n [0, 32) ++ // 1 << (32 - leading(val - 1)) = HIGH_BIT_32 >>> (31 - (32 - leading(val - 1))) ++ // HIGH_BIT_32 >>> (31 - (32 - leading(val - 1))) ++ // HIGH_BIT_32 >>> (31 - 32 + leading(val - 1)) ++ // HIGH_BIT_32 >>> (-1 + leading(val - 1)) ++ return HIGH_BIT_U32 >>> (Integer.numberOfLeadingZeros(value - 1) - 1); ++ } ++ ++ public static long roundCeilLog2(final long value) { ++ // see logic documented above ++ return HIGH_BIT_U64 >>> (Long.numberOfLeadingZeros(value - 1) - 1); ++ } ++ ++ public static int roundFloorLog2(final int value) { ++ // optimized variant of 1 << (31 - leading(val)) ++ // given ++ // 1 << n = HIGH_BIT_32 >>> (31 - n) for n [0, 32) ++ // 1 << (31 - leading(val)) = HIGH_BIT_32 >> (31 - (31 - leading(val))) ++ // HIGH_BIT_32 >> (31 - (31 - leading(val))) ++ // HIGH_BIT_32 >> (31 - 31 + leading(val)) ++ return HIGH_BIT_U32 >>> Integer.numberOfLeadingZeros(value); ++ } ++ ++ public static long roundFloorLog2(final long value) { ++ // see logic documented above ++ return HIGH_BIT_U64 >>> Long.numberOfLeadingZeros(value); ++ } ++ ++ public static boolean isPowerOfTwo(final int n) { ++ // 2^n has one bit ++ // note: this rets true for 0 still ++ return IntegerUtil.getTrailingBit(n) == n; ++ } ++ ++ public static boolean isPowerOfTwo(final long n) { ++ // 2^n has one bit ++ // note: this rets true for 0 still ++ return IntegerUtil.getTrailingBit(n) == n; ++ } ++ ++ public static int getTrailingBit(final int n) { ++ return -n & n; ++ } ++ ++ public static long getTrailingBit(final long n) { ++ return -n & n; ++ } ++ ++ public static int trailingZeros(final int n) { ++ return Integer.numberOfTrailingZeros(n); ++ } ++ ++ public static int trailingZeros(final long n) { ++ return Long.numberOfTrailingZeros(n); ++ } ++ ++ // from hacker's delight (signed division magic value) ++ public static int getDivisorMultiple(final long numbers) { ++ return (int)(numbers >>> 32); ++ } ++ ++ // from hacker's delight (signed division magic value) ++ public static int getDivisorShift(final long numbers) { ++ return (int)numbers; ++ } ++ ++ public static long getDivisorNumbers(final int d) { ++ final int ad = Math.abs(d); ++ ++ if (ad < 2) { ++ throw new IllegalArgumentException("|number| must be in [2, 2^31 -1], not: " + d); ++ } ++ ++ final int two31 = 0x80000000; ++ final long mask = 0xFFFFFFFFL; // mask for enforcing unsigned behaviour ++ ++ int p = 31; ++ ++ // all these variables are UNSIGNED! ++ int t = two31 + (d >>> 31); ++ int anc = t - 1 - (int)((t & mask)%ad); ++ int q1 = (int)((two31 & mask)/(anc & mask)); ++ int r1 = two31 - q1*anc; ++ int q2 = (int)((two31 & mask)/(ad & mask)); ++ int r2 = two31 - q2*ad; ++ int delta; ++ ++ do { ++ p = p + 1; ++ q1 = 2*q1; // Update q1 = 2**p/|nc|. ++ r1 = 2*r1; // Update r1 = rem(2**p, |nc|). ++ if ((r1 & mask) >= (anc & mask)) {// (Must be an unsigned comparison here) ++ q1 = q1 + 1; ++ r1 = r1 - anc; ++ } ++ q2 = 2*q2; // Update q2 = 2**p/|d|. ++ r2 = 2*r2; // Update r2 = rem(2**p, |d|). ++ if ((r2 & mask) >= (ad & mask)) {// (Must be an unsigned comparison here) ++ q2 = q2 + 1; ++ r2 = r2 - ad; ++ } ++ delta = ad - r2; ++ } while ((q1 & mask) < (delta & mask) || (q1 == delta && r1 == 0)); ++ ++ int magicNum = q2 + 1; ++ if (d < 0) { ++ magicNum = -magicNum; ++ } ++ int shift = p - 32; ++ return ((long)magicNum << 32) | shift; ++ } ++ ++ public static int branchlessAbs(final int val) { ++ // -n = -1 ^ n + 1 ++ final int mask = val >> (Integer.SIZE - 1); // -1 if < 0, 0 if >= 0 ++ return (mask ^ val) - mask; // if val < 0, then (0 ^ val) - 0 else (-1 ^ val) + 1 ++ } ++ ++ public static long branchlessAbs(final long val) { ++ // -n = -1 ^ n + 1 ++ final long mask = val >> (Long.SIZE - 1); // -1 if < 0, 0 if >= 0 ++ return (mask ^ val) - mask; // if val < 0, then (0 ^ val) - 0 else (-1 ^ val) + 1 ++ } ++ ++ //https://github.com/skeeto/hash-prospector for hash functions ++ ++ //score = ~590.47984224483832 ++ public static int hash0(int x) { ++ x *= 0x36935555; ++ x ^= x >>> 16; ++ return x; ++ } ++ ++ //score = ~310.01596637036749 ++ public static int hash1(int x) { ++ x ^= x >>> 15; ++ x *= 0x356aaaad; ++ x ^= x >>> 17; ++ return x; ++ } ++ ++ public static int hash2(int x) { ++ x ^= x >>> 16; ++ x *= 0x7feb352d; ++ x ^= x >>> 15; ++ x *= 0x846ca68b; ++ x ^= x >>> 16; ++ return x; ++ } ++ ++ public static int hash3(int x) { ++ x ^= x >>> 17; ++ x *= 0xed5ad4bb; ++ x ^= x >>> 11; ++ x *= 0xac4c1b51; ++ x ^= x >>> 15; ++ x *= 0x31848bab; ++ x ^= x >>> 14; ++ return x; ++ } ++ ++ //score = ~365.79959673201887 ++ public static long hash1(long x) { ++ x ^= x >>> 27; ++ x *= 0xb24924b71d2d354bL; ++ x ^= x >>> 28; ++ return x; ++ } ++ ++ //h2 hash ++ public static long hash2(long x) { ++ x ^= x >>> 32; ++ x *= 0xd6e8feb86659fd93L; ++ x ^= x >>> 32; ++ x *= 0xd6e8feb86659fd93L; ++ x ^= x >>> 32; ++ return x; ++ } ++ ++ public static long hash3(long x) { ++ x ^= x >>> 45; ++ x *= 0xc161abe5704b6c79L; ++ x ^= x >>> 41; ++ x *= 0xe3e5389aedbc90f7L; ++ x ^= x >>> 56; ++ x *= 0x1f9aba75a52db073L; ++ x ^= x >>> 53; ++ return x; ++ } ++ ++ private IntegerUtil() { ++ throw new RuntimeException(); ++ } ++} diff --git a/src/main/java/ca/spottedleaf/dataconverter/util/Long2IntArraySortedMap.java b/src/main/java/ca/spottedleaf/dataconverter/util/Long2IntArraySortedMap.java new file mode 100644 index 0000000000000000000000000000000000000000..94705bb141b550589faa9a0408402d8636c61907 @@ -19567,81 +21612,25 @@ index 0000000000000000000000000000000000000000..967ad1186cbc81a76a4958ea99d4eff3 + return correct.equals(value) ? null : correct; + } +} -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -index b889dbad607b6508fb4987d21d3be691a5b37072..747e2a31f055d84d4321c8241e1b6c2918557e91 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -@@ -75,7 +75,7 @@ public class ChunkStorage implements AutoCloseable { - boolean flag = true; +diff --git a/src/main/java/net/minecraft/util/datafix/DataFixers.java b/src/main/java/net/minecraft/util/datafix/DataFixers.java +index b08d32bc80b4a65ebb980366a3e717c3b0e1bdab..4c5d893c8c29a8395ecb769b20772ba80f66d4ac 100644 +--- a/src/main/java/net/minecraft/util/datafix/DataFixers.java ++++ b/src/main/java/net/minecraft/util/datafix/DataFixers.java +@@ -86,9 +86,16 @@ public class DataFixers { + DataFixerBuilder datafixerbuilder = new DataFixerBuilder(SharedConstants.getCurrentVersion().getWorldVersion()); - // CraftBukkit start -- if (i < 1466) { -+ if (false && i < 1466) { // Paper - no longer needed, data converter system handles it now - CompoundTag level = nbttagcompound.getCompound("Level"); - if (level.getBoolean("TerrainPopulated") && !level.getBoolean("LightPopulated")) { - ServerChunkCache cps = (generatoraccess == null) ? null : ((ServerLevel) generatoraccess).getChunkSource(); -@@ -87,7 +87,7 @@ public class ChunkStorage implements AutoCloseable { - // CraftBukkit end - - if (i < 1493) { -- nbttagcompound = NbtUtils.update(this.fixerUpper, DataFixTypes.CHUNK, nbttagcompound, i, 1493); -+ ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, nbttagcompound, i, 1493); // Paper - replace chunk converter - if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) { - synchronized (this.persistentDataLock) { // Paper - Async chunk loading - if (this.legacyStructureHandler == null) { -@@ -99,7 +99,7 @@ public class ChunkStorage implements AutoCloseable { - } - } - -- nbttagcompound = NbtUtils.update(this.fixerUpper, DataFixTypes.CHUNK, nbttagcompound, Math.max(1493, i)); -+ nbttagcompound = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, nbttagcompound, Math.max(1493, i), SharedConstants.getCurrentVersion().getWorldVersion()); // Paper - replace chunk converter - if (i < SharedConstants.getCurrentVersion().getWorldVersion()) { - nbttagcompound.putInt("DataVersion", SharedConstants.getCurrentVersion().getWorldVersion()); - } -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -index 0e13a1f898a793799416056bd468851013f9c5cb..916f93b097a65f95e830fe5e1567c85d304f808f 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -@@ -148,7 +148,7 @@ public class EntityStorage implements EntityPersistentStorage { - private CompoundTag upgradeChunkTag(CompoundTag chunkTag) { - int i = EntityStorage.getVersion(chunkTag); - -- return NbtUtils.update(this.fixerUpper, DataFixTypes.ENTITY_CHUNK, chunkTag, i); -+ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY_CHUNK, chunkTag, i, SharedConstants.getCurrentVersion().getWorldVersion()); // Paper - route to new converter system + DataFixers.addFixers(datafixerbuilder); +- return datafixerbuilder.build(Util.bootstrapExecutor()); ++ return redirectToDataconverter(datafixerbuilder, Util.bootstrapExecutor()); // Paper } - public static int getVersion(CompoundTag chunkTag) { -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -index e2d1149cbe75b0689c9f816b87ebb7ba0d6f56c8..a7a51aa31628d9dbc30f43ef74022b0cd917be7c 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -@@ -135,7 +135,15 @@ public class SectionStorage extends RegionFileStorage implements AutoCloseabl - int j = getVersion(dynamic); - int k = SharedConstants.getCurrentVersion().getWorldVersion(); - boolean bl = j != k; -- Dynamic dynamic2 = this.fixerUpper.update(this.type.getType(), dynamic, j, k); -+ // Paper start - route to new converter system -+ Dynamic dynamic2; ++ // Paper start ++ private static DataFixer redirectToDataconverter(final DataFixerBuilder instance, final java.util.concurrent.Executor executor) { ++ final DataFixer wrap = instance.build(executor); ++ return new ca.spottedleaf.dataconverter.minecraft.ReplacedDataFixerUpper(wrap); ++ } ++ // Paper end + -+ if (this.type.getType() == net.minecraft.util.datafix.fixes.References.POI_CHUNK) { -+ dynamic2 = new Dynamic<>(dynamic.getOps(), (T)ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.POI_CHUNK, (CompoundTag)dynamic.getValue(), j, k)); -+ } else { -+ dynamic2 = this.fixerUpper.update(this.type.getType(), dynamic, j, k); -+ } -+ // Paper end - route to new converter system - OptionalDynamic optionalDynamic = dynamic2.get("Sections"); - - for(int l = this.levelHeightAccessor.getMinSection(); l < this.levelHeightAccessor.getMaxSection(); ++l) { -diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java -index 6727468946ea5f60bd80549f827a7c2b9a42b98b..35c39aed9583275ef25d32c783715798b52bdb63 100644 ---- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java -+++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java -@@ -93,7 +93,7 @@ public class PlayerDataStorage { - // CraftBukkit end - int i = nbttagcompound.contains("DataVersion", 3) ? nbttagcompound.getInt("DataVersion") : -1; - -- player.load(NbtUtils.update(this.fixerUpper, DataFixTypes.PLAYER, nbttagcompound, i)); -+ player.load(ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.PLAYER, nbttagcompound, i, net.minecraft.SharedConstants.getCurrentVersion().getWorldVersion())); // Paper - replace player converter - } - - return nbttagcompound; + public static DataFixer getDataFixer() { + return DataFixers.DATA_FIXER; + } diff --git a/todo.txt b/todo.txt index be6bbf98d0..a563b5f0e2 100644 --- a/todo.txt +++ b/todo.txt @@ -29,3 +29,5 @@ check ChunkHolder#updateFutures async catcher leaf: check mid tick chunk task diff in ServerChunkCache +optimize nearby player lookups - look at patch and updateranges diff in chunkmap (why is it in this patch) +GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE_SQUARED is unused?