From 77baea3bf9f720266f0cd1f1b51da97087e386c1 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Thu, 24 Oct 2024 08:18:20 -0700 Subject: [PATCH] Begin fixing issues See diff in the update text file --- moonrise_update_1_21_2.txt | 10 +- ...-Utils.patch => 0822-fixup-MC-Utils.patch} | 254 ++- patches/server/0823-fixup-MC-Utils.patch | 117 ++ .../Moonrise-optimisation-patches.patch | 1807 ++++++----------- ...ble-implementation-for-blockstate-st.patch | 345 ---- .../server/Rewrite-dataconverter-system.patch | 1518 +++++++++++--- .../fixup-Moonrise-optimisation-patches.patch | 540 ++--- patches/server/fixup-Paper-config-files.patch | 87 + ...lementation-for-blockstate-state-loo.patch | 343 ---- 9 files changed, 2540 insertions(+), 2481 deletions(-) rename patches/server/{1070-fixup-MC-Utils.patch => 0822-fixup-MC-Utils.patch} (84%) create mode 100644 patches/server/0823-fixup-MC-Utils.patch rename patches/{unapplied => }/server/Moonrise-optimisation-patches.patch (95%) delete mode 100644 patches/server/Revert-Custom-table-implementation-for-blockstate-st.patch rename patches/{unapplied => }/server/Rewrite-dataconverter-system.patch (97%) create mode 100644 patches/server/fixup-Paper-config-files.patch delete mode 100644 patches/unapplied/server/Custom-table-implementation-for-blockstate-state-loo.patch diff --git a/moonrise_update_1_21_2.txt b/moonrise_update_1_21_2.txt index f7067cc556..d6a3d5df42 100644 --- a/moonrise_update_1_21_2.txt +++ b/moonrise_update_1_21_2.txt @@ -13,12 +13,7 @@ add notes to moonrise patch: todo: - double check that the misc changes commit on dev/1.21.2 moonrise is applied - implement platformhooks -- delete old block state table patch -- in StateHolder, implement getNullableValue from blockstate_propertyaccess -- ChunkEntitySlices getChunkEntities(), callEntitiesLoadEvent(), callEntitiesUnloadEvent() - in ChunkEntitySlices, implement modifySavedEntities() by copying from old -- in ChunkEntitySlices, implement unload() Entity.setRemoved() -- change PersistentEntitySectionManager addEntity chunk system call to have event=true - implement PlayerChunkUnloadEvent in PlatformHooks#onChunkUnWatch - make sure chunk pos is passed in PlatformHooks#postLoadProtoChunk - implement chunk_system.ChunkMapMixin diff from reference @@ -32,11 +27,10 @@ todo: - implement chunk_system.ServerLevelMixin diff from reference - implement chunk_tick_iteration - implement collisions.ServerExplosionMixin diff from reference -- implement modifyEntityTrackingRange with org.spigotmc.TrackingRange.getEntityTrackingRange -- implement random_ticking.BiomeMixin diff from reference - implement starlight.LevelLightEngineMixin diff from reference - implement starlight.ThreadedLevelLightEngineMixin diff from reference - implement starlight.ChunkSerializerMixin diff from reference - implement starlight.SerializableChunkData$SectionData diff from reference - implement starlight.SerializableChunkDataMixin diff from reference - +- unfuck the chtunk system config diff +- chunk system: move get entity lookup reroute into the folia scheduler api patch diff --git a/patches/server/1070-fixup-MC-Utils.patch b/patches/server/0822-fixup-MC-Utils.patch similarity index 84% rename from patches/server/1070-fixup-MC-Utils.patch rename to patches/server/0822-fixup-MC-Utils.patch index f12a27d1b4..58054eaa30 100644 --- a/patches/server/1070-fixup-MC-Utils.patch +++ b/patches/server/0822-fixup-MC-Utils.patch @@ -12,10 +12,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package ca.spottedleaf.moonrise.common; + -+import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder; +import com.mojang.datafixers.DataFixer; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; ++import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.GenerationChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; @@ -56,7 +56,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + public boolean allowAsyncTicketUpdates(); + -+ public void onChunkHolderTicketChange(final ServerLevel world, final NewChunkHolder holder, final int oldLevel, final int newLevel); ++ public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel); + + public void chunkUnloadFromWorld(final LevelChunk chunk); + @@ -694,11 +694,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 -import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; +import ca.spottedleaf.concurrentutil.util.Priority; +import ca.spottedleaf.moonrise.common.PlatformHooks; - import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel; - import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk; - import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader; + import com.mojang.logging.LogUtils; + import net.minecraft.server.level.ChunkHolder; + import net.minecraft.server.level.FullChunkStatus; @@ -0,0 +0,0 @@ public final class ChunkSystem { - private static final Logger LOGGER = LogUtils.getLogger(); + } public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { - scheduleChunkTask(level, chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL); @@ -707,27 +707,47 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { + public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority priority) { - ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkTask(chunkX, chunkZ, run, priority); + level.chunkSource.mainThreadProcessor.execute(run); } public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, - final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, + final ChunkStatus toStatus, final boolean addTicket, final Priority priority, final Consumer onComplete) { - ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, gen, toStatus, addTicket, priority, onComplete); - } + if (gen) { + scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +@@ -0,0 +0,0 @@ public final class ChunkSystem { + private static long chunkLoadCounter = 0L; public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, - final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { + final boolean addTicket, final Priority priority, final Consumer onComplete) { - ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); + if (!org.bukkit.Bukkit.isPrimaryThread()) { + scheduleChunkTask(level, chunkX, chunkZ, () -> { + scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +@@ -0,0 +0,0 @@ public final class ChunkSystem { + } + loadCallback.accept(result.orElse(null)); + }, (final Runnable r) -> { +- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); ++ scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST); + }); } public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, final FullChunkStatus toStatus, final boolean addTicket, - final PrioritisedExecutor.Priority priority, final Consumer onComplete) { + final Priority priority, final Consumer onComplete) { - ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); + // This method goes unused until the chunk system rewrite + if (toStatus == FullChunkStatus.INACCESSIBLE) { + throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); +@@ -0,0 +0,0 @@ public final class ChunkSystem { + } + loadCallback.accept(result.orElse(null)); + }, (final Runnable r) -> { +- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); ++ scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST); + }); } @@ -0,0 +0,0 @@ public final class ChunkSystem { @@ -1002,6 +1022,211 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public static int getMaxLightSection(final LevelHeightAccessor world) { +diff --git a/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.moonrise.paper; ++ ++import ca.spottedleaf.moonrise.common.PlatformHooks; ++import com.mojang.datafixers.DataFixer; ++import net.minecraft.core.BlockPos; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.server.level.ChunkHolder; ++import net.minecraft.server.level.GenerationChunkHolder; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.util.datafix.DataFixTypes; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.level.BlockGetter; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.Level; ++import net.minecraft.world.level.block.state.BlockState; ++import net.minecraft.world.level.chunk.ChunkAccess; ++import net.minecraft.world.level.chunk.LevelChunk; ++import net.minecraft.world.level.chunk.ProtoChunk; ++import net.minecraft.world.level.chunk.storage.SerializableChunkData; ++import net.minecraft.world.level.entity.EntityTypeTest; ++import net.minecraft.world.phys.AABB; ++import java.util.List; ++import java.util.function.Predicate; ++ ++public final class PaperHooks implements PlatformHooks { ++ ++ @Override ++ public String getBrand() { ++ return "Paper"; ++ } ++ ++ @Override ++ public int getLightEmission(final BlockState blockState, final BlockGetter world, final BlockPos pos) { ++ return blockState.getLightEmission(); ++ } ++ ++ @Override ++ public Predicate maybeHasLightEmission() { ++ return (final BlockState state) -> { ++ return state.getLightEmission() != 0; ++ }; ++ } ++ ++ @Override ++ public boolean hasCurrentlyLoadingChunk() { ++ return false; ++ } ++ ++ @Override ++ public LevelChunk getCurrentlyLoadingChunk(final GenerationChunkHolder holder) { ++ return null; ++ } ++ ++ @Override ++ public void setCurrentlyLoading(final GenerationChunkHolder holder, final LevelChunk levelChunk) { ++ ++ } ++ ++ @Override ++ public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) { ++ ++ } ++ ++ @Override ++ public boolean allowAsyncTicketUpdates() { ++ return true; ++ } ++ ++ @Override ++ public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel) { ++ ++ } ++ ++ @Override ++ public void chunkUnloadFromWorld(final LevelChunk chunk) { ++ ++ } ++ ++ @Override ++ public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) { ++ ++ } ++ ++ @Override ++ public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player) { ++ ++ } ++ ++ @Override ++ public void onChunkUnWatch(final ServerLevel world, final ChunkPos chunk, final ServerPlayer player) { ++ ++ } ++ ++ @Override ++ public void addToGetEntities(final Level world, final Entity entity, final AABB boundingBox, final Predicate predicate, final List into) { ++ ++ } ++ ++ @Override ++ public void addToGetEntities(final Level world, final EntityTypeTest entityTypeTest, final AABB boundingBox, final Predicate predicate, final List into, final int maxCount) { ++ ++ } ++ ++ @Override ++ public void entityMove(final Entity entity, final long oldSection, final long newSection) { ++ ++ } ++ ++ @Override ++ public boolean screenEntity(final ServerLevel world, final Entity entity, final boolean fromDisk, final boolean event) { ++ return true; ++ } ++ ++ @Override ++ public boolean configFixMC224294() { ++ return true; ++ } ++ ++ @Override ++ public boolean configAutoConfigSendDistance() { ++ ++ } ++ ++ @Override ++ public double configPlayerMaxLoadRate() { ++ ++ } ++ ++ @Override ++ public double configPlayerMaxGenRate() { ++ ++ } ++ ++ @Override ++ public double configPlayerMaxSendRate() { ++ ++ } ++ ++ @Override ++ public int configPlayerMaxConcurrentLoads() { ++ ++ } ++ ++ @Override ++ public int configPlayerMaxConcurrentGens() { ++ ++ } ++ ++ @Override ++ public long configAutoSaveInterval() { ++ ++ } ++ ++ @Override ++ public int configMaxAutoSavePerTick() { ++ ++ } ++ ++ @Override ++ public boolean configFixMC159283() { ++ return true; ++ } ++ ++ @Override ++ public boolean forceNoSave(final ChunkAccess chunk) { ++ return chunk instanceof LevelChunk levelChunk && levelChunk.mustNotSave; ++ } ++ ++ @Override ++ public CompoundTag convertNBT(final DataFixTypes type, final DataFixer dataFixer, final CompoundTag nbt, final int fromVersion, final int toVersion) { ++ return type.update(dataFixer, nbt, fromVersion, toVersion); ++ } ++ ++ @Override ++ public boolean hasMainChunkLoadHook() { ++ return false; ++ } ++ ++ @Override ++ public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData) { ++ ++ } ++ ++ @Override ++ public List modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List entities) { ++ return entities; ++ } ++ ++ @Override ++ public void unloadEntity(final Entity entity) { ++ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD); ++ } ++ ++ @Override ++ public int modifyEntityTrackingRange(final Entity entity, final int currentRange) { ++ return org.spigotmc.TrackingRange.getEntityTrackingRange(entity, currentRange); ++ } ++} 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java @@ -1029,3 +1254,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // Paper end - chunk system hooks if (!this.addEntityUuid(entity)) { +diff --git a/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks b/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks +@@ -0,0 +1 @@ ++ca.spottedleaf.moonrise.paper.PaperHooks diff --git a/patches/server/0823-fixup-MC-Utils.patch b/patches/server/0823-fixup-MC-Utils.patch new file mode 100644 index 0000000000..931b8cc0cd --- /dev/null +++ b/patches/server/0823-fixup-MC-Utils.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Wed, 23 Oct 2024 22:13:41 -0700 +Subject: [PATCH] fixup! MC Utils + + +diff --git a/src/main/java/ca/spottedleaf/moonrise/common/PlatformHooks.java b/src/main/java/ca/spottedleaf/moonrise/common/PlatformHooks.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/ca/spottedleaf/moonrise/common/PlatformHooks.java ++++ b/src/main/java/ca/spottedleaf/moonrise/common/PlatformHooks.java +@@ -0,0 +0,0 @@ + package ca.spottedleaf.moonrise.common; + ++import com.mojang.datafixers.DSL; + import com.mojang.datafixers.DataFixer; + import net.minecraft.core.BlockPos; + import net.minecraft.nbt.CompoundTag; +@@ -0,0 +0,0 @@ import net.minecraft.server.level.ChunkHolder; + import net.minecraft.server.level.GenerationChunkHolder; + import net.minecraft.server.level.ServerLevel; + import net.minecraft.server.level.ServerPlayer; +-import net.minecraft.util.datafix.DataFixTypes; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.level.BlockGetter; + import net.minecraft.world.level.ChunkPos; +@@ -0,0 +0,0 @@ public interface PlatformHooks { + // support for CB chunk mustNotSave + public boolean forceNoSave(final ChunkAccess chunk); + +- public CompoundTag convertNBT(final DataFixTypes type, final DataFixer dataFixer, final CompoundTag nbt, ++ public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt, + final int fromVersion, final int toVersion); + + public boolean hasMainChunkLoadHook(); +@@ -0,0 +0,0 @@ public interface PlatformHooks { + + public void unloadEntity(final Entity entity); + ++ public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk); ++ + public int modifyEntityTrackingRange(final Entity entity, final int currentRange); + + public static final class Holder { +diff --git a/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java ++++ b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java +@@ -0,0 +0,0 @@ + package ca.spottedleaf.moonrise.paper; + + import ca.spottedleaf.moonrise.common.PlatformHooks; ++import com.mojang.datafixers.DSL; + import com.mojang.datafixers.DataFixer; ++import com.mojang.serialization.Dynamic; + import net.minecraft.core.BlockPos; + import net.minecraft.nbt.CompoundTag; ++import net.minecraft.nbt.NbtOps; + import net.minecraft.server.level.ChunkHolder; + import net.minecraft.server.level.GenerationChunkHolder; + import net.minecraft.server.level.ServerLevel; + import net.minecraft.server.level.ServerPlayer; +-import net.minecraft.util.datafix.DataFixTypes; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.level.BlockGetter; + import net.minecraft.world.level.ChunkPos; +@@ -0,0 +0,0 @@ public final class PaperHooks implements PlatformHooks { + } + + @Override +- public CompoundTag convertNBT(final DataFixTypes type, final DataFixer dataFixer, final CompoundTag nbt, final int fromVersion, final int toVersion) { +- return type.update(dataFixer, nbt, fromVersion, toVersion); ++ public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt, ++ final int fromVersion, final int toVersion) { ++ return (CompoundTag)dataFixer.update( ++ type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion ++ ).getValue(); + } + + @Override +@@ -0,0 +0,0 @@ public final class PaperHooks implements PlatformHooks { + entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD); + } + ++ @Override ++ public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) { ++ net.minecraft.world.level.chunk.status.ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities()); ++ } ++ + @Override + public int modifyEntityTrackingRange(final Entity entity, final int currentRange) { + return org.spigotmc.TrackingRange.getEntityTrackingRange(entity, currentRange); +diff --git a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java ++++ b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java +@@ -0,0 +0,0 @@ public class ChunkStatusTasks { + }, context.mainThreadExecutor()); + } + +- private static void postLoadProtoChunk(ServerLevel world, List entities) { ++ public static void postLoadProtoChunk(ServerLevel world, List entities) { // Paper - public + if (!entities.isEmpty()) { + // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities + world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entities, world, EntitySpawnReason.LOAD).filter((entity) -> { +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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java ++++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager implements A + // I don't want to know why this is a generic type. + Entity entityCasted = (Entity)entity; + boolean wasRemoved = entityCasted.isRemoved(); +- boolean screened = ca.spottedleaf.moonrise.common.util.ChunkSystem.screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted, existing, false); ++ boolean screened = ca.spottedleaf.moonrise.common.util.ChunkSystem.screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted, existing, true); + if ((!wasRemoved && entityCasted.isRemoved()) || !screened) { + // removed by callback + return false; diff --git a/patches/unapplied/server/Moonrise-optimisation-patches.patch b/patches/server/Moonrise-optimisation-patches.patch similarity index 95% rename from patches/unapplied/server/Moonrise-optimisation-patches.patch rename to patches/server/Moonrise-optimisation-patches.patch index e8389b11df..08336751c6 100644 --- a/patches/unapplied/server/Moonrise-optimisation-patches.patch +++ b/patches/server/Moonrise-optimisation-patches.patch @@ -9,6 +9,10 @@ Currently includes: - Collision optimisations - Random block ticking optimisations - Chunk tick iteration optimisations + - Bitstorage optimisations + - Block/Biome Palette read optimisations + - StateHolder (BlockState/FluidState) property access optimisations + - Basic Fluid property read optimisations See https://github.com/Tuinity/Moonrise @@ -16,10 +20,10 @@ diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java -@@ -0,0 +0,0 @@ - package ca.spottedleaf.moonrise.common.util; +@@ -0,0 +0,0 @@ package ca.spottedleaf.moonrise.common.util; - import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; + import ca.spottedleaf.concurrentutil.util.Priority; + import ca.spottedleaf.moonrise.common.PlatformHooks; +import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel; +import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk; +import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader; @@ -38,16 +42,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { - scheduleChunkTask(level, chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL); + scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL); } - public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { + public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority priority) { - level.chunkSource.mainThreadProcessor.execute(run); + ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkTask(chunkX, chunkZ, run, priority); } public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, - final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, + final ChunkStatus toStatus, final boolean addTicket, final Priority priority, final Consumer onComplete) { - if (gen) { - scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); @@ -75,7 +79,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - - private static long chunkLoadCounter = 0L; public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, - final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { + final boolean addTicket, final Priority priority, final Consumer onComplete) { - if (!org.bukkit.Bukkit.isPrimaryThread()) { - scheduleChunkTask(level, chunkX, chunkZ, () -> { - scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); @@ -129,14 +133,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - loadCallback.accept(result.orElse(null)); - }, (final Runnable r) -> { -- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); +- scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST); - }); + ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); } public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, final FullChunkStatus toStatus, final boolean addTicket, - final PrioritisedExecutor.Priority priority, final Consumer onComplete) { + final Priority priority, final Consumer onComplete) { - // This method goes unused until the chunk system rewrite - if (toStatus == FullChunkStatus.INACCESSIBLE) { - throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); @@ -213,7 +217,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - loadCallback.accept(result.orElse(null)); - }, (final Runnable r) -> { -- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); +- scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST); - }); + ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); } @@ -342,6 +346,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } private ChunkSystem() {} +diff --git a/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java ++++ b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java +@@ -0,0 +0,0 @@ public final class PaperHooks implements PlatformHooks { + + @Override + public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) { +- net.minecraft.world.level.chunk.status.ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities()); ++ net.minecraft.world.level.chunk.status.ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities(), chunk.getPos()); // Paper - rewrite chunk system - add ChunkPos param + } + + @Override diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -4735,10 +4752,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + +public interface ChunkSystemSectionStorage { + -+ public CompoundTag moonrise$read(final int chunkX, final int chunkZ) throws IOException; -+ -+ public void moonrise$write(final int chunkX, final int chunkZ, final CompoundTag data) throws IOException; -+ + public RegionFileStorage moonrise$getRegionStorage(); + + public void moonrise$close() throws IOException; @@ -22441,8 +22454,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import co.aikar.timings.MinecraftTimings; // Paper --public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource, AutoCloseable { -+public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource, AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer { // Paper - rewrite chunk system +-public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource { ++public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource, ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer { // Paper - rewrite chunk system private static MinecraftServer SERVER; // Paper public static final Logger LOGGER = LogUtils.getLogger(); @@ -22602,19 +22615,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public String getLocalIp() { @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { - return false; - } : this::haveTime); -+ // Paper start - rewrite chunk system -+ final Throwable crash = this.chunkSystemCrash; -+ if (crash != null) { -+ this.chunkSystemCrash = null; -+ throw new RuntimeException("Chunk system crash propagated to tick()", crash); -+ } -+ // Paper end - rewrite chunk system - this.profiler.popPush("nextTickWait"); - this.mayHaveDelayedTasks = true; - this.delayedTasksMaxNextTickTimeNanos = Math.max(Util.getNanos() + i, this.nextTickTimeNanos); + this.tickServer(flag ? () -> { + return false; + } : this::haveTime); ++ // Paper start - rewrite chunk system ++ final Throwable crash = this.chunkSystemCrash; ++ if (crash != null) { ++ this.chunkSystemCrash = null; ++ throw new RuntimeException("Chunk system crash propagated to tick()", crash); ++ } ++ // Paper end - rewrite chunk system + this.tickFrame.end(); + gameprofilerfiller.popPush("nextTickWait"); + this.mayHaveDelayedTasks = true; @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { -- for (final Entity entity : level.getEntities().getAll()) { -+ for (final Entity entity : level.moonrise$getEntityLookup().getAllCopy()) { // Paper - rewrite chunk system - if (entity.isRemoved()) { - continue; - } -@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop savingFuture) { + @Override + protected void addSaveDependency(CompletableFuture savingFuture) { - if (this.saveSync.isDone()) { - this.saveSync = savingFuture; - } else { @@ -22927,21 +22932,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - public void blockChanged(BlockPos pos) { -- LevelChunk chunk = this.getTickingChunk(); -+ LevelChunk chunk = this.playersSentChunkTo.size() == 0 ? null : this.getChunkToSend(); // Paper - rewrite chunk system - - if (chunk != null) { - int i = this.levelHeightAccessor.getSectionIndex(pos.getY()); @@ -0,0 +0,0 @@ public class ChunkHolder extends GenerationChunkHolder { - - if (ichunkaccess != null) { - ichunkaccess.setUnsaved(true); + return false; + } else { + ichunkaccess.markUnsaved(); - LevelChunk chunk = this.getTickingChunk(); + LevelChunk chunk = this.getChunkToSend(); // Paper - rewrite chunk system - if (chunk != null) { - int j = this.lightEngine.getMinLightSection(); + if (chunk == null) { + return false; @@ -0,0 +0,0 @@ public class ChunkHolder extends GenerationChunkHolder { List list; @@ -23006,10 +23005,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } -- // CraftBukkit start -- // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins. -- // SPIGOT-7780: Moved out of updateFutures to call all chunk unload events before calling updateHighestAllowedStatus for all chunks -- protected void callEventIfUnloading(ChunkMap playerchunkmap) { + // CraftBukkit start + // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins. + // SPIGOT-7780: Moved out of updateFutures to call all chunk unload events before calling updateHighestAllowedStatus for all chunks + protected void callEventIfUnloading(ChunkMap playerchunkmap) { - FullChunkStatus oldFullChunkStatus = ChunkLevel.fullStatus(this.oldTicketLevel); - FullChunkStatus newFullChunkStatus = ChunkLevel.fullStatus(this.ticketLevel); - boolean oldIsFull = oldFullChunkStatus.isOrAfter(FullChunkStatus.FULL); @@ -23022,7 +23021,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - // Minecraft will apply the chunks tick lists to the world once the chunk got loaded, and then store the tick - // lists again inside the chunk once the chunk becomes inaccessible and set the chunk's needsSaving flag. - // These actions may however happen deferred, so we manually set the needsSaving flag already here. -- chunk.setUnsaved(true); +- chunk.markUnsaved(); - chunk.unloadCallback(); - }); - } @@ -23035,9 +23034,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - // Run callback right away if the future was already done - playerchunkmap.callbackExecutor.run(); - } -- } -- // CraftBukkit end -- ++ throw new UnsupportedOperationException(); // Paper - rewrite chunk system + } + // CraftBukkit end + protected void updateFutures(ChunkMap chunkLoadingManager, Executor executor) { - FullChunkStatus fullchunkstatus = ChunkLevel.fullStatus(this.oldTicketLevel); - FullChunkStatus fullchunkstatus1 = ChunkLevel.fullStatus(this.ticketLevel); @@ -23208,9 +23208,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private final PoiManager poiManager; public final LongSet toDrop; private boolean modified; -- private final ChunkTaskPriorityQueueSorter queueSorter; -- private final ProcessorHandle> worldgenMailbox; -- private final ProcessorHandle> mainThreadMailbox; +- private final ChunkTaskDispatcher worldgenTaskDispatcher; +- private final ChunkTaskDispatcher lightTaskDispatcher; + // Paper - rewrite chunk system public final ChunkProgressListener progressListener; private final ChunkStatusUpdateListener chunkStatusListener; @@ -23221,8 +23220,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private final PlayerMap playerMap; public final Int2ObjectMap entityMap; private final Long2ByteMap chunkTypeCache; - private final Long2LongMap chunkSaveCooldowns; +- private final Long2LongMap nextChunkSaveTime; +- private final LongSet chunksToEagerlySave; - private final Queue unloadQueue; +- private final AtomicInteger activeChunkWrites; + // Paper - rewrite chunk system public int serverViewDistance; - private final WorldGenContext worldGenContext; @@ -23250,31 +23251,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.playerMap = new PlayerMap(); this.entityMap = new Int2ObjectOpenHashMap(); this.chunkTypeCache = new Long2ByteOpenHashMap(); - this.chunkSaveCooldowns = new Long2LongOpenHashMap(); +- this.nextChunkSaveTime = new Long2LongOpenHashMap(); +- this.chunksToEagerlySave = new LongLinkedOpenHashSet(); - this.unloadQueue = Queues.newConcurrentLinkedQueue(); +- this.activeChunkWrites = new AtomicInteger(); + // Paper - rewrite chunk system Path path = session.getDimensionPath(world.dimension()); this.storageName = path.getFileName().toString(); @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.chunkStatusListener = chunkStatusChangeListener; - ProcessorMailbox threadedmailbox1 = ProcessorMailbox.create(executor, "light"); + ConsecutiveExecutor consecutiveexecutor1 = new ConsecutiveExecutor(executor, "light"); -- this.queueSorter = new ChunkTaskPriorityQueueSorter(ImmutableList.of(threadedmailbox, mailbox, threadedmailbox1), executor, Integer.MAX_VALUE); -- this.worldgenMailbox = this.queueSorter.getProcessor(threadedmailbox, false); -- this.mainThreadMailbox = this.queueSorter.getProcessor(mailbox, false); -- this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, this.queueSorter.getProcessor(threadedmailbox1, false)); -+ // Paper - rewrite chunk system -+ this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, null); // Paper - rewrite chunk system +- this.worldgenTaskDispatcher = new ChunkTaskDispatcher(consecutiveexecutor, executor); +- this.lightTaskDispatcher = new ChunkTaskDispatcher(consecutiveexecutor1, executor); +- this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), consecutiveexecutor1, this.lightTaskDispatcher); ++ this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), consecutiveexecutor1, null); // Paper - rewrite chunk system this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor); this.overworldDataStorage = persistentStateManagerFactory; this.poiManager = new PoiManager(new RegionStorageInfo(session.getLevelId(), world.dimension(), "poi"), path.resolve("poi"), dataFixer, dsync, iregistrycustom, world.getServer(), world); this.setServerViewDistance(viewDistance); -- this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, this.mainThreadMailbox); -+ this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, null); // Paper - rewrite chunk system +- this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, mainThreadExecutor, this::setChunkUnsaved); ++ this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, null, this::setChunkUnsaved); // Paper - rewrite chunk system } - // Paper start + private void setChunkUnsaved(ChunkPos pos) { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -23342,27 +23343,28 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - return chunkresult.map(List::of); - }); - } else { -- List>> list = new ArrayList(); +- int j = Mth.square(margin * 2 + 1); +- List>> list = new ArrayList(j); - ChunkPos chunkcoordintpair = centerChunk.getPos(); - -- for (int j = -margin; j <= margin; ++j) { -- for (int k = -margin; k <= margin; ++k) { -- int l = Math.max(Math.abs(k), Math.abs(j)); -- long i1 = ChunkPos.asLong(chunkcoordintpair.x + k, chunkcoordintpair.z + j); -- ChunkHolder playerchunk1 = this.getUpdatingChunkIfPresent(i1); +- for (int k = -margin; k <= margin; ++k) { +- for (int l = -margin; l <= margin; ++l) { +- int i1 = Math.max(Math.abs(l), Math.abs(k)); +- long j1 = ChunkPos.asLong(chunkcoordintpair.x + l, chunkcoordintpair.z + k); +- ChunkHolder playerchunk1 = this.getUpdatingChunkIfPresent(j1); - - if (playerchunk1 == null) { - return ChunkMap.UNLOADED_CHUNK_LIST_FUTURE; - } - -- ChunkStatus chunkstatus1 = (ChunkStatus) distanceToStatus.apply(l); +- ChunkStatus chunkstatus1 = (ChunkStatus) distanceToStatus.apply(i1); - - list.add(playerchunk1.scheduleChunkGenerationTask(chunkstatus1, this)); - } - } - - return Util.sequence(list).thenApply((list1) -> { -- List list2 = Lists.newArrayList(); +- List list2 = new ArrayList(list1.size()); - Iterator iterator = list1.iterator(); - - while (iterator.hasNext()) { @@ -23394,11 +23396,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public CompletableFuture> prepareEntityTickingChunk(ChunkHolder holder) { - return this.getChunkRangeFuture(holder, 2, (i) -> { - return ChunkStatus.FULL; -- }).thenApplyAsync((chunkresult) -> { +- }).thenApply((chunkresult) -> { - return chunkresult.map((list) -> { - return (LevelChunk) list.get(list.size() / 2); - }); -- }, this.mainThreadExecutor); +- }); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -23424,7 +23426,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (holder != null) { - holder.setTicketLevel(level); - } else { -- holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); +- holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this::onLevelChange, this); - // Paper start - ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderCreate(this.level, holder); - // Paper end @@ -23439,16 +23441,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } + private void onLevelChange(ChunkPos pos, IntSupplier levelGetter, int targetLevel, IntConsumer levelSetter) { +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + @Override public void close() throws IOException { - try { -- this.queueSorter.close(); +- this.worldgenTaskDispatcher.close(); +- this.lightTaskDispatcher.close(); - this.poiManager.close(); - } finally { - super.close(); - } -- + throw new UnsupportedOperationException("Use ServerChunkCache#close"); // Paper - rewrite chunk system + } protected void saveAllChunks(boolean flush) { @@ -23471,103 +23477,119 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - }); - } while (mutableboolean.isTrue()); - +- this.poiManager.flushAll(); - this.processUnloads(() -> { - return true; - }); - this.flushWorker(); - } else { -- ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); -- } +- this.nextChunkSaveTime.clear(); +- long i = Util.getMillis(); +- Iterator objectiterator = ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper - +- while (objectiterator.hasNext()) { +- ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); +- +- this.saveChunkIfNeeded(playerchunk, i); +- } +- } ++ // Paper start - rewrite chunk system + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.saveAllChunks( + flush, false, false + ); ++ // Paper end - rewrite chunk system + } - protected void tick(BooleanSupplier shouldKeepTicking) { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public boolean hasWork() { -- return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || ca.spottedleaf.moonrise.common.util.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper +- return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || ca.spottedleaf.moonrise.common.util.ChunkSystem.hasAnyChunkHolders(this.level) || !this.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.worldgenTaskDispatcher.hasWork() || this.lightTaskDispatcher.hasWork() || this.distanceManager.hasTickets(); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } private void processUnloads(BooleanSupplier shouldKeepTicking) { -- LongIterator longiterator = this.toDrop.iterator(); -- int i = 0; -- -- while (longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000)) { -- long j = longiterator.nextLong(); -- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.get(j); +- for (LongIterator longiterator = this.toDrop.iterator(); longiterator.hasNext(); longiterator.remove()) { +- long i = longiterator.nextLong(); +- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.get(i); - - if (playerchunk != null) { -- if (playerchunk.getGenerationRefCount() != 0) { -- continue; -- } -- -- this.updatingChunkMap.remove(j); -- this.pendingUnloads.put(j, playerchunk); +- this.updatingChunkMap.remove(i); +- this.pendingUnloads.put(i, playerchunk); - this.modified = true; -- ++i; -- this.scheduleUnload(j, playerchunk); +- this.scheduleUnload(i, playerchunk); - } -- -- longiterator.remove(); - } - -- int k = Math.max(0, this.unloadQueue.size() - 2000); +- int j = Math.max(0, this.unloadQueue.size() - 2000); - - Runnable runnable; - -- while ((shouldKeepTicking.getAsBoolean() || k > 0) && (runnable = (Runnable) this.unloadQueue.poll()) != null) { -- --k; +- while ((j > 0 || shouldKeepTicking.getAsBoolean()) && (runnable = (Runnable) this.unloadQueue.poll()) != null) { +- --j; - runnable.run(); - } - -- int l = 0; -- Iterator objectiterator = ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper -- -- while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { -- if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { -- ++l; -- } -- } +- this.saveChunksEagerly(shouldKeepTicking); + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.processUnloads(); // Paper - rewrite chunk system + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.autoSave(); // Paper - rewrite chunk system + } + + private void saveChunksEagerly(BooleanSupplier shouldKeepTicking) { +- long i = Util.getMillis(); +- int j = 0; +- LongIterator longiterator = this.chunksToEagerlySave.iterator(); +- +- while (j < 20 && this.activeChunkWrites.get() < 128 && shouldKeepTicking.getAsBoolean() && longiterator.hasNext()) { +- long k = longiterator.nextLong(); +- ChunkHolder playerchunk = (ChunkHolder) this.visibleChunkMap.get(k); +- ChunkAccess ichunkaccess = playerchunk != null ? playerchunk.getLatestChunk() : null; +- +- if (ichunkaccess != null && ichunkaccess.isUnsaved()) { +- if (this.saveChunkIfNeeded(playerchunk, i)) { +- ++j; +- longiterator.remove(); +- } +- } else { +- longiterator.remove(); +- } +- } ++ throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void scheduleUnload(long pos, ChunkHolder holder) { -- CompletableFuture completablefuture = holder.getSaveSyncFuture(); + private void scheduleUnload(long pos, ChunkHolder chunk) { +- CompletableFuture completablefuture = chunk.getSaveSyncFuture(); - Runnable runnable = () -> { -- if (!holder.isReadyForSaving()) { -- this.scheduleUnload(pos, holder); -- } else { -- ChunkAccess ichunkaccess = holder.getLatestChunk(); +- CompletableFuture completablefuture1 = chunk.getSaveSyncFuture(); - +- if (completablefuture1 != completablefuture) { +- this.scheduleUnload(pos, chunk); +- } else { +- ChunkAccess ichunkaccess = chunk.getLatestChunk(); - // Paper start - boolean removed; -- if ((removed = this.pendingUnloads.remove(pos, holder)) && ichunkaccess != null) { -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderDelete(this.level, holder); +- if ((removed = this.pendingUnloads.remove(pos, chunk)) && ichunkaccess != null) { +- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderDelete(this.level, chunk); - // Paper end - LevelChunk chunk; - - if (ichunkaccess instanceof LevelChunk) { -- chunk = (LevelChunk) ichunkaccess; -- chunk.setLoaded(false); +- chunk1 = (LevelChunk) ichunkaccess; +- chunk1.setLoaded(false); - } - - this.save(ichunkaccess); - if (ichunkaccess instanceof LevelChunk) { -- chunk = (LevelChunk) ichunkaccess; -- this.level.unload(chunk); +- chunk1 = (LevelChunk) ichunkaccess; +- this.level.unload(chunk1); - } - - this.lightEngine.updateChunkStatus(ichunkaccess.getPos()); - this.lightEngine.tryScheduleUpdate(); - this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null); -- this.chunkSaveCooldowns.remove(ichunkaccess.getPos().toLong()); +- this.nextChunkSaveTime.remove(ichunkaccess.getPos().toLong()); - } else if (removed) { // Paper start - ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderDelete(this.level, holder); - } // Paper end @@ -23579,7 +23601,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - Objects.requireNonNull(this.unloadQueue); - completablefuture.thenRunAsync(runnable, queue::add).whenComplete((ovoid, throwable) -> { - if (throwable != null) { -- ChunkMap.LOGGER.error("Failed to save chunk {}", holder.getPos(), throwable); +- ChunkMap.LOGGER.error("Failed to save chunk {}", chunk.getPos(), throwable); - } - - }); @@ -23598,20 +23620,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } private CompletableFuture scheduleChunkLoad(ChunkPos pos) { -- return this.readChunk(pos).thenApply((optional) -> { -- return optional.filter((nbttagcompound) -> { -- boolean flag = ChunkMap.isChunkDataValid(nbttagcompound); +- CompletableFuture> completablefuture = this.readChunk(pos).thenApplyAsync((optional) -> { +- return optional.map((nbttagcompound) -> { +- SerializableChunkData serializablechunkdata = SerializableChunkData.parse(this.level, this.level.registryAccess(), nbttagcompound); - -- if (!flag) { +- if (serializablechunkdata == null) { - ChunkMap.LOGGER.error("Chunk file at {} is missing level data, skipping", pos); - } - -- return flag; +- return serializablechunkdata; - }); +- }, Util.backgroundExecutor().forName("parseChunk")); +- CompletableFuture completablefuture1 = this.poiManager.prefetch(pos); +- +- return completablefuture.thenCombine(completablefuture1, (optional, object) -> { +- return optional; - }).thenApplyAsync((optional) -> { -- this.level.getProfiler().incrementCounter("chunkLoad"); +- Profiler.get().incrementCounter("chunkLoad"); - if (optional.isPresent()) { -- ProtoChunk protochunk = ChunkSerializer.read(this.level, this.poiManager, this.storageInfo(), pos, (CompoundTag) optional.get()); +- ProtoChunk protochunk = ((SerializableChunkData) optional.get()).read(this.level, this.poiManager, this.storageInfo(), pos); - - this.markPosition(pos, protochunk.getPersistedStatus().getChunkType()); - return protochunk; @@ -23624,7 +23651,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private static boolean isChunkDataValid(CompoundTag nbt) { + private ChunkAccess handleChunkLoadFailure(Throwable throwable, ChunkPos chunkPos) { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Override @@ -23690,16 +23717,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void runGenerationTask(ChunkGenerationTask chunkLoader) { -- this.worldgenMailbox.tell(ChunkTaskPriorityQueueSorter.message(chunkLoader.getCenter(), () -> { -- CompletableFuture completablefuture = chunkLoader.runUntilWait(); + private void runGenerationTask(ChunkGenerationTask loader) { +- GenerationChunkHolder generationchunkholder = loader.getCenter(); +- ChunkTaskDispatcher chunktaskdispatcher = this.worldgenTaskDispatcher; +- Runnable runnable = () -> { +- CompletableFuture completablefuture = loader.runUntilWait(); - - if (completablefuture != null) { - completablefuture.thenRun(() -> { -- this.runGenerationTask(chunkLoader); +- this.runGenerationTask(loader); - }); - } -- })); +- }; +- long i = generationchunkholder.getPos().toLong(); +- +- Objects.requireNonNull(generationchunkholder); +- chunktaskdispatcher.submit(runnable, i, generationchunkholder::getQueueLevel); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -23716,24 +23749,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - }); - CompletableFuture> completablefuture1 = completablefuture.thenApplyAsync((chunkresult) -> { - return chunkresult.map((list) -> { -- return (LevelChunk) list.get(list.size() / 2); -- }); -- }, (runnable) -> { -- this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); -- }).thenApplyAsync((chunkresult) -> { -- return chunkresult.ifSuccess((chunk) -> { -- chunk.postProcessGeneration(); +- LevelChunk chunk = (LevelChunk) list.get(list.size() / 2); +- +- chunk.postProcessGeneration(this.level); - this.level.startTickingChunk(chunk); - CompletableFuture completablefuture2 = holder.getSendSyncFuture(); - - if (completablefuture2.isDone()) { -- this.onChunkReadyToSend(chunk); +- this.onChunkReadyToSend(holder, chunk); - } else { - completablefuture2.thenAcceptAsync((object) -> { -- this.onChunkReadyToSend(chunk); +- this.onChunkReadyToSend(holder, chunk); - }, this.mainThreadExecutor); - } - +- return chunk; - }); - }, this.mainThreadExecutor); - @@ -23745,7 +23775,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void onChunkReadyToSend(LevelChunk chunk) { + private void onChunkReadyToSend(ChunkHolder chunkHolder, LevelChunk chunk) { - ChunkPos chunkcoordintpair = chunk.getPos(); - Iterator iterator = this.playerMap.getAllPlayers().iterator(); - @@ -23756,17 +23786,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - ChunkMap.markChunkPendingToSend(entityplayer, chunk); - } - } +- +- this.level.getChunkSource().onChunkReadyToSend(chunkHolder); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system - } public CompletableFuture> prepareAccessibleChunk(ChunkHolder holder) { -- return this.getChunkRangeFuture(holder, 1, ChunkLevel::getStatusAroundFullChunk).thenApplyAsync((chunkresult) -> { +- return this.getChunkRangeFuture(holder, 1, ChunkLevel::getStatusAroundFullChunk).thenApply((chunkresult) -> { - return chunkresult.map((list) -> { - return (LevelChunk) list.get(list.size() / 2); - }); -- }, (runnable) -> { -- this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); - }); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -23775,25 +23804,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - private boolean saveChunkIfNeeded(ChunkHolder chunkHolder) { + private boolean saveChunkIfNeeded(ChunkHolder chunkHolder, long currentTime) { - if (chunkHolder.wasAccessibleSinceLastSave() && chunkHolder.isReadyForSaving()) { - ChunkAccess ichunkaccess = chunkHolder.getLatestChunk(); - - if (!(ichunkaccess instanceof ImposterProtoChunk) && !(ichunkaccess instanceof LevelChunk)) { - return false; +- } else if (!ichunkaccess.isUnsaved()) { +- return false; - } else { -- long i = ichunkaccess.getPos().toLong(); -- long j = this.chunkSaveCooldowns.getOrDefault(i, -1L); -- long k = System.currentTimeMillis(); +- long j = ichunkaccess.getPos().toLong(); +- long k = this.nextChunkSaveTime.getOrDefault(j, -1L); - -- if (k < j) { +- if (currentTime < k) { - return false; - } else { - boolean flag = this.save(ichunkaccess); - - chunkHolder.refreshAccessibility(); - if (flag) { -- this.chunkSaveCooldowns.put(i, k + 10000L); +- this.nextChunkSaveTime.put(j, currentTime + 10000L); - } - - return flag; @@ -23807,10 +23837,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean save(ChunkAccess chunk) { - this.poiManager.flush(chunk.getPos()); -- if (!chunk.isUnsaved()) { +- if (!chunk.tryMarkSaved()) { - return false; - } else { -- chunk.setUnsaved(false); - ChunkPos chunkcoordintpair = chunk.getPos(); - - try { @@ -23826,11 +23855,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - } - -- this.level.getProfiler().incrementCounter("chunkSave"); -- CompoundTag nbttagcompound = ChunkSerializer.write(this.level, chunk); +- Profiler.get().incrementCounter("chunkSave"); +- this.activeChunkWrites.incrementAndGet(); +- SerializableChunkData serializablechunkdata = SerializableChunkData.copyOf(this.level, chunk); - -- this.write(chunkcoordintpair, nbttagcompound).exceptionally((throwable) -> { -- this.level.getServer().reportChunkSaveFailure(throwable, this.storageInfo(), chunkcoordintpair); +- Objects.requireNonNull(serializablechunkdata); +- CompletableFuture completablefuture = CompletableFuture.supplyAsync(serializablechunkdata::write, Util.backgroundExecutor()); +- +- Objects.requireNonNull(completablefuture); +- this.write(chunkcoordintpair, completablefuture::join).handle((ovoid, throwable) -> { +- if (throwable != null) { +- this.level.getServer().reportChunkSaveFailure(throwable, this.storageInfo(), chunkcoordintpair); +- } +- +- this.activeChunkWrites.decrementAndGet(); - return null; - }); - this.markPosition(chunkcoordintpair, chunkstatus.getChunkType()); @@ -23863,7 +23901,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - return false; - } - -- ChunkType chunktype = ChunkSerializer.getChunkTypeFromTag(nbttagcompound); +- ChunkType chunktype = SerializableChunkData.getChunkTypeFromTag(nbttagcompound); - - return this.markPosition(pos, chunktype) == 1; - } @@ -23917,8 +23955,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static void dropChunk(ServerPlayer player, ChunkPos pos) { - player.connection.chunkSender.dropChunk(player, pos); + // Paper - rewrite chunk system - } - ++ } ++ + // Paper start - rewrite chunk system + @Override + public CompletableFuture> read(final ChunkPos pos) { @@ -23954,12 +23992,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + @Override + public void flushWorker() { + ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.flush(); -+ } + } + // Paper end - rewrite chunk system -+ + @Nullable public LevelChunk getChunkToSend(long pos) { - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -24155,7 +24192,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + continue; + } + ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity)tracker).moonrise$clearPlayers(); -+ } + } + } + // Paper end - optimise entity tracker + @@ -24164,7 +24201,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (true) { + this.newTrackerTick(); + return; - } ++ } + // Paper end - optimise entity tracker + // Paper - rewrite chunk system @@ -24322,10 +24359,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8); - private final TickingTracker tickingTicketsTracker = new TickingTracker(); - private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(32); -- final Set chunksToUpdateFutures = Sets.newHashSet(); -- final ChunkTaskPriorityQueueSorter ticketThrottler; -- final ProcessorHandle> ticketThrottlerInput; -- final ProcessorHandle ticketThrottlerReleaser; +- final Set chunksToUpdateFutures = new ReferenceOpenHashSet(); +- final ThrottlingChunkTaskDispatcher ticketDispatcher; - final LongSet ticketsToRelease = new LongOpenHashSet(); - final Executor mainThreadExecutor; + // Paper - rewrite chunk system @@ -24336,13 +24371,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper - rewrite chunk system protected DistanceManager(Executor workerExecutor, Executor mainThreadExecutor) { - Objects.requireNonNull(mainThreadExecutor); - ProcessorHandle mailbox = ProcessorHandle.of("player ticket throttler", mainThreadExecutor::execute); - ChunkTaskPriorityQueueSorter chunktaskqueuesorter = new ChunkTaskPriorityQueueSorter(ImmutableList.of(mailbox), workerExecutor, 4); + TaskScheduler taskscheduler = TaskScheduler.wrapExecutor("player ticket throttler", mainThreadExecutor); -- this.ticketThrottler = chunktaskqueuesorter; -- this.ticketThrottlerInput = chunktaskqueuesorter.getProcessor(mailbox, true); -- this.ticketThrottlerReleaser = chunktaskqueuesorter.getReleaseProcessor(mailbox); +- this.ticketDispatcher = new ThrottlingChunkTaskDispatcher(taskscheduler, workerExecutor, 4); - this.mainThreadExecutor = mainThreadExecutor; + // Paper - rewrite chunk system } @@ -24420,17 +24451,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - - if (!this.chunksToUpdateFutures.isEmpty()) { +- Iterator iterator = this.chunksToUpdateFutures.iterator(); +- +- ChunkHolder playerchunk; +- - // CraftBukkit start - SPIGOT-7780: Call chunk unload events before updateHighestAllowedStatus -- this.chunksToUpdateFutures.forEach((playerchunk) -> { +- while (iterator.hasNext()) { +- playerchunk = (ChunkHolder) iterator.next(); - playerchunk.callEventIfUnloading(chunkLoadingManager); -- }); +- } +- +- iterator = this.chunksToUpdateFutures.iterator(); - // CraftBukkit end -- this.chunksToUpdateFutures.forEach((playerchunk) -> { +- +- while (iterator.hasNext()) { +- playerchunk = (ChunkHolder) iterator.next(); - playerchunk.updateHighestAllowedStatus(chunkLoadingManager); -- }); -- this.chunksToUpdateFutures.forEach((playerchunk) -> { +- } +- +- iterator = this.chunksToUpdateFutures.iterator(); +- +- while (iterator.hasNext()) { +- playerchunk = (ChunkHolder) iterator.next(); - playerchunk.updateFutures(chunkLoadingManager, this.mainThreadExecutor); -- }); +- } +- - this.chunksToUpdateFutures.clear(); - return true; - } else { @@ -24443,18 +24488,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (this.getTickets(j).stream().anyMatch((ticket) -> { - return ticket.getType() == TicketType.PLAYER; - })) { -- ChunkHolder playerchunk = chunkLoadingManager.getUpdatingChunkIfPresent(j); +- ChunkHolder playerchunk1 = chunkLoadingManager.getUpdatingChunkIfPresent(j); - -- if (playerchunk == null) { +- if (playerchunk1 == null) { - throw new IllegalStateException(); - } - -- CompletableFuture> completablefuture = playerchunk.getEntityTickingChunkFuture(); +- CompletableFuture> completablefuture = playerchunk1.getEntityTickingChunkFuture(); - - completablefuture.thenAccept((chunkresult) -> { - this.mainThreadExecutor.execute(() -> { -- this.ticketThrottlerReleaser.tell(ChunkTaskPriorityQueueSorter.release(() -> { -- }, j, false)); +- this.ticketDispatcher.release(j, () -> { +- }, false); - }); - }); - } @@ -24633,8 +24678,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.spawnChunkTracker.hasObjectsNear(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(chunkPos), ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(chunkPos)); // Paper - chunk tick iteration optimisation } + public LongIterator getSpawnCandidateChunks() { +@@ -0,0 +0,0 @@ public abstract class DistanceManager { + } + public String getDebugStatus() { -- return this.ticketThrottler.getDebugStatus(); +- return this.ticketDispatcher.getDebugStatus(); + return "No DistanceManager stats available"; // Paper - rewrite chunk system } @@ -24680,6 +24729,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } + public LongSet getTickingChunks() { +@@ -0,0 +0,0 @@ public abstract class DistanceManager { + } + public void removeTicketsOnClosing() { - ImmutableSet> immutableset = ImmutableSet.of(TicketType.UNKNOWN, TicketType.POST_TELEPORT, TicketType.FUTURE_AWAIT); // Paper - add additional tickets to preserve - ObjectIterator>>> objectiterator = this.tickets.long2ObjectEntrySet().fastIterator(); @@ -24779,10 +24832,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - private final AtomicReferenceArray>> futures = new AtomicReferenceArray<>(CHUNK_STATUSES.size()); - private final AtomicReference task = new AtomicReference<>(); - private final AtomicInteger generationRefCount = new AtomicInteger(); +- private volatile CompletableFuture generationSaveSyncFuture = CompletableFuture.completedFuture(null); + // Paper - rewrite chunk system public GenerationChunkHolder(ChunkPos pos) { this.pos = pos; +@@ -0,0 +0,0 @@ public abstract class GenerationChunkHolder { } public CompletableFuture> scheduleChunkGenerationTask(ChunkStatus requestedStatus, ChunkMap chunkLoadingManager) { @@ -24988,21 +25043,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public void increaseGenerationRefCount() { -- this.generationRefCount.incrementAndGet(); -+ throw new UnsupportedOperationException(); // Paper - rewrite chunk system - } + protected abstract void addSaveDependency(CompletableFuture savingFuture); - public void decreaseGenerationRefCount() { -- int i = this.generationRefCount.decrementAndGet(); -- if (i < 0) { -- throw new IllegalStateException("More releases than claims. Count: " + i); + public void increaseGenerationRefCount() { +- if (this.generationRefCount.getAndIncrement() == 0) { +- this.generationSaveSyncFuture = new CompletableFuture<>(); +- this.addSaveDependency(this.generationSaveSyncFuture); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public int getGenerationRefCount() { -- return this.generationRefCount.get(); + public void decreaseGenerationRefCount() { +- CompletableFuture completableFuture = this.generationSaveSyncFuture; +- int i = this.generationRefCount.decrementAndGet(); +- if (i == 0) { +- completableFuture.complete(null); +- } +- +- if (i < 0) { +- throw new IllegalStateException("More releases than claims. Count: " + i); +- } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -25095,15 +25155,15 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/sr index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -0,0 +0,0 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp - import net.minecraft.world.level.storage.DimensionDataStorage; +@@ -0,0 +0,0 @@ import net.minecraft.world.level.storage.DimensionDataStorage; import net.minecraft.world.level.storage.LevelStorageSource; + import org.slf4j.Logger; -public class ServerChunkCache extends ChunkSource { +public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache { // Paper - rewrite chunk system - public static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper - private static final List CHUNK_STATUSES = ChunkStatus.getStatusList(); + private static final Logger LOGGER = LogUtils.getLogger(); + private final DistanceManager distanceManager; @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>(); long chunkFutureAwaitCounter; @@ -25197,18 +25257,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - return ifLoaded; - } - // Paper end - Perf: Optimise getChunkAt calls for loaded chunks -- ProfilerFiller gameprofilerfiller = this.level.getProfiler(); +- ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.incrementCounter("getChunk"); - long k = ChunkPos.asLong(x, z); +- +- for (int l = 0; l < 4; ++l) { +- if (k == this.lastChunkPos[l] && leastStatus == this.lastChunkStatus[l]) { +- ChunkAccess ichunkaccess = this.lastChunk[l]; + // Paper start - rewrite chunk system + if (leastStatus == ChunkStatus.FULL) { + final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z)); -- for (int l = 0; l < 4; ++l) { -- if (k == this.lastChunkPos[l] && leastStatus == this.lastChunkStatus[l]) { -- ChunkAccess ichunkaccess = this.lastChunk[l]; -- - if (ichunkaccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime - return ichunkaccess; - } @@ -25264,15 +25324,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - long k = chunkcoordintpair.toLong(); - int l = ChunkLevel.byStatus(leastStatus); - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k); -+ // Paper start - rewrite chunk system -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.level, chunkX, chunkZ, "Scheduling chunk load off-main"); - +- - // CraftBukkit start - don't add new ticket for currently unloading chunk - boolean currentlyUnloading = false; - if (playerchunk != null) { - FullChunkStatus oldChunkState = ChunkLevel.fullStatus(playerchunk.oldTicketLevel); - FullChunkStatus currentChunkState = ChunkLevel.fullStatus(playerchunk.getTicketLevel()); - currentlyUnloading = (oldChunkState.isOrAfter(FullChunkStatus.FULL) && !currentChunkState.isOrAfter(FullChunkStatus.FULL)); +- } +- if (create && !currentlyUnloading) { +- // CraftBukkit end +- this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair); +- if (this.chunkAbsent(playerchunk, l)) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); +- +- gameprofilerfiller.push("chunkLoad"); +- this.runDistanceManagerUpdates(); +- playerchunk = this.getVisibleChunkIfPresent(k); +- gameprofilerfiller.pop(); +- if (this.chunkAbsent(playerchunk, l)) { +- throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("No chunk holder after ticket has been added")); +- } +- } ++ // Paper start - rewrite chunk system ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.level, chunkX, chunkZ, "Scheduling chunk load off-main"); ++ + final int minLevel = ChunkLevel.byStatus(leastStatus); + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkX, chunkZ); + @@ -25281,19 +25357,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if ((chunkHolder == null || chunkHolder.getTicketLevel() > minLevel || needsFullScheduling) && !create) { + return ChunkHolder.UNLOADED_CHUNK_FUTURE; } -- if (create && !currentlyUnloading) { -- // CraftBukkit end -- this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair); -- if (this.chunkAbsent(playerchunk, l)) { -- ProfilerFiller gameprofilerfiller = this.level.getProfiler(); -- -- gameprofilerfiller.push("chunkLoad"); -- this.runDistanceManagerUpdates(); -- playerchunk = this.getVisibleChunkIfPresent(k); -- gameprofilerfiller.pop(); -- if (this.chunkAbsent(playerchunk, l)) { -- throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("No chunk holder after ticket has been added")); -+ + +- return this.chunkAbsent(playerchunk, l) ? GenerationChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.scheduleChunkGenerationTask(leastStatus, this.chunkMap); +- } + final ChunkAccess ifPresent = chunkHolder == null ? null : chunkHolder.getChunkIfPresent(leastStatus); + if (needsFullScheduling || ifPresent == null) { + // schedule @@ -25303,13 +25369,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ret.complete(ChunkHolder.UNLOADED_CHUNK); + } else { + ret.complete(ChunkResult.of(chunk)); - } -- } -- } ++ } + }; - -- return this.chunkAbsent(playerchunk, l) ? GenerationChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.scheduleChunkGenerationTask(leastStatus, this.chunkMap); -- } ++ + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().scheduleChunkLoad( + chunkX, chunkZ, leastStatus, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHER, @@ -25374,9 +25436,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end public boolean isPositionTicking(long pos) { -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); +- if (!this.level.shouldTickBlocksAt(pos)) { +- return false; +- } else { +- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); - -- return playerchunk == null ? false : (!this.level.shouldTickBlocksAt(pos) ? false : ((ChunkResult) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).isSuccess()); +- return playerchunk == null ? false : ((ChunkResult) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).isSuccess(); +- } + // Paper start - rewrite chunk system + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(pos); + return newChunkHolder != null && newChunkHolder.isTickingReady(); @@ -25396,7 +25462,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - if (save) { - this.save(true); - } -- // CraftBukkit end + // CraftBukkit end ++ // Paper - rewrite chunk system + this.dataStorage.close(); - this.lightEngine.close(); - this.chunkMap.close(); + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.close(save, true); // Paper - rewrite chunk system @@ -25405,11 +25473,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start - modelled on below public void purgeUnload() { + if (true) return; // Paper - rewrite chunk system - this.level.getProfiler().push("purge"); - this.distanceManager.purgeStaleTickets(); - this.runDistanceManagerUpdates(); + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("purge"); @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - this.level.getProfiler().popPush("chunks"); + gameprofilerfiller.popPush("chunks"); if (tickChunks) { this.level.timings.chunks.startTiming(); // Paper - timings + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().tick(); // Paper - rewrite chunk system @@ -25419,102 +25487,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { } - private void tickChunks() { -+ long chunksTicked = 0; // Paper - rewrite chunk system - long i = this.level.getGameTime(); - long j = i - this.lastInhabitedUpdate; - -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - - gameprofilerfiller.push("pollingChunks"); - gameprofilerfiller.push("filteringLoadedChunks"); -- List list = Lists.newArrayListWithCapacity(this.chunkMap.size()); -- Iterator iterator = this.chunkMap.getChunks().iterator(); -- if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper -+ // Paper start - chunk tick iteration optimisations -+ List list; -+ { -+ final ca.spottedleaf.moonrise.common.list.ReferenceList tickingChunks = -+ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel) this.level).moonrise$getTickingChunks(); - -- while (iterator.hasNext()) { -- ChunkHolder playerchunk = (ChunkHolder) iterator.next(); -- LevelChunk chunk = playerchunk.getTickingChunk(); -+ final ServerChunkCache.ChunkAndHolder[] raw = tickingChunks.getRawDataUnchecked(); -+ final int size = tickingChunks.size(); - -- if (chunk != null) { -- list.add(new ServerChunkCache.ChunkAndHolder(chunk, playerchunk)); -+ if (this.iterationCopy == null || this.iterationCopy.length < size) { -+ this.iterationCopy = new ServerChunkCache.ChunkAndHolder[raw.length]; - } -+ System.arraycopy(raw, 0, this.iterationCopy, 0, size); -+ -+ list = it.unimi.dsi.fastutil.objects.ObjectArrayList.wrap( -+ this.iterationCopy, size -+ ); - } -+ // Paper end - chunk tick iteration optimisations -+ Iterator iterator = null; // Paper - chunk tick iteration optimisations -+ if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper -+ -+ // Paper - chunk tick iteration optimisations - - if (this.level.tickRateManager().runsNormally()) { - gameprofilerfiller.popPush("naturalSpawnCount"); -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - LevelChunk chunk1 = chunkproviderserver_a.chunk; - ChunkPos chunkcoordintpair = chunk1.getPos(); - -- if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair)) { -+ if (true && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair)) { // Paper - rewrite chunk system - chunk1.incrementInhabitedTime(j); - if (flag && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair, true)) { // Spigot - NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1); - } - -- if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { -+ if (true) { // Paper - rewrite chunk system - this.level.tickChunk(chunk1, l); -+ // Paper start - rewrite chunk system -+ if ((++chunksTicked & 7L) == 0L) { -+ ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks(); -+ } -+ // Paper end - rewrite chunk system - } - } - } -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - } - - gameprofilerfiller.popPush("broadcast"); -- list.forEach((chunkproviderserver_a1) -> { -- this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing -- chunkproviderserver_a1.holder.broadcastChanges(chunkproviderserver_a1.chunk); -- this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing -- }); -+ // Paper start - chunk tick iteration optimisations -+ this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing -+ { -+ final it.unimi.dsi.fastutil.objects.ObjectArrayList chunks = (it.unimi.dsi.fastutil.objects.ObjectArrayList)list; -+ final ServerChunkCache.ChunkAndHolder[] raw = chunks.elements(); -+ final int size = chunks.size(); -+ -+ Objects.checkFromToIndex(0, size, raw.length); -+ for (int idx = 0; idx < size; ++idx) { -+ final ServerChunkCache.ChunkAndHolder holder = raw[idx]; -+ raw[idx] = null; -+ -+ holder.holder().broadcastChanges(holder.chunk()); -+ } -+ } -+ this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing -+ // Paper end - chunk tick iteration optimisations - gameprofilerfiller.pop(); - gameprofilerfiller.pop(); - } - } - private void getFullChunk(long pos, Consumer chunkConsumer) { - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); - @@ -25594,21 +25566,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import org.bukkit.event.world.TimeSkipEvent; // CraftBukkit end --public class ServerLevel extends Level implements WorldGenLevel { -+public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel, ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader { // Paper - rewrite chunk system +-public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLevel { ++public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLevel, ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel, ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader { // Paper - rewrite chunk system public static final BlockPos END_SPAWN_POINT = new BlockPos(100, 50, 0); public static final IntProvider RAIN_DELAY = UniformInt.of(12000, 180000); -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public final PrimaryLevelData serverLevelData; // CraftBukkit - type private int lastSpawnChunkRadius; - final EntityTickList entityTickList; + final EntityTickList entityTickList = new EntityTickList(); - public final PersistentEntitySectionManager entityManager; + // Paper - rewrite chunk system private final GameEventDispatcher gameEventDispatcher; public boolean noSave; private final SleepStatus sleepStatus; -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public final void loadChunksForMoveAsync(AABB axisalignedbb, ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority, java.util.function.Consumer> onLoad) { @@ -25625,7 +25597,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3; int maxBlockX = Mth.floor(axisalignedbb.maxX + 1.0E-7D) + 3; -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe int minChunkZ = minBlockZ >> 4; int maxChunkZ = maxBlockZ >> 4; @@ -25800,7 +25772,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } } -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe for (int cx = minChunkX; cx <= maxChunkX; ++cx) { for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { @@ -25857,7 +25829,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Add env and gen to constructor, IWorldDataServer -> WorldDataServer public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe DataFixer datafixer = minecraftserver.getFixerUpper(); EntityPersistentStorage entitypersistentstorage = new EntityStorage(new SimpleRegionStorage(new RegionStorageInfo(convertable_conversionsession.getLevelId(), resourcekey, "entities"), convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, DataFixTypes.ENTITY_CHUNK), this, minecraftserver); @@ -25875,7 +25847,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return minecraftserver.overworld().getDataStorage(); }); this.chunkSource.getGeneratorState().ensureStructuresGenerated(); -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.randomSequences = (RandomSequences) Objects.requireNonNullElseGet(randomsequences, () -> { return (RandomSequences) this.getDataStorage().computeIfAbsent(RandomSequences.factory(l), "random_sequences"); }); @@ -25895,16 +25867,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit } -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe gameprofilerfiller.push("checkDespawn"); entity.checkDespawn(); gameprofilerfiller.pop(); -- if (this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { -+ if (true || this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { // Paper - rewrite chunk system +- if (entity instanceof ServerPlayer || this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { ++ if (true) { // Paper - rewrite chunk system Entity entity1 = entity.getVehicle(); if (entity1 != null) { -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } gameprofilerfiller.push("entityManagement"); @@ -25923,7 +25895,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } protected void tickTime() { -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe }); } @@ -25987,7 +25959,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void tickChunk(LevelChunk chunk, int randomTickSpeed) { ChunkPos chunkcoordintpair = chunk.getPos(); boolean flag = this.isRaining(); -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe gameprofilerfiller.popPush("tickBlocks"); timings.chunkTicksBlocks.startTiming(); // Paper if (randomTickSpeed > 0) { @@ -26024,9 +25996,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } timings.chunkTicksBlocks.stopTiming(); // Paper -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe if (fluid1.is(fluid)) { - fluid1.tick(this, pos); + fluid1.tick(this, pos, iblockdata); } + // Paper start - rewrite chunk system + if ((++this.tickedBlocksOrFluids & 7L) != 0L) { @@ -26036,7 +26008,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe if (iblockdata.is(block)) { iblockdata.tick(this, pos, this.random); } @@ -26048,7 +26020,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) { @@ -26060,7 +26032,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ServerChunkCache chunkproviderserver = this.getChunkSource(); if (!savingDisabled) { -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } timings.worldSaveChunks.startTiming(); // Paper @@ -26088,7 +26060,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start - moved from MinecraftServer.saveChunks ServerLevel worldserver1 = this; -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.removePlayerImmediately((ServerPlayer) entity, Entity.RemovalReason.DISCARDED); } @@ -26097,7 +26069,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // CraftBukkit start -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } // CraftBukkit end @@ -26106,7 +26078,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public boolean tryAddFreshEntityWithPassengers(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { // CraftBukkit end @@ -26119,7 +26091,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return false; } else { this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } } @@ -26128,7 +26100,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 bufferedwriter.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size())); bufferedwriter.write(String.format(Locale.ROOT, "block_ticks: %d\n", this.getBlockTicks().count())); bufferedwriter.write(String.format(Locale.ROOT, "fluid_ticks: %d\n", this.getFluidTicks().count())); -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe BufferedWriter bufferedwriter2 = Files.newBufferedWriter(path1); try { @@ -26137,7 +26109,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } catch (Throwable throwable4) { if (bufferedwriter2 != null) { try { -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe BufferedWriter bufferedwriter3 = Files.newBufferedWriter(path2); try { @@ -26146,7 +26118,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } catch (Throwable throwable6) { if (bufferedwriter3 != null) { try { -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @VisibleForTesting public String getWatchdogStats() { @@ -26155,7 +26127,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString(); }), this.blockEntityTickers.size(), ServerLevel.getTypeCount(this.blockEntityTickers, TickingBlockEntity::getType), this.getBlockTicks().count(), this.getFluidTicks().count(), this.gatherChunkSourceStats()); } -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public LevelEntityGetter getEntities() { org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot @@ -26184,7 +26156,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public void startTickingChunk(LevelChunk chunk) { -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public void close() throws IOException { super.close(); @@ -26239,7 +26211,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } @Override -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe CrashReportCategory crashreportsystemdetails = super.fillReportDetails(report); crashreportsystemdetails.setDetail("Loaded entity count", () -> { @@ -26252,7 +26224,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -0,0 +0,0 @@ import org.bukkit.event.player.PlayerToggleSneakEvent; +@@ -0,0 +0,0 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.inventory.MainHand; // CraftBukkit end @@ -26310,11 +26282,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable, ca.spottedleaf.moonrise.patches.starlight.light.StarLightLightingProvider { // Paper - rewrite chunk system public static final int DEFAULT_BATCH_SIZE = 1000; private static final Logger LOGGER = LogUtils.getLogger(); -- private final ProcessorMailbox taskMailbox; +- private final ConsecutiveExecutor consecutiveExecutor; - private final ObjectList> lightTasks = new ObjectArrayList<>(); + // Paper - rewrite chunk sytem private final ChunkMap chunkMap; -- private final ProcessorHandle> sorterMailbox; +- private final ChunkTaskDispatcher taskDispatcher; + // Paper - rewrite chunk sytem private final int taskPerBatch = 1000; - private final AtomicBoolean scheduled = new AtomicBoolean(); @@ -26435,13 +26407,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - rewrite chunk system public ThreadedLevelLightEngine( - LightChunkGetter chunkProvider, -@@ -0,0 +0,0 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl + LightChunkGetter chunkProvider, ChunkMap chunkLoadingManager, boolean hasBlockLight, ConsecutiveExecutor processor, ChunkTaskDispatcher executor ) { super(chunkProvider, true, hasBlockLight); this.chunkMap = chunkLoadingManager; -- this.sorterMailbox = executor; -- this.taskMailbox = processor; +- this.taskDispatcher = executor; +- this.consecutiveExecutor = processor; + // Paper - rewrite chunk sytem } @@ -26475,7 +26446,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - super.queueSectionData(LightLayer.SKY, SectionPos.of(pos, i), null); - } - -- for (int j = this.levelHeightAccessor.getMinSection(); j < this.levelHeightAccessor.getMaxSection(); j++) { +- for (int j = this.levelHeightAccessor.getMinSectionY(); j <= this.levelHeightAccessor.getMaxSectionY(); j++) { - super.updateSectionStatus(SectionPos.of(pos, j), true); - } - }, () -> "updateChunkStatus " + pos + " true")); @@ -26538,12 +26509,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } private void addTask(int x, int z, IntSupplier completedLevelSupplier, ThreadedLevelLightEngine.TaskType stage, Runnable task) { -- this.sorterMailbox.tell(ChunkTaskPriorityQueueSorter.message(() -> { +- this.taskDispatcher.submit(() -> { - this.lightTasks.add(Pair.of(stage, task)); - if (this.lightTasks.size() >= 1000) { - this.runUpdate(); - } -- }, ChunkPos.asLong(x, z), completedLevelSupplier)); +- }, ChunkPos.asLong(x, z), completedLevelSupplier); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -26593,7 +26564,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void tryScheduleUpdate() { - if ((!this.lightTasks.isEmpty() || super.hasLightWork()) && this.scheduled.compareAndSet(false, true)) { -- this.taskMailbox.tell(() -> { +- this.consecutiveExecutor.schedule(() -> { - this.runUpdate(); - this.scheduled.set(false); - }); @@ -26955,8 +26926,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import org.bukkit.plugin.PluginManager; // CraftBukkit end --public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder { -+public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker +-public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder { ++public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker // CraftBukkit start private static final int CURRENT_LEVEL = 2; @@ -27184,13 +27155,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - BlockState iblockdata = this.level().getBlockState(blockposition); + final float reducedWith = this.dimensions.width() * 0.8F; + final AABB box = AABB.ofSize(this.getEyePosition(), reducedWith, 1.0E-6D, reducedWith); -+ -+ if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isEmpty(box)) { -+ return false; -+ } - return !iblockdata.isAir() && iblockdata.isSuffocating(this.level(), blockposition) && Shapes.joinIsNotEmpty(iblockdata.getCollisionShape(this.level(), blockposition).move((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()), Shapes.create(axisalignedbb), BooleanOp.AND); - }); ++ if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isEmpty(box)) { ++ return false; ++ } ++ + final BlockPos.MutableBlockPos tempPos = new BlockPos.MutableBlockPos(); + + final int minX = Mth.floor(box.minX); @@ -27304,7 +27275,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - rewrite chunk system CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit end - final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers + if (this.removalReason == null) { @@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.stopRiding(); } @@ -27312,8 +27283,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.getPassengers().forEach(Entity::stopRiding); + if (this.removalReason != Entity.RemovalReason.UNLOADED_TO_CHUNK) { this.getPassengers().forEach(Entity::stopRiding); } // Paper - rewrite chunk system this.levelCallback.onRemove(entity_removalreason); - // Paper start - Folia schedulers - if (!(this instanceof ServerPlayer) && entity_removalreason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { + this.onRemoval(entity_removalreason); + } @@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @Override @@ -27331,8 +27302,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.world.level.chunk.storage.SectionStorage; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; --public class PoiManager extends SectionStorage { -+public class PoiManager extends SectionStorage implements ca.spottedleaf.moonrise.patches.chunk_system.level.poi.ChunkSystemPoiManager { // Paper - rewrite chunk system +-public class PoiManager extends SectionStorage { ++public class PoiManager extends SectionStorage implements ca.spottedleaf.moonrise.patches.chunk_system.level.poi.ChunkSystemPoiManager { // Paper - rewrite chunk system public static final int MAX_VILLAGE_DISTANCE = 6; public static final int VILLAGE_SECTION_SIZE = 1; private final PoiManager.DistanceTracker distanceTracker; @@ -27454,35 +27425,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.checkConsistencyWithBlocks(SectionPos.of(chunkX, section, chunkZ), sections[section - minY]); + } + } -+ -+ @Override -+ public final void moonrise$close() throws java.io.IOException {} -+ -+ @Override -+ public final net.minecraft.nbt.CompoundTag moonrise$read(final int chunkX, final int chunkZ) throws java.io.IOException { -+ if (!ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.isRegionFileThread()) { -+ return ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.loadData( -+ this.world, chunkX, chunkZ, ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.RegionFileType.POI_DATA, -+ ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.getIOBlockingPriorityForCurrentThread() -+ ); -+ } -+ return this.moonrise$getRegionStorage().read(new ChunkPos(chunkX, chunkZ)); -+ } -+ -+ @Override -+ public final void moonrise$write(final int chunkX, final int chunkZ, final net.minecraft.nbt.CompoundTag data) throws java.io.IOException { -+ if (!ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.isRegionFileThread()) { -+ ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.scheduleSave(this.world, chunkX, chunkZ, data, ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.RegionFileType.POI_DATA); -+ return; -+ } -+ this.moonrise$getRegionStorage().write(new ChunkPos(chunkX, chunkZ), data); -+ } + // Paper end - rewrite chunk system + public PoiManager( RegionStorageInfo storageKey, Path directory, -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage { +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage { world ); this.distanceTracker = new PoiManager.DistanceTracker(); @@ -27490,7 +27438,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public void add(BlockPos pos, Holder type) { -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage { +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage { } public int sectionsToVillage(SectionPos pos) { @@ -27501,7 +27449,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } boolean isVillageCenter(long pos) { -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage { +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage { @Override public void tick(BooleanSupplier shouldKeepTicking) { @@ -27534,7 +27482,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection chunkSection) { -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage { +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage { .map(sectionPos -> Pair.of(sectionPos, this.getOrLoad(sectionPos.asLong()))) .filter(pair -> !pair.getSecond().map(PoiSection::isValid).orElse(false)) .map(pair -> pair.getFirst().chunk()) @@ -27556,9 +27504,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static final Logger LOGGER = LogUtils.getLogger(); private final Short2ObjectMap records = new Short2ObjectOpenHashMap<>(); private final Map, Set> byType = Maps.newHashMap(); -@@ -0,0 +0,0 @@ public class PoiSection { - .orElseGet(Util.prefix("Failed to read POI section: ", LOGGER::error), () -> new PoiSection(updateListener, false, ImmutableList.of())); - } + private final Runnable setDirty; + private boolean isValid; + // Paper start - rewrite chunk system + private final Optional noAllocOptional = Optional.of((PoiSection)(Object)this);; @@ -27727,498 +27674,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // Paper start - Affects Spawning API -diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/Explosion.java -+++ b/src/main/java/net/minecraft/world/level/Explosion.java -@@ -0,0 +0,0 @@ public class Explosion { - // CraftBukkit end - public boolean excludeSourceFromDamage = true; // Paper - Allow explosions to damage source - -+ // Paper start - optimise collisions -+ private static final double[] CACHED_RAYS; -+ static { -+ final it.unimi.dsi.fastutil.doubles.DoubleArrayList rayCoords = new it.unimi.dsi.fastutil.doubles.DoubleArrayList(); -+ -+ for (int x = 0; x <= 15; ++x) { -+ for (int y = 0; y <= 15; ++y) { -+ for (int z = 0; z <= 15; ++z) { -+ if ((x == 0 || x == 15) || (y == 0 || y == 15) || (z == 0 || z == 15)) { -+ double xDir = (double)((float)x / 15.0F * 2.0F - 1.0F); -+ double yDir = (double)((float)y / 15.0F * 2.0F - 1.0F); -+ double zDir = (double)((float)z / 15.0F * 2.0F - 1.0F); -+ -+ double mag = Math.sqrt( -+ xDir * xDir + yDir * yDir + zDir * zDir -+ ); -+ -+ rayCoords.add((xDir / mag) * (double)0.3F); -+ rayCoords.add((yDir / mag) * (double)0.3F); -+ rayCoords.add((zDir / mag) * (double)0.3F); -+ } -+ } -+ } -+ } -+ -+ CACHED_RAYS = rayCoords.toDoubleArray(); -+ } -+ -+ private static final int CHUNK_CACHE_SHIFT = 2; -+ private static final int CHUNK_CACHE_MASK = (1 << CHUNK_CACHE_SHIFT) - 1; -+ private static final int CHUNK_CACHE_WIDTH = 1 << CHUNK_CACHE_SHIFT; -+ -+ private static final int BLOCK_EXPLOSION_CACHE_SHIFT = 3; -+ private static final int BLOCK_EXPLOSION_CACHE_MASK = (1 << BLOCK_EXPLOSION_CACHE_SHIFT) - 1; -+ private static final int BLOCK_EXPLOSION_CACHE_WIDTH = 1 << BLOCK_EXPLOSION_CACHE_SHIFT; -+ -+ // resistance = (res + 0.3F) * 0.3F; -+ // so for resistance = 0, we need res = -0.3F -+ private static final Float ZERO_RESISTANCE = Float.valueOf(-0.3f); -+ private it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap blockCache = null; -+ private long[] chunkPosCache = null; -+ private net.minecraft.world.level.chunk.LevelChunk[] chunkCache = null; -+ private ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache getOrCacheExplosionBlock(final int x, final int y, final int z, -+ final long key, final boolean calculateResistance) { -+ ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache ret = this.blockCache.get(key); -+ if (ret != null) { -+ return ret; -+ } -+ -+ BlockPos pos = new BlockPos(x, y, z); -+ -+ if (!this.level.isInWorldBounds(pos)) { -+ ret = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache(key, pos, null, null, 0.0f, true); -+ } else { -+ net.minecraft.world.level.chunk.LevelChunk chunk; -+ long chunkKey = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x >> 4, z >> 4); -+ int chunkCacheKey = ((x >> 4) & CHUNK_CACHE_MASK) | (((z >> 4) << CHUNK_CACHE_SHIFT) & (CHUNK_CACHE_MASK << CHUNK_CACHE_SHIFT)); -+ if (this.chunkPosCache[chunkCacheKey] == chunkKey) { -+ chunk = this.chunkCache[chunkCacheKey]; -+ } else { -+ this.chunkPosCache[chunkCacheKey] = chunkKey; -+ this.chunkCache[chunkCacheKey] = chunk = this.level.getChunk(x >> 4, z >> 4); -+ } -+ -+ BlockState blockState = ((ca.spottedleaf.moonrise.patches.chunk_getblock.GetBlockChunk)chunk).moonrise$getBlock(x, y, z); -+ FluidState fluidState = blockState.getFluidState(); -+ -+ Optional resistance = !calculateResistance ? Optional.empty() : this.damageCalculator.getBlockExplosionResistance((Explosion)(Object)this, this.level, pos, blockState, fluidState); -+ -+ ret = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache( -+ key, pos, blockState, fluidState, -+ (resistance.orElse(ZERO_RESISTANCE).floatValue() + 0.3f) * 0.3f, -+ false -+ ); -+ } -+ -+ this.blockCache.put(key, ret); -+ -+ return ret; -+ } -+ -+ private boolean clipsAnything(final Vec3 from, final Vec3 to, -+ final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.LazyEntityCollisionContext context, -+ final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[] blockCache, -+ final BlockPos.MutableBlockPos currPos) { -+ // assume that context.delegated = false -+ final double adjX = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON * (from.x - to.x); -+ final double adjY = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON * (from.y - to.y); -+ final double adjZ = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON * (from.z - to.z); -+ -+ if (adjX == 0.0 && adjY == 0.0 && adjZ == 0.0) { -+ return false; -+ } -+ -+ final double toXAdj = to.x - adjX; -+ final double toYAdj = to.y - adjY; -+ final double toZAdj = to.z - adjZ; -+ final double fromXAdj = from.x + adjX; -+ final double fromYAdj = from.y + adjY; -+ final double fromZAdj = from.z + adjZ; -+ -+ int currX = Mth.floor(fromXAdj); -+ int currY = Mth.floor(fromYAdj); -+ int currZ = Mth.floor(fromZAdj); -+ -+ final double diffX = toXAdj - fromXAdj; -+ final double diffY = toYAdj - fromYAdj; -+ final double diffZ = toZAdj - fromZAdj; -+ -+ final double dxDouble = Math.signum(diffX); -+ final double dyDouble = Math.signum(diffY); -+ final double dzDouble = Math.signum(diffZ); -+ -+ final int dx = (int)dxDouble; -+ final int dy = (int)dyDouble; -+ final int dz = (int)dzDouble; -+ -+ final double normalizedDiffX = diffX == 0.0 ? Double.MAX_VALUE : dxDouble / diffX; -+ final double normalizedDiffY = diffY == 0.0 ? Double.MAX_VALUE : dyDouble / diffY; -+ final double normalizedDiffZ = diffZ == 0.0 ? Double.MAX_VALUE : dzDouble / diffZ; -+ -+ double normalizedCurrX = normalizedDiffX * (diffX > 0.0 ? (1.0 - Mth.frac(fromXAdj)) : Mth.frac(fromXAdj)); -+ double normalizedCurrY = normalizedDiffY * (diffY > 0.0 ? (1.0 - Mth.frac(fromYAdj)) : Mth.frac(fromYAdj)); -+ double normalizedCurrZ = normalizedDiffZ * (diffZ > 0.0 ? (1.0 - Mth.frac(fromZAdj)) : Mth.frac(fromZAdj)); -+ -+ for (;;) { -+ currPos.set(currX, currY, currZ); -+ -+ // ClipContext.Block.COLLIDER -> BlockBehaviour.BlockStateBase::getCollisionShape -+ // ClipContext.Fluid.NONE -> ignore fluids -+ -+ // read block from cache -+ final long key = BlockPos.asLong(currX, currY, currZ); -+ -+ final int cacheKey = -+ (currX & BLOCK_EXPLOSION_CACHE_MASK) | -+ (currY & BLOCK_EXPLOSION_CACHE_MASK) << (BLOCK_EXPLOSION_CACHE_SHIFT) | -+ (currZ & BLOCK_EXPLOSION_CACHE_MASK) << (BLOCK_EXPLOSION_CACHE_SHIFT + BLOCK_EXPLOSION_CACHE_SHIFT); -+ ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache cachedBlock = blockCache[cacheKey]; -+ if (cachedBlock == null || cachedBlock.key != key) { -+ blockCache[cacheKey] = cachedBlock = this.getOrCacheExplosionBlock(currX, currY, currZ, key, false); -+ } -+ -+ final BlockState blockState = cachedBlock.blockState; -+ if (blockState != null && !((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)blockState).moonrise$emptyCollisionShape()) { -+ net.minecraft.world.phys.shapes.VoxelShape collision = cachedBlock.cachedCollisionShape; -+ if (collision == null) { -+ collision = ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)blockState).moonrise$getConstantCollisionShape(); -+ if (collision == null) { -+ collision = blockState.getCollisionShape(this.level, currPos, context); -+ if (!context.isDelegated()) { -+ // if it was not delegated during this call, assume that for any future ones it will not be delegated -+ // again, and cache the result -+ cachedBlock.cachedCollisionShape = collision; -+ } -+ } else { -+ cachedBlock.cachedCollisionShape = collision; -+ } -+ } -+ -+ if (!collision.isEmpty() && collision.clip(from, to, currPos) != null) { -+ return true; -+ } -+ } -+ -+ if (normalizedCurrX > 1.0 && normalizedCurrY > 1.0 && normalizedCurrZ > 1.0) { -+ return false; -+ } -+ -+ // inc the smallest normalized coordinate -+ -+ if (normalizedCurrX < normalizedCurrY) { -+ if (normalizedCurrX < normalizedCurrZ) { -+ currX += dx; -+ normalizedCurrX += normalizedDiffX; -+ } else { -+ // x < y && x >= z <--> z < y && z <= x -+ currZ += dz; -+ normalizedCurrZ += normalizedDiffZ; -+ } -+ } else if (normalizedCurrY < normalizedCurrZ) { -+ // y <= x && y < z -+ currY += dy; -+ normalizedCurrY += normalizedDiffY; -+ } else { -+ // y <= x && z <= y <--> z <= y && z <= x -+ currZ += dz; -+ normalizedCurrZ += normalizedDiffZ; -+ } -+ } -+ } -+ -+ private float getSeenFraction(final Vec3 source, final Entity target, -+ final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[] blockCache, -+ final BlockPos.MutableBlockPos blockPos) { -+ final AABB boundingBox = target.getBoundingBox(); -+ final double diffX = boundingBox.maxX - boundingBox.minX; -+ final double diffY = boundingBox.maxY - boundingBox.minY; -+ final double diffZ = boundingBox.maxZ - boundingBox.minZ; -+ -+ final double incX = 1.0 / (diffX * 2.0 + 1.0); -+ final double incY = 1.0 / (diffY * 2.0 + 1.0); -+ final double incZ = 1.0 / (diffZ * 2.0 + 1.0); -+ -+ if (incX < 0.0 || incY < 0.0 || incZ < 0.0) { -+ return 0.0f; -+ } -+ -+ final double offX = (1.0 - Math.floor(1.0 / incX) * incX) * 0.5 + boundingBox.minX; -+ final double offY = boundingBox.minY; -+ final double offZ = (1.0 - Math.floor(1.0 / incZ) * incZ) * 0.5 + boundingBox.minZ; -+ -+ final ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.LazyEntityCollisionContext context = new ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.LazyEntityCollisionContext(target); -+ -+ int totalRays = 0; -+ int missedRays = 0; -+ -+ for (double dx = 0.0; dx <= 1.0; dx += incX) { -+ final double fromX = Math.fma(dx, diffX, offX); -+ for (double dy = 0.0; dy <= 1.0; dy += incY) { -+ final double fromY = Math.fma(dy, diffY, offY); -+ for (double dz = 0.0; dz <= 1.0; dz += incZ) { -+ ++totalRays; -+ -+ final Vec3 from = new Vec3( -+ fromX, -+ fromY, -+ Math.fma(dz, diffZ, offZ) -+ ); -+ -+ if (!this.clipsAnything(from, source, context, blockCache, blockPos)) { -+ ++missedRays; -+ } -+ } -+ } -+ } -+ -+ return (float)missedRays / (float)totalRays; -+ } -+ // Paper end - optimise collisions -+ - public static DamageSource getDefaultDamageSource(Level world, @Nullable Entity source) { - return world.damageSources().explosion(source, Explosion.getIndirectSourceEntityInternal(source)); - } -@@ -0,0 +0,0 @@ public class Explosion { - } - // CraftBukkit end - this.level.gameEvent(this.source, (Holder) GameEvent.EXPLODE, new Vec3(this.x, this.y, this.z)); -- Set set = Sets.newHashSet(); -+ -+ // Paper start - collision optimisations -+ this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>(); -+ -+ this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH]; -+ java.util.Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS); -+ -+ this.chunkCache = new net.minecraft.world.level.chunk.LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH]; -+ -+ final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[] blockCache = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH]; -+ -+ // use initial cache value that is most likely to be used: the source position -+ final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache initialCache; -+ { -+ final int blockX = Mth.floor(this.x); -+ final int blockY = Mth.floor(this.y); -+ final int blockZ = Mth.floor(this.z); -+ -+ final long key = BlockPos.asLong(blockX, blockY, blockZ); -+ -+ initialCache = this.getOrCacheExplosionBlock(blockX, blockY, blockZ, key, true); -+ } -+ // Paper end - collision optimisations -+ - boolean flag = true; - - int i; - int j; - -- for (int k = 0; k < 16; ++k) { -- for (i = 0; i < 16; ++i) { -- for (j = 0; j < 16; ++j) { -- if (k == 0 || k == 15 || i == 0 || i == 15 || j == 0 || j == 15) { -- double d0 = (double) ((float) k / 15.0F * 2.0F - 1.0F); -- double d1 = (double) ((float) i / 15.0F * 2.0F - 1.0F); -- double d2 = (double) ((float) j / 15.0F * 2.0F - 1.0F); -- double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2); -- -- d0 /= d3; -- d1 /= d3; -- d2 /= d3; -- float f = this.radius * (0.7F + this.level.random.nextFloat() * 0.6F); -- double d4 = this.x; -- double d5 = this.y; -- double d6 = this.z; -- -- for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) { -- BlockPos blockposition = BlockPos.containing(d4, d5, d6); -- BlockState iblockdata = this.level.getBlockState(blockposition); -- if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed -- FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions -- -- if (!this.level.isInWorldBounds(blockposition)) { -- break; -+ // Paper start - collision optimisations -+ for (int ray = 0, len = CACHED_RAYS.length; ray < len;) { -+ ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache cachedBlock = initialCache; -+ -+ double currX = this.x; -+ double currY = this.y; -+ double currZ = this.z; -+ -+ final double incX = CACHED_RAYS[ray]; -+ final double incY = CACHED_RAYS[ray + 1]; -+ final double incZ = CACHED_RAYS[ray + 2]; -+ -+ ray += 3; -+ float power = this.radius * (0.7F + this.level.random.nextFloat() * 0.6F); -+ do { -+ final int blockX = Mth.floor(currX); -+ final int blockY = Mth.floor(currY); -+ final int blockZ = Mth.floor(currZ); -+ -+ final long key = BlockPos.asLong(blockX, blockY, blockZ); -+ -+ if (cachedBlock.key != key) { -+ final int cacheKey = -+ (blockX & BLOCK_EXPLOSION_CACHE_MASK) | -+ (blockY & BLOCK_EXPLOSION_CACHE_MASK) << (BLOCK_EXPLOSION_CACHE_SHIFT) | -+ (blockZ & BLOCK_EXPLOSION_CACHE_MASK) << (BLOCK_EXPLOSION_CACHE_SHIFT + BLOCK_EXPLOSION_CACHE_SHIFT); -+ cachedBlock = blockCache[cacheKey]; -+ if (cachedBlock == null || cachedBlock.key != key) { -+ blockCache[cacheKey] = cachedBlock = this.getOrCacheExplosionBlock(blockX, blockY, blockZ, key, true); -+ } - } - -- Optional optional = this.damageCalculator.getBlockExplosionResistance(this, this.level, blockposition, iblockdata, fluid); -- -- if (optional.isPresent()) { -- f -= ((Float) optional.get() + 0.3F) * 0.3F; -+ if (cachedBlock.outOfWorld) { -+ break; - } -- -- if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockposition, iblockdata, f)) { -- set.add(blockposition); -- // Paper start - prevent headless pistons from forming -- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == Blocks.MOVING_PISTON) { -- net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(blockposition); -- if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) { -- net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING); -- set.add(blockposition.relative(direction.getOpposite())); -+ // Paper end - collision optimisations -+ BlockState iblockdata = cachedBlock.blockState; // Paper - optimise collisions -+ // Paper - collision optimisations -+ -+ // Paper start - collision optimisations -+ power -= cachedBlock.resistance; -+ -+ if (power > 0.0f && cachedBlock.shouldExplode == null && iblockdata.isDestroyable()) { // Paper - Protect Bedrock and End Portal/Frames from being destroyed -+ // note: we expect shouldBlockExplode to be pure with respect to power, as Vanilla currently is. -+ // basically, it is unused, which allows us to cache the result -+ final boolean shouldExplode = this.damageCalculator.shouldBlockExplode((Explosion)(Object)this, this.level, cachedBlock.immutablePos, cachedBlock.blockState, power); -+ cachedBlock.shouldExplode = shouldExplode ? Boolean.TRUE : Boolean.FALSE; -+ if (shouldExplode) { -+ if (this.fire || !cachedBlock.blockState.isAir()) { -+ this.toBlow.add(cachedBlock.immutablePos); -+ // Paper start - prevent headless pistons from forming -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == Blocks.MOVING_PISTON) { -+ net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(cachedBlock.immutablePos); // Paper - optimise collisions -+ if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) { -+ net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING); -+ this.toBlow.add(cachedBlock.immutablePos.relative(direction.getOpposite())); // Paper - optimise collisions -+ } -+ } -+ // Paper end - prevent headless pistons from forming - } - } -- // Paper end - prevent headless pistons from forming - } - -- d4 += d0 * 0.30000001192092896D; -- d5 += d1 * 0.30000001192092896D; -- d6 += d2 * 0.30000001192092896D; -- } -+ power -= 0.22500001F; -+ currX += incX; -+ currY += incY; -+ currZ += incZ; -+ } while (power > 0.0f); -+ // Paper end - collision optimisations - } -- } -- } -- } - -- this.toBlow.addAll(set); -+ // Paper - optimise collisions - float f2 = this.radius * 2.0F; - - i = Mth.floor(this.x - (double) f2 - 1.0D); -@@ -0,0 +0,0 @@ public class Explosion { - Vec3 vec3d = new Vec3(this.x, this.y, this.z); - Iterator iterator = list.iterator(); - -+ // Paper start - optimise collisions -+ final BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(); -+ // Paper end - optimise collisions -+ - while (iterator.hasNext()) { - Entity entity = (Entity) iterator.next(); - -@@ -0,0 +0,0 @@ public class Explosion { - d8 /= d11; - d9 /= d11; - d10 /= d11; -+ final double seenFraction; // Paper - optimise collisions - if (this.damageCalculator.shouldDamageEntity(this, entity)) { - // CraftBukkit start - -@@ -0,0 +0,0 @@ public class Explosion { - - entity.lastDamageCancelled = false; - -+ seenFraction = (double)this.getBlockDensity(vec3d, entity, blockCache, blockPos); // Paper - optimise collisions -+ - if (entity instanceof EnderDragon) { - for (EnderDragonPart entityComplexPart : ((EnderDragon) entity).subEntities) { - // Calculate damage separately for each EntityComplexPart -@@ -0,0 +0,0 @@ public class Explosion { - } - } - } else { -- entity.hurt(this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity)); -+ // Paper start - optimise collisions -+ // inline getEntityDamageAmount so that we can avoid double calling getSeenPercent, which is the MOST -+ // expensive part of this loop!!!! -+ final double factor = (1.0 - d7) * seenFraction; -+ entity.hurt(this.damageSource, (float)((factor * factor + factor) / 2.0 * 7.0 * (double)f2 + 1.0)); -+ // Paper end - optimise collisions - } - - if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled - continue; - } - // CraftBukkit end -- } -+ } else { seenFraction = (double)this.getBlockDensity(vec3d, entity, blockCache, blockPos); } // Paper - optimise collisions - -- double d12 = (1.0D - d7) * this.getBlockDensity(vec3d, entity) * (double) this.damageCalculator.getKnockbackMultiplier(entity); // Paper - Optimize explosions -+ double d12 = (1.0D - d7) * seenFraction * (double) this.damageCalculator.getKnockbackMultiplier(entity); // Paper - Optimize explosions // Paper - optimise collisions - double d13; - - if (entity instanceof LivingEntity) { -@@ -0,0 +0,0 @@ public class Explosion { - } - } - } -- -+ // Paper start - optimise collisions -+ this.blockCache = null; -+ this.chunkPosCache = null; -+ this.chunkCache = null; -+ // Paper end - optimise collisions - } - - public void finalizeExplosion(boolean particles) { -@@ -0,0 +0,0 @@ public class Explosion { - private BlockInteraction() {} - } - // Paper start - Optimize explosions -- private float getBlockDensity(Vec3 vec3d, Entity entity) { -+ private float getBlockDensity(Vec3 vec3d, Entity entity, ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[] blockCache, BlockPos.MutableBlockPos blockPos) { // Paper - optimise collisions - if (!this.level.paperConfig().environment.optimizeExplosions) { -- return getSeenPercent(vec3d, entity); -+ return this.getSeenFraction(vec3d, entity, blockCache, blockPos); // Paper - optimise collisions - } - CacheKey key = new CacheKey(this, entity.getBoundingBox()); - Float blockDensity = this.level.explosionDensityCache.get(key); - if (blockDensity == null) { -- blockDensity = getSeenPercent(vec3d, entity); -+ blockDensity = this.getSeenFraction(vec3d, entity, blockCache, blockPos); // Paper - optimise collisions - this.level.explosionDensityCache.put(key, blockDensity); - } - diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/Level.java @@ -28721,7 +28176,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - optimise random ticking + - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator) { // Paper - create paper world config + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator) { // Paper - create paper world config this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @@ -28798,23 +28253,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void setBlockEntity(BlockEntity blockEntity) { @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - @Override - public List getEntities(@Nullable Entity except, AABB box, Predicate predicate) { - this.getProfiler().incrementCounter("getEntities"); -- List list = Lists.newArrayList(); -+ // Paper start - rewrite chunk system -+ final List ret = new java.util.ArrayList<>(); + Profiler.get().incrementCounter("getEntities"); + List list = Lists.newArrayList(); - this.getEntities().get(box, (entity1) -> { - if (entity1 != except && predicate.test(entity1)) { - list.add(entity1); - } -+ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(except, box, ret, predicate); ++ // Paper start - rewrite chunk system ++ final List ret = new java.util.ArrayList<>(); - if (entity1 instanceof EnderDragon) { - EnderDragonPart[] aentitycomplexpart = ((EnderDragon) entity1).getSubEntities(); - int i = aentitycomplexpart.length; -- ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(except, box, ret, predicate); + - for (int j = 0; j < i; ++j) { - EnderDragonPart entitycomplexpart = aentitycomplexpart[j]; - @@ -28836,17 +28289,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - public void getEntities(EntityTypeTest filter, AABB box, Predicate predicate, List result, int limit) { -+ // Paper start - rewrite chunk system -+ public void getEntities(final EntityTypeTest entityTypeTest, -+ final AABB boundingBox, final Predicate predicate, -+ final List into, final int maxCount) { - this.getProfiler().incrementCounter("getEntities"); +- Profiler.get().incrementCounter("getEntities"); - this.getEntities().get(filter, box, (entity) -> { - if (predicate.test(entity)) { - result.add(entity); - if (result.size() >= limit) { - return AbortableIterationConsumer.Continuation.ABORT; - } ++ // Paper start - rewrite chunk system ++ public void getEntities(final EntityTypeTest entityTypeTest, ++ final AABB boundingBox, final Predicate predicate, ++ final List into, final int maxCount) { ++ this.getProfiler().incrementCounter("getEntities"); + + if (entityTypeTest instanceof net.minecraft.world.entity.EntityType byType) { + if (maxCount != Integer.MAX_VALUE) { @@ -28961,14 +28415,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public final class Biome { @Deprecated - public float getTemperature(BlockPos blockPos) { + public float getTemperature(BlockPos blockPos, int seaLevel) { - long l = blockPos.asLong(); - Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = this.temperatureCache.get(); - float f = long2FloatLinkedOpenHashMap.get(l); - if (!Float.isNaN(f)) { - return f; - } else { -- float g = this.getHeightAdjustedTemperature(blockPos); +- float g = this.getHeightAdjustedTemperature(blockPos, seaLevel); - if (long2FloatLinkedOpenHashMap.size() == 1024) { - long2FloatLinkedOpenHashMap.removeFirstFloat(); - } @@ -28976,7 +28430,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - long2FloatLinkedOpenHashMap.put(l, g); - return g; - } -+ return this.getHeightAdjustedTemperature(blockPos); // Paper - optimise random ticking ++ return this.getHeightAdjustedTemperature(blockPos, seaLevel); // Paper - optimise random ticking } public boolean shouldFreeze(LevelReader world, BlockPos blockPos) { @@ -29004,11 +28458,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - public abstract static class BlockStateBase extends StateHolder { + public abstract static class BlockStateBase extends StateHolder implements ca.spottedleaf.moonrise.patches.starlight.blockstate.StarlightAbstractBlockState, ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState { // Paper - rewrite chunk system // Paper - optimise collisions - private final int lightEmission; - private final boolean useShapeForLightOcclusion; + private static final Direction[] DIRECTIONS = Direction.values(); + private static final VoxelShape[] EMPTY_OCCLUSION_SHAPES = (VoxelShape[]) Util.make(new VoxelShape[BlockBehaviour.BlockStateBase.DIRECTIONS.length], (avoxelshape) -> { @@ -0,0 +0,0 @@ public abstract class BlockBehaviour implements FeatureElement { - private FluidState fluidState; - private boolean isRandomlyTicking; + private boolean propagatesSkylightDown; + private int lightBlock; + // Paper start - rewrite chunk system + private int opacityIfCached; @@ -29084,9 +28538,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super(block, propertyMap, codec); this.fluidState = Fluids.EMPTY.defaultFluidState(); @@ -0,0 +0,0 @@ public abstract class BlockBehaviour implements FeatureElement { - this.shapeExceedsCube = this.cache == null || this.cache.largeCollisionShape; // Paper - moved from actual method to here - this.legacySolid = this.calculateSolid(); + this.propagatesSkylightDown = ((Block) this.owner).propagatesSkylightDown(this.asState()); + this.lightBlock = ((Block) this.owner).getLightBlock(this.asState()); + // Paper start - rewrite chunk system + this.isConditionallyFullOpaque = this.canOcclude & this.useShapeForLightOcclusion; + this.opacityIfCached = this.cache == null || this.isConditionallyFullOpaque ? -1 : this.cache.lightBlock; @@ -29131,16 +28585,16 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/sr index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java +++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java -@@ -0,0 +0,0 @@ import net.minecraft.world.ticks.SerializableTickContainer; +@@ -0,0 +0,0 @@ import net.minecraft.world.ticks.SavedTick; import net.minecraft.world.ticks.TickContainerAccess; import org.slf4j.Logger; --public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiomeSource, LightChunk, StructureAccess { -+public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiomeSource, LightChunk, StructureAccess, ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk { // Paper - rewrite chunk system +-public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, LightChunk, StructureAccess { ++public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, LightChunk, StructureAccess, ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk { // Paper - rewrite chunk system public static final int NO_FILLED_SECTION = -1; private static final Logger LOGGER = LogUtils.getLogger(); -@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom +@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh @Nullable protected BlendingData blendingData; public final Map heightmaps = Maps.newEnumMap(Heightmap.Types.class); @@ -29149,7 +28603,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private final Map structureStarts = Maps.newHashMap(); private final Map structuresRefences = Maps.newHashMap(); protected final Map pendingBlockEntities = Maps.newHashMap(); -@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom +@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(ChunkAccess.DATA_TYPE_REGISTRY); // CraftBukkit end @@ -29207,7 +28661,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public ChunkAccess(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor heightLimitView, Registry biomeRegistry, long inhabitedTime, @Nullable LevelChunkSection[] sectionArray, @Nullable BlendingData blendingData) { this.locX = pos.x; this.locZ = pos.z; // Paper - reduce need for field lookups this.chunkPos = pos; this.coordinateKey = ChunkPos.asLong(locX, locZ); // Paper - cache long key -@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom +@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh this.inhabitedTime = inhabitedTime; this.postProcessing = new ShortList[heightLimitView.getSectionsCount()]; this.blendingData = blendingData; @@ -29216,7 +28670,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (sectionArray != null) { if (this.sections.length == sectionArray.length) { System.arraycopy(sectionArray, 0, this.sections, 0, this.sections.length); -@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom +@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh ChunkAccess.replaceMissingSections(biomeRegistry, this.sections); // CraftBukkit start this.biomeRegistry = biomeRegistry; @@ -29233,12 +28687,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public final Registry biomeRegistry; // CraftBukkit end -@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom +@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh @Override public Holder getNoiseBiome(int biomeX, int biomeY, int biomeZ) { - try { -- int l = QuartPos.fromBlock(this.getMinBuildHeight()); +- int l = QuartPos.fromBlock(this.getMinY()); - int i1 = l + QuartPos.fromBlock(this.getHeight()) - 1; - int j1 = Mth.clamp(biomeY, l, i1); - int k1 = this.getSectionIndex(QuartPos.toBlock(j1)); @@ -29271,7 +28725,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // CraftBukkit start -@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom +@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh } public void initializeLightSources() { @@ -29285,20 +28739,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return null; // Paper - rewrite chunk system } - public static record TicksToSave(SerializableTickContainer blocks, SerializableTickContainer fluids) { + public static record PackedTicks(List> blocks, List> fluids) { diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java @@ -0,0 +0,0 @@ public abstract class ChunkGenerator { - return CompletableFuture.supplyAsync(Util.wrapThreadWithTaskName("init_biomes", () -> { + return CompletableFuture.supplyAsync(() -> { chunk.fillBiomesFromNoise(this.biomeSource, noiseConfig.sampler()); return chunk; -- }), Util.backgroundExecutor()); -+ }), Runnable::run); // Paper - rewrite chunk system +- }, Util.backgroundExecutor().forName("init_biomes")); ++ }, Runnable::run); // Paper - rewrite chunk system } - public abstract void applyCarvers(WorldGenRegion chunkRegion, long seed, RandomState noiseConfig, BiomeManager biomeAccess, StructureManager structureAccessor, ChunkAccess chunk, GenerationStep.Carving carverStep); + public abstract void applyCarvers(WorldGenRegion chunkRegion, long seed, RandomState noiseConfig, BiomeManager biomeAccess, StructureManager structureAccessor, ChunkAccess chunk); @@ -0,0 +0,0 @@ public abstract class ChunkGenerator { return Pair.of(placement.getLocatePos(pos), holder); } @@ -29499,7 +28953,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.skyLightSources = protoChunk.skyLightSources; + // Paper - rewrite chunk system this.setLightCorrect(protoChunk.isLightCorrect()); - this.unsaved = true; + this.markUnsaved(); this.needsDecoration = true; // CraftBukkit // CraftBukkit start this.persistentDataContainer = protoChunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading. @@ -29512,9 +28966,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - rewrite chunk system } - @Override + public void setUnsavedListener(LevelChunk.UnsavedListener unsavedListener) { @@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess { - ProfilerFiller gameprofilerfiller = this.level.getProfiler(); + ProfilerFiller gameprofilerfiller = Profiler.get(); gameprofilerfiller.push("updateSkyLightSources"); - this.skyLightSources.update(this, j, i, l); @@ -29613,8 +29067,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static final int SECTION_WIDTH = 16; public static final int SECTION_HEIGHT = 16; @@ -0,0 +0,0 @@ public class LevelChunkSection { - // CraftBukkit start - read/write - private PalettedContainer> biomes; + public final PalettedContainer states; + private PalettedContainer> biomes; // CraftBukkit - read/write + // Paper start - block counting + private static final it.unimi.dsi.fastutil.ints.IntArrayList FULL_LIST = new it.unimi.dsi.fastutil.ints.IntArrayList(16*16*16); @@ -29638,9 +29092,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - block counting + - public LevelChunkSection(PalettedContainer datapaletteblock, PalettedContainer> palettedcontainerro) { - // CraftBukkit end - this.states = datapaletteblock; + private LevelChunkSection(LevelChunkSection section) { + this.nonEmptyBlockCount = section.nonEmptyBlockCount; + this.tickingBlockCount = section.tickingBlockCount; @@ -0,0 +0,0 @@ public class LevelChunkSection { ++this.tickingFluidCount; } @@ -29788,7 +29242,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ProtoChunk extends ChunkAccess { } - if (LightEngine.hasDifferentLightProperties(this, pos, blockState, state)) { + if (LightEngine.hasDifferentLightProperties(blockState, state)) { - this.skyLightSources.update(this, m, j, o); + // Paper - rewrite chunk system this.lightEngine.checkBlock(pos); @@ -29894,7 +29348,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java +++ b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java @@ -0,0 +0,0 @@ public class ChunkStatusTasks { - chunk1 = ((ImposterProtoChunk) protochunk).getWrapped(); + chunk1 = protochunkextension.getWrapped(); } else { chunk1 = new LevelChunk(worldserver, protochunk, ($) -> { // Paper - decompile fix - ChunkStatusTasks.postLoadProtoChunk(worldserver, protochunk.getEntities()); @@ -29903,14 +29357,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 generationchunkholder.replaceProtoChunk(new ImposterProtoChunk(chunk1, false)); } @@ -0,0 +0,0 @@ public class ChunkStatusTasks { - }); + }, context.mainThreadExecutor()); } -- private static void postLoadProtoChunk(ServerLevel world, List entities) { -+ public static void postLoadProtoChunk(ServerLevel world, List entities, ChunkPos pos) { // Paper - public, add ChunkPos param +- public static void postLoadProtoChunk(ServerLevel world, List entities) { // Paper - public ++ public static void postLoadProtoChunk(ServerLevel world, List entities, ChunkPos pos) { // Paper - public // Paper - rewrite chunk system - add ChunkPos param if (!entities.isEmpty()) { // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities - world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entities, world).filter((entity) -> { + world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entities, world, EntitySpawnReason.LOAD).filter((entity) -> { @@ -0,0 +0,0 @@ public class ChunkStatusTasks { } checkDupeUUID(world, entity); // Paper - duplicate uuid resolving @@ -30035,126 +29489,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static class Builder { private final ChunkStatus status; @Nullable -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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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 -@@ -0,0 +0,0 @@ public class ChunkSerializer { - achunksection[k] = chunksection; - SectionPos sectionposition = SectionPos.of(chunkPos, b0); - -- poiStorage.checkConsistencyWithBlocks(sectionposition, chunksection); -+ // Paper - rewrite chunk system - moved to final load stage - } - - boolean flag3 = nbttagcompound1.contains("BlockLight", 7); -@@ -0,0 +0,0 @@ public class ChunkSerializer { - } - } - -+ ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.loadLightHook(world, chunkPos, nbt, (ChunkAccess)object1); // Paper - rewrite chunk system - note: it's ok to pass the raw value instead of wrapped -+ - if (chunktype == ChunkType.LEVELCHUNK) { - return new ImposterProtoChunk((LevelChunk) object1, false); - } else { -@@ -0,0 +0,0 @@ public class ChunkSerializer { - } - // CraftBukkit end - -+ // Paper start - async chunk saving -+ // must be called sync -+ public static ca.spottedleaf.moonrise.patches.chunk_system.async_save.AsyncChunkSaveData getAsyncSaveData(ServerLevel world, ChunkAccess chunk) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(world, chunk.locX, chunk.locZ, "Preparing async chunk save data"); -+ -+ final CompoundTag tickLists = new CompoundTag(); -+ ChunkSerializer.saveTicks(world, tickLists, chunk.getTicksForSerialization()); -+ -+ ListTag blockEntitiesSerialized = new ListTag(); -+ for (final BlockPos blockPos : chunk.getBlockEntitiesPos()) { -+ final CompoundTag blockEntityNbt = chunk.getBlockEntityNbtForSaving(blockPos, world.registryAccess()); -+ if (blockEntityNbt != null) { -+ blockEntitiesSerialized.add(blockEntityNbt); -+ } -+ } -+ -+ return new ca.spottedleaf.moonrise.patches.chunk_system.async_save.AsyncChunkSaveData( -+ tickLists.get(BLOCK_TICKS_TAG), -+ tickLists.get(FLUID_TICKS_TAG), -+ blockEntitiesSerialized, -+ world.getGameTime() -+ ); -+ } -+ // Paper end - async chunk saving -+ - public static CompoundTag write(ServerLevel world, ChunkAccess chunk) { -+ // Paper start - async chunk saving -+ return saveChunk(world, chunk, null); -+ } -+ public static CompoundTag saveChunk(ServerLevel world, ChunkAccess chunk, ca.spottedleaf.moonrise.patches.chunk_system.async_save.AsyncChunkSaveData asyncsavedata) { -+ // Paper end - async chunk saving - ChunkPos chunkcoordintpair = chunk.getPos(); - CompoundTag nbttagcompound = NbtUtils.addCurrentDataVersion(new CompoundTag()); - - nbttagcompound.putInt("xPos", chunkcoordintpair.x); - nbttagcompound.putInt("yPos", chunk.getMinSection()); - nbttagcompound.putInt("zPos", chunkcoordintpair.z); -- nbttagcompound.putLong("LastUpdate", world.getGameTime()); -+ nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime() : world.getGameTime()); // Paper - async chunk saving - nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime()); - nbttagcompound.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(chunk.getPersistedStatus()).toString()); - BlendingData blendingdata = chunk.getBlendingData(); -@@ -0,0 +0,0 @@ public class ChunkSerializer { - nbttagcompound.putBoolean("isLightOn", true); - } - -- ListTag nbttaglist1 = new ListTag(); -- Iterator iterator = chunk.getBlockEntitiesPos().iterator(); -+ // Paper start - async chunk saving -+ ListTag nbttaglist1; -+ Iterator iterator; -+ if (asyncsavedata != null) { -+ nbttaglist1 = asyncsavedata.blockEntities(); -+ iterator = java.util.Collections.emptyIterator(); -+ } else { -+ nbttaglist1 = new ListTag(); -+ iterator = chunk.getBlockEntitiesPos().iterator(); -+ } -+ // Paper end - async chunk saving - - CompoundTag nbttagcompound2; - -@@ -0,0 +0,0 @@ public class ChunkSerializer { - nbttagcompound.put("CarvingMasks", nbttagcompound2); - } - -+ // Paper start -+ if (asyncsavedata != null) { -+ nbttagcompound.put(BLOCK_TICKS_TAG, asyncsavedata.blockTickList()); -+ nbttagcompound.put(FLUID_TICKS_TAG, asyncsavedata.fluidTickList()); -+ } else { - ChunkSerializer.saveTicks(world, nbttagcompound, chunk.getTicksForSerialization()); -+ } -+ // Paper end - nbttagcompound.put("PostProcessing", ChunkSerializer.packOffsets(chunk.getPostProcessing())); - CompoundTag nbttagcompound3 = new CompoundTag(); - Iterator iterator1 = chunk.getHeightmaps().iterator(); -@@ -0,0 +0,0 @@ public class ChunkSerializer { - nbttagcompound.put("ChunkBukkitValues", chunk.persistentDataContainer.toTagCompound()); - } - // CraftBukkit end -+ ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.saveLightHook(world, chunk, nbttagcompound); // Paper - rewrite chunk system - return nbttagcompound; - } - -@@ -0,0 +0,0 @@ public class ChunkSerializer { - - return nbttaglist == null && nbttaglist1 == null ? null : (chunk) -> { - if (nbttaglist != null) { -- world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(nbttaglist, world)); -+ world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(nbttaglist, world), chunk.getPos()); // Paper - rewrite chunk system - } - - if (nbttaglist1 != null) { 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java @@ -30219,12 +29553,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - rewrite chunk system } - public CompletableFuture write(ChunkPos chunkPos, CompoundTag nbt) { + public CompletableFuture write(ChunkPos chunkPos, Supplier nbtSupplier) { @@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable { - } - // Paper end - guard against serializing mismatching coordinates + }; + // Paper end - guard against possible chunk pos desync this.handleLegacyStructureIndex(chunkPos); -- return this.worker.store(chunkPos, nbt); +- return this.worker.store(chunkPos, guardedPosCheck); // Paper - guard against possible chunk pos desync + // Paper start - rewrite chunk system + try { + this.storage.write(chunkPos, nbt); @@ -30307,10 +29641,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class IOWorker implements ChunkScanAccess, AutoCloseable { private static final Logger LOGGER = LogUtils.getLogger(); private final AtomicBoolean shutdownRequested = new AtomicBoolean(); - private final ProcessorMailbox mailbox; + private final PriorityConsecutiveExecutor consecutiveExecutor; - private final RegionFileStorage storage; + public final RegionFileStorage storage; // Paper - public - private final Map pendingWrites = Maps.newLinkedHashMap(); + private final SequencedMap pendingWrites = new LinkedHashMap<>(); private final Long2ObjectLinkedOpenHashMap> regionCacheForBlender = new Long2ObjectLinkedOpenHashMap<>(); private static final int REGION_CACHE_SIZE = 1024; diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -30545,18 +29879,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.world.level.LevelHeightAccessor; import org.slf4j.Logger; --public class SectionStorage implements AutoCloseable { -+public abstract class SectionStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.level.storage.ChunkSystemSectionStorage { // Paper - rewrite chunk system - private static final Logger LOGGER = LogUtils.getLogger(); +-public class SectionStorage implements AutoCloseable { ++public class SectionStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.level.storage.ChunkSystemSectionStorage { // Paper - rewrite chunk system + static final Logger LOGGER = LogUtils.getLogger(); private static final String SECTIONS_TAG = "Sections"; - private final SimpleRegionStorage simpleRegionStorage; + // Paper - rewrite chunk system private final Long2ObjectMap> storage = new Long2ObjectOpenHashMap<>(); - private final LongLinkedOpenHashSet dirty = new LongLinkedOpenHashSet(); - private final Function> codec; -@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { - private final ChunkIOErrorReporter errorReporter; - protected final LevelHeightAccessor levelHeightAccessor; + private final LongLinkedOpenHashSet dirtyChunks = new LongLinkedOpenHashSet(); + private final Codec

codec; +@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { + private final Long2ObjectMap>>> pendingLoads = new Long2ObjectOpenHashMap<>(); + private final Object loadLock = new Object(); + // Paper start - rewrite chunk system + private final RegionFileStorage regionStorage; @@ -30565,19 +29899,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public final RegionFileStorage moonrise$getRegionStorage() { + return this.regionStorage; + } ++ ++ @Override ++ public void moonrise$close() throws IOException {} + // Paper end - rewrite chunk system + public SectionStorage( SimpleRegionStorage storageAccess, - Function> codecFactory, -@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { + Codec

codec, +@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { ChunkIOErrorReporter errorHandler, LevelHeightAccessor world ) { - this.simpleRegionStorage = storageAccess; + // Paper - rewrite chunk system - this.codec = codecFactory; - this.factory = factory; + this.codec = codec; + this.packer = serializer; + this.unpacker = deserializer; +@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { this.registryAccess = registryManager; this.errorReporter = errorHandler; this.levelHeightAccessor = world; @@ -30585,51 +29924,47 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } protected void tick(BooleanSupplier shouldKeepTicking) { -@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { +@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { } - private CompletableFuture> tryRead(ChunkPos pos) { -- return this.simpleRegionStorage.read(pos).exceptionally(throwable -> { -- if (throwable instanceof IOException iOException) { -- LOGGER.error("Error reading chunk {} data from disk", pos, iOException); -- this.errorReporter.reportChunkLoadFailure(iOException, this.simpleRegionStorage.storageInfo(), pos); -- return Optional.empty(); -- } else { -- throw new CompletionException(throwable); -- } -- }); -+ // Paper start - rewrite chunk system -+ try { -+ return CompletableFuture.completedFuture(Optional.ofNullable(this.moonrise$read(pos.x, pos.z))); -+ } catch (final Throwable thr) { -+ return CompletableFuture.failedFuture(thr); -+ } -+ // Paper end - rewrite chunk system + private CompletableFuture>> tryRead(ChunkPos chunkPos) { +- RegistryOps registryOps = this.registryAccess.createSerializationContext(NbtOps.INSTANCE); +- return this.simpleRegionStorage +- .read(chunkPos) +- .thenApplyAsync( +- chunkNbt -> chunkNbt.map( +- nbt -> SectionStorage.PackedChunk.parse(this.codec, registryOps, nbt, this.simpleRegionStorage, this.levelHeightAccessor) +- ), +- Util.backgroundExecutor().forName("parseSection") +- ) +- .exceptionally(throwable -> { +- if (throwable instanceof IOException iOException) { +- LOGGER.error("Error reading chunk {} data from disk", chunkPos, iOException); +- this.errorReporter.reportChunkLoadFailure(iOException, this.simpleRegionStorage.storageInfo(), chunkPos); +- return Optional.empty(); +- } else { +- throw new CompletionException(throwable); +- } +- }); ++ throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName()); // Paper - rewrite chunk system } - private void readColumn(ChunkPos pos, RegistryOps ops, @Nullable CompoundTag nbt) { -- if (nbt == null) { -- for (int i = this.levelHeightAccessor.getMinSection(); i < this.levelHeightAccessor.getMaxSection(); i++) { -- this.storage.put(getKey(pos, i), Optional.empty()); + private void unpackChunk(ChunkPos chunkPos, @Nullable SectionStorage.PackedChunk

result) { +- if (result == null) { +- for (int i = this.levelHeightAccessor.getMinSectionY(); i <= this.levelHeightAccessor.getMaxSectionY(); i++) { +- this.storage.put(getKey(chunkPos, i), Optional.empty()); - } - } else { -- Dynamic dynamic = new Dynamic<>(ops, nbt); -- int j = getVersion(dynamic); -- int k = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); -- boolean bl = j != k; -- Dynamic dynamic2 = this.simpleRegionStorage.upgradeChunkTag(dynamic, j); -- OptionalDynamic optionalDynamic = dynamic2.get("Sections"); +- boolean bl = result.versionChanged(); - -- for (int l = this.levelHeightAccessor.getMinSection(); l < this.levelHeightAccessor.getMaxSection(); l++) { -- long m = getKey(pos, l); -- Optional optional = optionalDynamic.get(Integer.toString(l)) -- .result() -- .flatMap(dynamicx -> this.codec.apply(() -> this.setDirty(m)).parse(dynamicx).resultOrPartial(LOGGER::error)); -- this.storage.put(m, optional); -- optional.ifPresent(sections -> { -- this.onSectionLoad(m); +- for (int j = this.levelHeightAccessor.getMinSectionY(); j <= this.levelHeightAccessor.getMaxSectionY(); j++) { +- long l = getKey(chunkPos, j); +- Optional optional = Optional.ofNullable(result.sectionsByY.get(j)).map(section -> this.unpacker.apply((P)section, () -> this.setDirty(l))); +- this.storage.put(l, optional); +- optional.ifPresent(object -> { +- this.onSectionLoad(l); - if (bl) { -- this.setDirty(m); +- this.setDirty(l); - } - }); - } @@ -30637,26 +29972,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new IllegalStateException("Only chunk system can load in state, offending class:" + this.getClass().getName()); // Paper - rewrite chunk system } - private void writeColumn(ChunkPos pos) { -@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { - Dynamic dynamic = this.writeColumn(pos, registryOps); - Tag tag = dynamic.getValue(); - if (tag instanceof CompoundTag) { + private void writeChunk(ChunkPos pos) { +- RegistryOps registryOps = this.registryAccess.createSerializationContext(NbtOps.INSTANCE); +- Dynamic dynamic = this.writeChunk(pos, registryOps); +- Tag tag = dynamic.getValue(); +- if (tag instanceof CompoundTag) { - this.simpleRegionStorage.write(pos, (CompoundTag)tag).exceptionally(throwable -> { - this.errorReporter.reportChunkSaveFailure(throwable, this.simpleRegionStorage.storageInfo(), pos); - return null; - }); -+ // Paper start - rewrite chunk system -+ try { -+ this.moonrise$write(pos.x, pos.z, (net.minecraft.nbt.CompoundTag)tag); -+ } catch (final IOException ex) { -+ LOGGER.error("Error writing poi chunk data to disk for chunk " + pos, ex); -+ } -+ // Paper end - rewrite chunk system - } else { - LOGGER.error("Expected compound tag, got {}", tag); - } -@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { +- } else { +- LOGGER.error("Expected compound tag, got {}", tag); +- } ++ throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName()); // Paper - rewrite chunk system + } + + private Dynamic writeChunk(ChunkPos chunkPos, DynamicOps ops) { +@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { protected void onSectionLoad(long pos) { } @@ -30664,15 +29996,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void setDirty(long pos) { // Paper - public Optional optional = this.storage.get(pos); if (optional != null && !optional.isEmpty()) { - this.dirty.add(pos); -@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { + this.dirtyChunks.add(ChunkPos.asLong(SectionPos.x(pos), SectionPos.z(pos))); +@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { @Override public void close() throws IOException { - this.simpleRegionStorage.close(); + this.moonrise$close(); // Paper - rewrite chunk system } - } + + static record PackedChunk(Int2ObjectMap sectionsByY, boolean versionChanged) { diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java @@ -30763,11 +30096,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java +++ b/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java @@ -0,0 +0,0 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { - return CompletableFuture.supplyAsync(Util.wrapThreadWithTaskName("init_biomes", () -> { + return CompletableFuture.supplyAsync(() -> { this.doCreateBiomes(blender, noiseConfig, structureAccessor, chunk); return chunk; -- }), Util.backgroundExecutor()); -+ }), Runnable::run); // Paper - rewrite chunk system +- }, Util.backgroundExecutor().forName("init_biomes")); ++ }, Runnable::run); // Paper - rewrite chunk system } private void doCreateBiomes(Blender blender, RandomState noiseConfig, StructureManager structureAccessor, ChunkAccess chunk) { @@ -30775,8 +30108,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } return ichunkaccess1; -- }), Util.backgroundExecutor()); -+ }), Runnable::run); // Paper - rewrite chunk system +- }, Util.backgroundExecutor().forName("wgen_fill_noise")); ++ }, Runnable::run); // Paper - rewrite chunk system } private ChunkAccess doFill(Blender blender, StructureManager structureAccessor, RandomState noiseConfig, ChunkAccess chunk, int minimumCellY, int cellHeight) { @@ -30863,8 +30196,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.world.level.chunk.LightChunkGetter; -public class LevelLightEngine implements LightEventListener { -+public class LevelLightEngine implements LightEventListener, ca.spottedleaf.moonrise.patches.starlight.light.StarLightLightingProvider { ++public class LevelLightEngine implements LightEventListener, ca.spottedleaf.moonrise.patches.starlight.light.StarLightLightingProvider { // Paper - rewrite chunk system public static final int LIGHT_SECTION_PADDING = 1; + public static final LevelLightEngine EMPTY = new LevelLightEngine(); protected final LevelHeightAccessor levelHeightAccessor; - @Nullable - private final LightEngine blockEngine; @@ -30908,6 +30242,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - rewrite chunk system } + private LevelLightEngine() { + this.levelHeightAccessor = LevelHeightAccessor.create(0, 0); +- this.blockEngine = null; +- this.skyEngine = null; ++ // Paper start - rewrite chunk system ++ this.lightEngine = new ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface(null, false, false, (LevelLightEngine)(Object)this); ++ // Paper end - rewrite chunk system + } + @Override public void checkBlock(BlockPos pos) { - if (this.blockEngine != null) { @@ -31043,10 +30386,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.lightEngine.getRawBrightness(pos, ambientDarkness); // Paper - rewrite chunk system } - public boolean lightOnInSection(SectionPos sectionPos) { -- long l = sectionPos.asLong(); + public boolean lightOnInColumn(long sectionPos) { - return this.blockEngine == null -- || this.blockEngine.storage.lightOnInSection(l) && (this.skyEngine == null || this.skyEngine.storage.lightOnInSection(l)); +- || this.blockEngine.storage.lightOnInColumn(sectionPos) && (this.skyEngine == null || this.skyEngine.storage.lightOnInColumn(sectionPos)); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system // Paper - not implemented on server } @@ -31063,7 +30405,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static Direction getDirection( // Paper - optimise collisions - public AABB box, Vec3 intersectingVector, double[] traceDistanceResult, @Nullable Direction approachDirection, double deltaX, double deltaY, double deltaZ ) { - if (deltaX > 1.0E-7) { + return getDirection( diff --git a/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java @@ -31451,7 +30793,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - DoubleArrayList.wrap(new double[]{minX, maxX}), - DoubleArrayList.wrap(new double[]{minY, maxY}), - DoubleArrayList.wrap(new double[]{minZ, maxZ}) -- ); ++ minX == 0.0 && maxX == 1.0 ? ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minX, maxX }), ++ minY == 0.0 && maxY == 1.0 ? ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minY, maxY }), ++ minZ == 0.0 && maxZ == 1.0 ? ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minZ, maxZ }) + ); - } else if (i == 0 && j == 0 && k == 0) { - return block(); - } else { @@ -31468,10 +30813,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - (int)Math.round(maxX * (double)l), - (int)Math.round(maxY * (double)m), - (int)Math.round(maxZ * (double)n) -+ minX == 0.0 && maxX == 1.0 ? ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minX, maxX }), -+ minY == 0.0 && maxY == 1.0 ? ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minY, maxY }), -+ minZ == 0.0 && maxZ == 1.0 ? ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minZ, maxZ }) - ); +- ); - return new CubeVoxelShape(bitSetDiscreteVoxelShape); } } else { @@ -31646,45 +30988,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - optimise collisions } - public static VoxelShape getFaceShape(VoxelShape shape, Direction direction) { -- if (shape == block()) { -- return block(); -- } else { -- Direction.Axis axis = direction.getAxis(); -- boolean bl; -- int i; -- if (direction.getAxisDirection() == Direction.AxisDirection.POSITIVE) { -- bl = DoubleMath.fuzzyEquals(shape.max(axis), 1.0, 1.0E-7); -- i = shape.shape.getSize(axis) - 1; -- } else { -- bl = DoubleMath.fuzzyEquals(shape.min(axis), 0.0, 1.0E-7); -- i = 0; -- } -+ return ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)shape).moonrise$getFaceShapeClamped(direction); // Paper - optimise collisions -+ } - -- return (VoxelShape)(!bl ? empty() : new SliceShape(shape, axis, i)); -- } -+ // Paper start - optimise collisions -+ private static boolean mergedMayOccludeBlock(final VoxelShape shape1, final VoxelShape shape2) { -+ // if the combined bounds of the two shapes cannot occlude, then neither can the merged -+ final AABB bounds1 = shape1.bounds(); -+ final AABB bounds2 = shape2.bounds(); -+ -+ final double minX = Math.min(bounds1.minX, bounds2.minX); -+ final double minY = Math.min(bounds1.minY, bounds2.minY); -+ final double minZ = Math.min(bounds1.minZ, bounds2.minZ); -+ -+ final double maxX = Math.max(bounds1.maxX, bounds2.maxX); -+ final double maxY = Math.max(bounds1.maxY, bounds2.maxY); -+ final double maxZ = Math.max(bounds1.maxZ, bounds2.maxZ); -+ -+ return (minX <= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON && maxX >= (1 - ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) && -+ (minY <= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON && maxY >= (1 - ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) && -+ (minZ <= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON && maxZ >= (1 - ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)); - } -+ // Paper end - optimise collisions - - public static boolean mergedFaceOccludes(VoxelShape one, VoxelShape two, Direction direction) { - if (one != block() && two != block()) { - Direction.Axis axis = direction.getAxis(); @@ -31695,18 +30998,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - voxelShape = empty(); - } + // Paper start - optimise collisions -+ public static boolean mergedFaceOccludes(final VoxelShape first, final VoxelShape second, final Direction direction) { -+ // see if any of the shapes on their own occludes, only if cached -+ if (((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$occludesFullBlockIfCached() || ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$occludesFullBlockIfCached()) { -+ return true; -+ } ++ private static boolean mergedMayOccludeBlock(final VoxelShape shape1, final VoxelShape shape2) { ++ // if the combined bounds of the two shapes cannot occlude, then neither can the merged ++ final AABB bounds1 = shape1.bounds(); ++ final AABB bounds2 = shape2.bounds(); - if (!DoubleMath.fuzzyEquals(voxelShape2.min(axis), 0.0, 1.0E-7)) { - voxelShape2 = empty(); - } -+ if (first.isEmpty() & second.isEmpty()) { -+ return false; -+ } ++ final double minX = Math.min(bounds1.minX, bounds2.minX); ++ final double minY = Math.min(bounds1.minY, bounds2.minY); ++ final double minZ = Math.min(bounds1.minZ, bounds2.minZ); - return !joinIsNotEmpty( - block(), @@ -31714,6 +31016,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - BooleanOp.ONLY_FIRST - ); - } else { ++ final double maxX = Math.max(bounds1.maxX, bounds2.maxX); ++ final double maxY = Math.max(bounds1.maxY, bounds2.maxY); ++ final double maxZ = Math.max(bounds1.maxZ, bounds2.maxZ); ++ ++ return (minX <= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON && maxX >= (1 - ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) && ++ (minY <= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON && maxY >= (1 - ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) && ++ (minZ <= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON && maxZ >= (1 - ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)); ++ } ++ // Paper end - optimise collisions ++ ++ // Paper start - optimise collisions ++ public static boolean mergedFaceOccludes(final VoxelShape first, final VoxelShape second, final Direction direction) { ++ // see if any of the shapes on their own occludes, only if cached ++ if (((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$occludesFullBlockIfCached() || ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$occludesFullBlockIfCached()) { ++ return true; ++ } ++ ++ if (first.isEmpty() & second.isEmpty()) { ++ return false; ++ } ++ + // we optimise getOpposite, so we can use it + // secondly, use our cache to retrieve sliced shape + final VoxelShape newFirst = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$getFaceShapeClamped(direction); @@ -32319,6 +31642,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.isEmpty; // Paper - optimise collisions } + public VoxelShape move(Vec3 vec3d) { +@@ -0,0 +0,0 @@ public abstract class VoxelShape { + } + public VoxelShape move(double x, double y, double z) { - return (VoxelShape)(this.isEmpty() - ? Shapes.empty() @@ -32473,7 +31800,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.findIndex(Direction.Axis.Y, vec32.y - (double)pos.getY()), - this.findIndex(Direction.Axis.Z, vec32.z - (double)pos.getZ()) - ) -- ? new BlockHitResult(vec32, Direction.getNearest(vec3.x, vec3.y, vec3.z).getOpposite(), pos, true) +- ? new BlockHitResult(vec32, Direction.getApproximateNearest(vec3.x, vec3.y, vec3.z).getOpposite(), pos, true) - : AABB.clip(this.toAabbs(), start, end, pos); + } + @@ -32545,7 +31872,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public VoxelShape getFaceShape(Direction facing) { @@ -0,0 +0,0 @@ public abstract class VoxelShape { - } + && DoubleMath.fuzzyEquals(doubleList.getDouble(1), 1.0, 1.0E-7); } - public double collide(Direction.Axis axis, AABB box, double maxDist) { @@ -32560,22 +31887,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + switch (axis) { + case X: { -+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.collideX((VoxelShape)(Object)this, source, source_move); ++ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.collideX((VoxelShape) (Object) this, source, source_move); + } + case Y: { -+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.collideY((VoxelShape)(Object)this, source, source_move); ++ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.collideY((VoxelShape) (Object) this, source, source_move); + } + case Z: { -+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.collideZ((VoxelShape)(Object)this, source, source_move); ++ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.collideZ((VoxelShape) (Object) this, source, source_move); + } + default: { + throw new RuntimeException("Unknown axis: " + axis); + } + } -+ // Paper end - optimise collisions } ++ // Paper end - optimise collisions protected double collideX(AxisCycle axisCycle, AABB box, double maxDist) { + if (this.isEmpty()) { diff --git a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java @@ -32648,13 +31976,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } @@ -0,0 +0,0 @@ public class LevelChunkTicks implements SerializableTickContainer, TickCon + } - @Override - public ListTag save(long l, Function function) { -+ this.lastSaved = l; // Paper - rewrite chunk system + public ListTag save(long time, Function typeToNameFunction) { ++ this.lastSaved = time; // Paper - rewrite chunk system ListTag listTag = new ListTag(); - if (this.pendingTicks != null) { - for (SavedTick savedTick : this.pendingTicks) { + + for (SavedTick savedTick : this.pack(time)) { @@ -0,0 +0,0 @@ public class LevelChunkTicks implements SerializableTickContainer, TickCon public void unpack(long time) { @@ -32706,7 +32034,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - entityManager.ensureChunkQueuedForLoad(pair); // Start entity loading - - // SPIGOT-6772: Use entity mailbox and re-schedule entities if they get unloaded -- ProcessorMailbox mailbox = ((EntityStorage) entityManager.permanentStorage).entityDeserializerQueue; +- ConsecutiveExecutor mailbox = ((EntityStorage) entityManager.permanentStorage).entityDeserializerQueue; - BooleanSupplier supplier = () -> { - // only execute inbox if our entities are not present - if (entityManager.areEntitiesLoaded(pair)) { @@ -32942,6 +32270,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - rewrite chunk system // Paper end } + diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/AsyncCatcher.java diff --git a/patches/server/Revert-Custom-table-implementation-for-blockstate-st.patch b/patches/server/Revert-Custom-table-implementation-for-blockstate-st.patch deleted file mode 100644 index bab62f109f..0000000000 --- a/patches/server/Revert-Custom-table-implementation-for-blockstate-st.patch +++ /dev/null @@ -1,345 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 21 Oct 2024 12:52:44 -0700 -Subject: [PATCH] Revert "Custom table implementation for blockstate state - lookups" - -This reverts commit 14a7e6521ba0ce6dc8ebf98a1ccce59a5ec6a194. - -TODO Replace via deleting the patch - -diff --git a/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java b/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java -deleted file mode 100644 -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- a/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java -+++ /dev/null -@@ -0,0 +0,0 @@ --package io.papermc.paper.util.table; -- --import com.google.common.collect.Table; --import net.minecraft.world.level.block.state.StateHolder; --import net.minecraft.world.level.block.state.properties.Property; --import java.util.Collection; --import java.util.HashSet; --import java.util.Map; --import java.util.Set; -- --public final class ZeroCollidingReferenceStateTable { -- -- // upper 32 bits: starting index -- // lower 32 bits: bitset for contained ids -- protected final long[] this_index_table; -- protected final Comparable[] this_table; -- protected final StateHolder this_state; -- -- protected long[] index_table; -- protected StateHolder[][] value_table; -- -- public ZeroCollidingReferenceStateTable(final StateHolder state, final Map, Comparable> this_map) { -- this.this_state = state; -- this.this_index_table = this.create_table(this_map.keySet()); -- -- int max_id = -1; -- for (final Property property : this_map.keySet()) { -- final int id = lookup_vindex(property, this.this_index_table); -- if (id > max_id) { -- max_id = id; -- } -- } -- -- this.this_table = new Comparable[max_id + 1]; -- for (final Map.Entry, Comparable> entry : this_map.entrySet()) { -- this.this_table[lookup_vindex(entry.getKey(), this.this_index_table)] = entry.getValue(); -- } -- } -- -- public void loadInTable(final Table, Comparable, StateHolder> table, -- final Map, Comparable> this_map) { -- final Set> combined = new HashSet<>(table.rowKeySet()); -- combined.addAll(this_map.keySet()); -- -- this.index_table = this.create_table(combined); -- -- int max_id = -1; -- for (final Property property : combined) { -- final int id = lookup_vindex(property, this.index_table); -- if (id > max_id) { -- max_id = id; -- } -- } -- -- this.value_table = new StateHolder[max_id + 1][]; -- -- final Map, Map, StateHolder>> map = table.rowMap(); -- for (final Property property : map.keySet()) { -- final Map, StateHolder> propertyMap = map.get(property); -- -- final int id = lookup_vindex(property, this.index_table); -- final StateHolder[] states = this.value_table[id] = new StateHolder[property.getPossibleValues().size()]; -- -- for (final Map.Entry, StateHolder> entry : propertyMap.entrySet()) { -- if (entry.getValue() == null) { -- // TODO what -- continue; -- } -- -- states[((Property)property).getIdFor(entry.getKey())] = entry.getValue(); -- } -- } -- -- -- for (final Map.Entry, Comparable> entry : this_map.entrySet()) { -- final Property property = entry.getKey(); -- final int index = lookup_vindex(property, this.index_table); -- -- if (this.value_table[index] == null) { -- this.value_table[index] = new StateHolder[property.getPossibleValues().size()]; -- } -- -- this.value_table[index][((Property)property).getIdFor(entry.getValue())] = this.this_state; -- } -- } -- -- -- protected long[] create_table(final Collection> collection) { -- int max_id = -1; -- for (final Property property : collection) { -- final int id = property.getId(); -- if (id > max_id) { -- max_id = id; -- } -- } -- -- final long[] ret = new long[((max_id + 1) + 31) >>> 5]; // ceil((max_id + 1) / 32) -- -- for (final Property property : collection) { -- final int id = property.getId(); -- -- ret[id >>> 5] |= (1L << (id & 31)); -- } -- -- int total = 0; -- for (int i = 1, len = ret.length; i < len; ++i) { -- ret[i] |= (long)(total += Long.bitCount(ret[i - 1] & 0xFFFFFFFFL)) << 32; -- } -- -- return ret; -- } -- -- public Comparable get(final Property state) { -- final Comparable[] table = this.this_table; -- final int index = lookup_vindex(state, this.this_index_table); -- -- if (index < 0 || index >= table.length) { -- return null; -- } -- return table[index]; -- } -- -- public StateHolder get(final Property property, final Comparable with) { -- final int withId = ((Property)property).getIdFor(with); -- if (withId < 0) { -- return null; -- } -- -- final int index = lookup_vindex(property, this.index_table); -- final StateHolder[][] table = this.value_table; -- if (index < 0 || index >= table.length) { -- return null; -- } -- -- final StateHolder[] values = table[index]; -- -- if (withId >= values.length) { -- return null; -- } -- -- return values[withId]; -- } -- -- protected static int lookup_vindex(final Property property, final long[] index_table) { -- final int id = property.getId(); -- final long bitset_mask = (1L << (id & 31)); -- final long lower_mask = bitset_mask - 1; -- final int index = id >>> 5; -- if (index >= index_table.length) { -- return -1; -- } -- final long index_value = index_table[index]; -- final long contains_check = ((index_value & bitset_mask) - 1) >> (Long.SIZE - 1); // -1L if doesn't contain -- -- // index = total bits set in lower table values (upper 32 bits of index_value) plus total bits set in lower indices below id -- // contains_check is 0 if the bitset had id set, else it's -1: so index is unaffected if contains_check == 0, -- // otherwise it comes out as -1. -- return (int)(((index_value >>> 32) + Long.bitCount(index_value & lower_mask)) | contains_check); -- } --} -diff --git a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java -+++ b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java -@@ -0,0 +0,0 @@ public abstract class StateHolder { - private final Reference2ObjectArrayMap, Comparable> values; - private Table, Comparable, S> neighbours; - protected final MapCodec propertiesCodec; -- protected final io.papermc.paper.util.table.ZeroCollidingReferenceStateTable optimisedTable; // Paper - optimise state lookup - - protected StateHolder(O owner, Reference2ObjectArrayMap, Comparable> propertyMap, MapCodec codec) { - this.owner = owner; - this.values = propertyMap; - this.propertiesCodec = codec; -- this.optimisedTable = new io.papermc.paper.util.table.ZeroCollidingReferenceStateTable(this, propertyMap); // Paper - optimise state lookup - } - - public > S cycle(Property property) { -@@ -0,0 +0,0 @@ public abstract class StateHolder { - } - - public > boolean hasProperty(Property property) { -- return this.optimisedTable.get(property) != null; // Paper - optimise state lookup -+ return this.values.containsKey(property); - } - - public > T getValue(Property property) { -- Comparable comparable = this.optimisedTable.get(property); // Paper - optimise state lookup -+ Comparable comparable = this.values.get(property); - if (comparable == null) { - throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner); - } else { -@@ -0,0 +0,0 @@ public abstract class StateHolder { - } - - public > Optional getOptionalValue(Property property) { -- Comparable comparable = this.optimisedTable.get(property); // Paper - optimise state lookup -+ Comparable comparable = this.values.get(property); - return comparable == null ? Optional.empty() : Optional.of(property.getValueClass().cast(comparable)); - } - - public , V extends T> S setValue(Property property, V value) { -- // Paper start - optimise state lookup -- final S ret = (S)this.optimisedTable.get(property, value); -- if (ret == null) { -- throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value"); -+ Comparable comparable = this.values.get(property); -+ if (comparable == null) { -+ throw new IllegalArgumentException("Cannot set property " + property + " as it does not exist in " + this.owner); -+ } else if (comparable.equals(value)) { -+ return (S)this; -+ } else { -+ S object = this.neighbours.get(property, value); -+ if (object == null) { -+ throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value"); -+ } else { -+ return object; -+ } - } -- return ret; -- // Paper end - optimise state lookup - } - - public , V extends T> S trySetValue(Property property, V value) { -@@ -0,0 +0,0 @@ public abstract class StateHolder { - } - } - -- this.neighbours = (Table, Comparable, S>)(table.isEmpty() ? table : ArrayTable.create(table)); this.optimisedTable.loadInTable((Table)this.neighbours, this.values); // Paper - optimise state lookup -+ this.neighbours = (Table, Comparable, S>)(table.isEmpty() ? table : ArrayTable.create(table)); - } - } - -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -@@ -0,0 +0,0 @@ import java.util.Optional; - public class BooleanProperty extends Property { - private final ImmutableSet values = ImmutableSet.of(true, false); - -- // Paper start - optimise iblockdata state lookup -- @Override -- public final int getIdFor(final Boolean value) { -- return value.booleanValue() ? 1 : 0; -- } -- // Paper end - optimise iblockdata state lookup -- - protected BooleanProperty(String name) { - super(name, Boolean.class); - } -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java -@@ -0,0 +0,0 @@ public class EnumProperty & StringRepresentable> extends Prope - private final ImmutableSet values; - private final Map names = Maps.newHashMap(); - -- // Paper start - optimise iblockdata state lookup -- private int[] idLookupTable; -- -- @Override -- public final int getIdFor(final T value) { -- return this.idLookupTable[value.ordinal()]; -- } -- // Paper end - optimise iblockdata state lookup -- - protected EnumProperty(String name, Class type, Collection values) { - super(name, type); - this.values = ImmutableSet.copyOf(values); -@@ -0,0 +0,0 @@ public class EnumProperty & StringRepresentable> extends Prope - - this.names.put(string, enum_); - } -- // Paper start - optimise BlockState lookup -- int id = 0; -- this.idLookupTable = new int[type.getEnumConstants().length]; -- java.util.Arrays.fill(this.idLookupTable, -1); -- for (final T value : this.getPossibleValues()) { -- this.idLookupTable[value.ordinal()] = id++; -- } -- // Paper end - optimise BlockState lookup - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -@@ -0,0 +0,0 @@ public class IntegerProperty extends Property { - public final int min; - public final int max; - -- // Paper start - optimise iblockdata state lookup -- @Override -- public final int getIdFor(final Integer value) { -- final int val = value.intValue(); -- final int ret = val - this.min; -- -- return ret | ((this.max - ret) >> 31); -- } -- // Paper end - optimise iblockdata state lookup -- - protected IntegerProperty(String name, int min, int max) { - super(name, Integer.class); - if (min < 0) { -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java -@@ -0,0 +0,0 @@ public abstract class Property> { - ); - private final Codec> valueCodec = this.codec.xmap(this::value, Property.Value::value); - -- // Paper start - optimise iblockdata state lookup -- private static final java.util.concurrent.atomic.AtomicInteger ID_GENERATOR = new java.util.concurrent.atomic.AtomicInteger(); -- private final int id = ID_GENERATOR.getAndIncrement(); -- -- public final int getId() { -- return this.id; -- } -- -- public abstract int getIdFor(final T value); -- // Paper end - optimise state lookup -- - protected Property(String name, Class type) { - this.clazz = type; - this.name = name; diff --git a/patches/unapplied/server/Rewrite-dataconverter-system.patch b/patches/server/Rewrite-dataconverter-system.patch similarity index 97% rename from patches/unapplied/server/Rewrite-dataconverter-system.patch rename to patches/server/Rewrite-dataconverter-system.patch index d36b1630e0..21d9819455 100644 --- a/patches/unapplied/server/Rewrite-dataconverter-system.patch +++ b/patches/server/Rewrite-dataconverter-system.patch @@ -233,216 +233,225 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Note: Some of these are nameless. + // Unless a data version is specified here, it will NOT have converters ran for it. Please add them on update! + final int[] converterVersions = new int[] { -+ 99, -+ 100, -+ 101, -+ 102, -+ 105, -+ 106, -+ 107, -+ 108, -+ 109, -+ 110, -+ 111, -+ 113, -+ 135, -+ 143, -+ 147, -+ 165, -+ 501, -+ 502, -+ 505, -+ 700, -+ 701, -+ 702, -+ 703, -+ 704, -+ 705, -+ 804, -+ 806, -+ 808, -+ 808, -+ 813, -+ 816, -+ 820, -+ 1022, -+ 1125, -+ 1344, -+ 1446, -+ 1450, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1451, -+ 1456, -+ 1458, -+ 1460, -+ 1466, -+ 1470, -+ 1474, -+ 1475, -+ 1480, -+ 1481, -+ 1483, -+ 1484, -+ 1486, -+ 1487, -+ 1488, -+ 1490, -+ 1492, -+ 1494, -+ 1496, -+ 1500, -+ 1501, -+ 1502, -+ 1506, -+ 1510, -+ 1514, -+ 1515, -+ 1624, -+ 1800, -+ 1801, -+ 1802, -+ 1803, -+ 1904, -+ 1905, -+ 1906, -+ 1909, -+ 1911, -+ 1914, -+ 1917, -+ 1918, -+ 1920, -+ 1925, -+ 1928, -+ 1929, -+ 1931, -+ 1936, -+ 1946, -+ 1948, -+ 1953, -+ 1955, -+ 1961, -+ 1963, -+ 2100, -+ 2202, -+ 2209, -+ 2211, -+ 2218, -+ 2501, -+ 2502, -+ 2503, -+ 2505, -+ 2508, -+ 2509, -+ 2511, -+ 2514, -+ 2516, -+ 2518, -+ 2519, -+ 2522, -+ 2523, -+ 2527, -+ 2528, -+ 2529, -+ 2531, -+ 2533, -+ 2535, -+ 2538, -+ 2550, -+ 2551, -+ 2552, -+ 2553, -+ 2558, -+ 2568, -+ 2671, -+ 2679, -+ 2680, -+ 2684, -+ 2686, -+ 2688, -+ 2690, -+ 2691, -+ 2693, -+ 2696, -+ 2700, -+ 2701, -+ 2702, -+ 2704, -+ 2707, -+ 2710, -+ 2717, -+ 2825, -+ 2831, -+ 2832, -+ 2833, -+ 2838, -+ 2841, -+ 2842, -+ 2843, -+ 2846, -+ 2852, -+ 2967, -+ 2970, -+ 3077, -+ 3078, -+ 3081, -+ 3082, -+ 3083, -+ 3084, -+ 3086, -+ 3087, -+ 3088, -+ 3090, -+ 3093, -+ 3094, -+ 3097, -+ 3108, -+ 3201, -+ 3203, -+ 3204, -+ 3209, -+ 3214, -+ 3319, -+ 3322, -+ 3438, -+ 3439, -+ 3440, -+ 3441, -+ 3447, -+ 3448, -+ 3450, -+ 3451, -+ 3459, -+ 3564, -+ 3565, -+ 3566, -+ 3568, -+ 3683, -+ 3685, -+ 3692, -+ 3800, -+ 3803, -+ 3807, -+ 3808, -+ 3809, -+ 3812, -+ 3813, -+ 3814, -+ 3818, -+ 3820, -+ 3825, -+ 3828, -+ 3833, -+ 3939, -+ 3943, -+ 3945 -+ // All up to 1.21 ++ 99, ++ 100, ++ 101, ++ 102, ++ 105, ++ 106, ++ 107, ++ 108, ++ 109, ++ 110, ++ 111, ++ 113, ++ 135, ++ 143, ++ 147, ++ 165, ++ 501, ++ 502, ++ 505, ++ 700, ++ 701, ++ 702, ++ 703, ++ 704, ++ 705, ++ 804, ++ 806, ++ 808, ++ 808, ++ 813, ++ 816, ++ 820, ++ 1022, ++ 1125, ++ 1344, ++ 1446, ++ 1450, ++ 1451, ++ 1451, ++ 1451, ++ 1451, ++ 1451, ++ 1451, ++ 1451, ++ 1451, ++ 1451, ++ 1456, ++ 1458, ++ 1460, ++ 1466, ++ 1470, ++ 1474, ++ 1475, ++ 1480, ++ 1481, ++ 1483, ++ 1484, ++ 1486, ++ 1487, ++ 1488, ++ 1490, ++ 1492, ++ 1494, ++ 1496, ++ 1500, ++ 1501, ++ 1502, ++ 1506, ++ 1510, ++ 1514, ++ 1515, ++ 1624, ++ 1800, ++ 1801, ++ 1802, ++ 1803, ++ 1904, ++ 1905, ++ 1906, ++ 1909, ++ 1911, ++ 1914, ++ 1917, ++ 1918, ++ 1920, ++ 1925, ++ 1928, ++ 1929, ++ 1931, ++ 1936, ++ 1946, ++ 1948, ++ 1953, ++ 1955, ++ 1961, ++ 1963, ++ 2100, ++ 2202, ++ 2209, ++ 2211, ++ 2218, ++ 2501, ++ 2502, ++ 2503, ++ 2505, ++ 2508, ++ 2509, ++ 2511, ++ 2514, ++ 2516, ++ 2518, ++ 2519, ++ 2522, ++ 2523, ++ 2527, ++ 2528, ++ 2529, ++ 2531, ++ 2533, ++ 2535, ++ 2538, ++ 2550, ++ 2551, ++ 2552, ++ 2553, ++ 2558, ++ 2568, ++ 2671, ++ 2679, ++ 2680, ++ 2684, ++ 2686, ++ 2688, ++ 2690, ++ 2691, ++ 2693, ++ 2696, ++ 2700, ++ 2701, ++ 2702, ++ 2704, ++ 2707, ++ 2710, ++ 2717, ++ 2825, ++ 2831, ++ 2832, ++ 2833, ++ 2838, ++ 2841, ++ 2842, ++ 2843, ++ 2846, ++ 2852, ++ 2967, ++ 2970, ++ 3077, ++ 3078, ++ 3081, ++ 3082, ++ 3083, ++ 3084, ++ 3086, ++ 3087, ++ 3088, ++ 3090, ++ 3093, ++ 3094, ++ 3097, ++ 3108, ++ 3201, ++ 3203, ++ 3204, ++ 3209, ++ 3214, ++ 3319, ++ 3322, ++ 3438, ++ 3439, ++ 3440, ++ 3441, ++ 3447, ++ 3448, ++ 3450, ++ 3451, ++ 3459, ++ 3564, ++ 3565, ++ 3566, ++ 3568, ++ 3683, ++ 3685, ++ 3692, ++ 3800, ++ 3803, ++ 3807, ++ 3808, ++ 3809, ++ 3812, ++ 3813, ++ 3814, ++ 3818, ++ 3820, ++ 3825, ++ 3828, ++ 3833, ++ 3939, ++ 3943, ++ 3945, ++ 4054, ++ 4055, ++ 4057, ++ 4059, ++ 4061, ++ 4064, ++ 4067, ++ 4068, ++ 4081, ++ // All up to 1.21.3 + }; + Arrays.sort(converterVersions); + @@ -1161,18 +1170,37 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static final int V1_20_5 = 3837; + public static final int V1_20_6_RC1 = 3838; + public static final int V1_20_6 = 3839; -+ public static final int V2418WA = 3940; -+ public static final int V2419WA = 3941; -+ public static final int V2419WB = 3942; -+ public static final int V2420WA = 3944; -+ public static final int V2421WA = 3946; -+ public static final int V2421WB = 3947; -+ public static final int V_1_21_PRE1 = 3948; -+ public static final int V_1_21_PRE2 = 3949; -+ public static final int V_1_21_PRE3 = 3950; -+ public static final int V_1_21_PRE4 = 3951; -+ public static final int V_1_21_RC1 = 3952; -+ public static final int V_1_21 = 3953; ++ public static final int V24W18A = 3940; ++ public static final int V24W19A = 3941; ++ public static final int V24W19B = 3942; ++ public static final int V24W20A = 3944; ++ public static final int V24W21A = 3946; ++ public static final int V24W21B = 3947; ++ public static final int V1_21_PRE1 = 3948; ++ public static final int V1_21_PRE2 = 3949; ++ public static final int V1_21_PRE3 = 3950; ++ public static final int V1_21_PRE4 = 3951; ++ public static final int V1_21_RC1 = 3952; ++ public static final int V1_21 = 3953; ++ public static final int V1_21_RC = 3954; ++ public static final int V1_21_1 = 3955; ++ public static final int V24W33A = 4058; ++ public static final int V24W34A = 4060; ++ public static final int V24W35A = 4062; ++ public static final int V24W36A = 4063; ++ public static final int V24W37A = 4065; ++ public static final int V24W38A = 4066; ++ public static final int V24W39A = 4069; ++ public static final int V24W40A = 4072; ++ public static final int V1_21_2_PRE1 = 4073; ++ public static final int V1_21_2_PRE2 = 4074; ++ public static final int V1_21_2_PRE3 = 4075; ++ public static final int V1_21_2_PRE4 = 4076; ++ public static final int V1_21_2_PRE5 = 4077; ++ public static final int V1_21_2_RC1 = 4078; ++ public static final int V1_21_2_RC2 = 4079; ++ public static final int V1_21_2 = 4080; ++ public static final int V1_21_3 = 4082; + + private MCVersions() {} +} @@ -1281,6 +1309,72 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public static void register(final int version, final int versionStep, final Function renamer) { ++ MCTypeRegistry.DATA_COMPONENTS.addStructureConverter(new DataConverter<>(version, versionStep) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final MapType attributeModifiers = data.getMap("minecraft:attribute_modifiers"); ++ if (attributeModifiers == null) { ++ return null; ++ } ++ ++ final ListType modifiers = attributeModifiers.getList("modifiers", ObjectType.MAP); ++ if (modifiers == null) { ++ return null; ++ } ++ ++ for (int i = 0, len = modifiers.size(); i < len; ++i) { ++ RenameHelper.renameString(modifiers.getMap(i), "type", renamer); ++ } ++ ++ return null; ++ } ++ }); ++ ++ final DataConverter, MapType> entityConverter = new DataConverter<>(version, versionStep) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final ListType modifiers = data.getList("attributes", ObjectType.MAP); ++ if (modifiers == null) { ++ return null; ++ } ++ ++ for (int i = 0, len = modifiers.size(); i < len; ++i) { ++ RenameHelper.renameString(modifiers.getMap(i), "id", renamer); ++ } ++ ++ return null; ++ } ++ }; ++ ++ MCTypeRegistry.ENTITY.addStructureConverter(entityConverter); ++ MCTypeRegistry.PLAYER.addStructureConverter(entityConverter); ++ } ++ ++ private ConverterAbstractAttributesRename() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/attributes/ConverterAbstractOldAttributesRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/attributes/ConverterAbstractOldAttributesRename.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/attributes/ConverterAbstractOldAttributesRename.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.dataconverter.minecraft.converters.attributes; ++ ++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.ListType; ++import ca.spottedleaf.dataconverter.types.MapType; ++import ca.spottedleaf.dataconverter.types.ObjectType; ++import java.util.function.Function; ++ ++public final class ConverterAbstractOldAttributesRename { ++ ++ public static void register(final int version, final Function renamer) { ++ register(version, 0, renamer); ++ } ++ ++ public static void register(final int version, final int versionStep, final Function renamer) { + final DataConverter, MapType> entityConverter = new DataConverter<>(version, versionStep) { + @Override + public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { @@ -1319,7 +1413,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + }); + } + -+ private ConverterAbstractAttributesRename() {} ++ private ConverterAbstractOldAttributesRename() {} +} diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/blockname/ConverterAbstractBlockRename.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/blockname/ConverterAbstractBlockRename.java new file mode 100644 @@ -9254,6 +9348,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import ca.spottedleaf.dataconverter.minecraft.versions.*; +import com.mojang.logging.LogUtils; +import org.slf4j.Logger; ++import java.text.DecimalFormat; + +public final class MCTypeRegistry { + @@ -9303,12 +9398,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public static final MCValueType DATACONVERTER_CUSTOM_TYPE_COMMAND = new MCValueType("DC_Custom/Command"); + + static { ++ LOGGER.info("Initialising converters for DataConverter..."); ++ ++ final long start = System.nanoTime(); + try { + registerAll(); + } catch (final Throwable thr) { + LOGGER.error(LogUtils.FATAL_MARKER, "Failed to register data converters", thr); + throw new RuntimeException(thr); + } ++ final long end = System.nanoTime(); ++ ++ final DecimalFormat oneDecimalFormat = new DecimalFormat("#,##0.0"); ++ ++ LOGGER.info("Finished initialising converters for DataConverter in " + oneDecimalFormat.format((double)(end - start) / 1.0E6) + "ms"); + } + + private static void registerAll() { @@ -9548,6 +9651,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + V3939.register(); + V3943.register(); + V3945.register(); ++ // V1.21.2 ++ V4054.register(); ++ V4055.register(); ++ V4057.register(); ++ V4059.register(); ++ V4061.register(); ++ V4064.register(); ++ V4067.register(); ++ V4068.register(); ++ V4070.register(); ++ V4071.register(); ++ // V1.21.3 ++ V4081.register(); + } + + private MCTypeRegistry() {} @@ -9741,6 +9857,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public static String retrieveTranslationString(final String possibleJson) { ++ if (possibleJson == null) { ++ return null; ++ } ++ + try { + final JsonElement element = JsonParser.parseString(possibleJson); + @@ -9996,6 +10116,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return null; + } + }); ++ MCTypeRegistry.ENTITY.addConverterForId("Villager", new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ data.setBoolean("CanPickUpLoot", true); ++ return null; ++ } ++ }); + } + + private V101() {} @@ -10113,6 +10240,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + MCTypeRegistry.PLAYER.addStructureWalker(VERSION, (final MapType data, final long fromVersion, final long toVersion) -> { + WalkerUtils.convert(MCTypeRegistry.ENTITY, data.getMap("RootVehicle"), "Entity", fromVersion, toVersion); + ++ WalkerUtils.convertList(MCTypeRegistry.ENTITY, data, "ender_pearls", fromVersion, toVersion); ++ + WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "Inventory", fromVersion, toVersion); + WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, data, "EnderItems", fromVersion, toVersion); + @@ -10933,6 +11062,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + WalkerUtils.convert(MCTypeRegistry.ENTITY, rootVehicle, "Entity", fromVersion, toVersion); + } + ++ WalkerUtils.convertList(MCTypeRegistry.ENTITY, data, "ender_pearls", fromVersion, toVersion); ++ + return null; + }); + @@ -16286,7 +16417,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +package ca.spottedleaf.dataconverter.minecraft.versions; + +import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.attributes.ConverterAbstractAttributesRename; ++import ca.spottedleaf.dataconverter.minecraft.converters.attributes.ConverterAbstractOldAttributesRename; +import com.google.common.collect.ImmutableMap; +import java.util.HashMap; +import java.util.Map; @@ -16319,7 +16450,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ); + + public static void register() { -+ ConverterAbstractAttributesRename.register(VERSION, RENAMES::get); ++ ConverterAbstractOldAttributesRename.register(VERSION, RENAMES::get); + } + + private V2523() {} @@ -22444,7 +22575,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +package ca.spottedleaf.dataconverter.minecraft.versions; + +import ca.spottedleaf.dataconverter.minecraft.MCVersions; -+import ca.spottedleaf.dataconverter.minecraft.converters.attributes.ConverterAbstractAttributesRename; ++import ca.spottedleaf.dataconverter.minecraft.converters.attributes.ConverterAbstractOldAttributesRename; +import java.util.HashMap; +import java.util.Map; + @@ -22457,7 +22588,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + Map.of("minecraft:horse.jump_strength", "minecraft:generic.jump_strength") + ); + -+ ConverterAbstractAttributesRename.register(VERSION, renames::get); ++ ConverterAbstractOldAttributesRename.register(VERSION, renames::get); + } + + private V3814() {} @@ -23141,7 +23272,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return null; + } + -+ + final String id = NamespaceUtil.correctNamespace(item.getString("id", "minecraft:air")); + final int count = item.getInt("count", 0); + @@ -23230,7 +23360,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + +public final class V3943 { + -+ private static final int VERSION = MCVersions.V2419WB + 1; ++ private static final int VERSION = MCVersions.V24W19B + 1; + + public static void register() { + MCTypeRegistry.OPTIONS.addStructureConverter(new DataConverter<>(VERSION) { @@ -23279,7 +23409,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + +public final class V3945 { + -+ private static final int VERSION = MCVersions.V2420WA + 1; ++ private static final int VERSION = MCVersions.V24W20A + 1; + + private static final Map UUID_TO_ID = new HashMap<>( + ImmutableMap.builder() @@ -23397,9 +23527,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return retList; + } + -+ + public static void register() { -+ + MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { + @Override + public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { @@ -23507,6 +23635,745 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + private V3945() {} +} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4054.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4054.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4054.java +@@ -0,0 +0,0 @@ ++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.util.ComponentUtils; ++import ca.spottedleaf.dataconverter.types.MapType; ++ ++public final class V4054 { ++ ++ private static final int VERSION = MCVersions.V1_21_1 + 99; ++ ++ public static void register() { ++ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:banner", new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ convertComponents(data.getMap("components")); ++ return null; ++ } ++ }); ++ MCTypeRegistry.ITEM_STACK.addConverterForId("minecraft:white_banner", new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ convertComponents(data.getMap("components")); ++ return null; ++ } ++ }); ++ } ++ ++ private static void convertComponents(final MapType components) { ++ if (components == null) { ++ return; ++ } ++ ++ final String itemNameKey = ComponentUtils.retrieveTranslationString(components.getString("minecraft:item_name")); ++ ++ if (!"block.minecraft.ominous_banner".equals(itemNameKey)) { ++ return; ++ } ++ ++ components.setString("minecraft:rarity", "uncommon"); ++ components.setString("minecraft:item_name", ComponentUtils.createTranslatableComponent("block.minecraft.ominous_banner")); ++ } ++ ++ private V4054() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4055.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4055.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4055.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.attributes.ConverterAbstractAttributesRename; ++import ca.spottedleaf.dataconverter.util.NamespaceUtil; ++ ++public final class V4055 { ++ ++ private static final int VERSION = MCVersions.V1_21_1 + 100; ++ ++ private static final Prefix[] PREFIXES_TO_REMOVE = new Prefix[] { ++ new Prefix("generic."), ++ new Prefix("horse."), ++ new Prefix("player."), ++ new Prefix("zombie.") ++ }; ++ ++ private static record Prefix(String raw, String namespaced) { ++ public Prefix(final String raw) { ++ this(raw, NamespaceUtil.correctNamespace(raw)); ++ } ++ } ++ ++ public static void register() { ++ ConverterAbstractAttributesRename.register(VERSION, (final String input) -> { ++ final String namespacedInput = NamespaceUtil.correctNamespace(input); ++ ++ for (final Prefix prefix : PREFIXES_TO_REMOVE) { ++ if (!namespacedInput.startsWith(prefix.namespaced())) { ++ continue; ++ } ++ ++ return "minecraft:".concat(namespacedInput.substring(prefix.namespaced().length())); ++ } ++ ++ return null; ++ }); ++ } ++ ++ private V4055() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4057.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4057.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4057.java +@@ -0,0 +0,0 @@ ++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 V4057 { ++ ++ private static final int VERSION = MCVersions.V1_21_1 + 102; ++ ++ public static void register() { ++ MCTypeRegistry.CHUNK.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final MapType carvingMasks = data.getMap("CarvingMasks"); ++ if (carvingMasks == null) { ++ return null; ++ } ++ data.remove("CarvingMasks"); ++ ++ final long[] airMask = carvingMasks.getLongs("AIR"); ++ if (airMask != null) { ++ data.setLongs("carving_mask", airMask); ++ } ++ ++ return null; ++ } ++ }); ++ } ++ ++ private V4057() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4059.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4059.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4059.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.converters.datatypes.DataWalker; ++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.TypeUtil; ++ ++public final class V4059 { ++ ++ private static final int VERSION = MCVersions.V24W33A + 1; ++ ++ public static void register() { ++ // previous version: 3818.3 ++ MCTypeRegistry.DATA_COMPONENTS.addStructureWalker(VERSION, new DataWalker<>() { ++ private static void walkBlockPredicates(final MapType root, final long fromVersion, final long toVersion) { ++ if (root.hasKey("blocks", ObjectType.STRING)) { ++ WalkerUtils.convert(MCTypeRegistry.BLOCK_NAME, root, "blocks", fromVersion, toVersion); ++ } else if (root.hasKey("blocks", ObjectType.LIST)) { ++ WalkerUtils.convertList(MCTypeRegistry.BLOCK_NAME, root, "blocks", fromVersion, toVersion); ++ } ++ } ++ ++ @Override ++ public MapType walk(final MapType root, final long fromVersion, final long toVersion) { ++ WalkerUtils.convertListPath(MCTypeRegistry.ENTITY, root, "minecraft:bees", "entity_data", fromVersion, toVersion); ++ ++ WalkerUtils.convert(MCTypeRegistry.TILE_ENTITY, root, "minecraft:block_entity_data", fromVersion, toVersion); ++ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, root, "minecraft:bundle_contents", fromVersion, toVersion); ++ ++ final MapType canBreak = root.getMap("minecraft:can_break"); ++ if (canBreak != null) { ++ final ListType predicates = canBreak.getList("predicates", ObjectType.MAP); ++ if (predicates != null) { ++ for (int i = 0, len = predicates.size(); i < len; ++i) { ++ walkBlockPredicates(predicates.getMap(i), fromVersion, toVersion); ++ } ++ } ++ // Not handled by DFU: simple encoding does not require "predicates" ++ walkBlockPredicates(canBreak, fromVersion, toVersion); ++ } ++ ++ final MapType canPlaceOn = root.getMap("minecraft:can_place_on"); ++ if (canPlaceOn != null) { ++ final ListType predicates = canPlaceOn.getList("predicates", ObjectType.MAP); ++ if (predicates != null) { ++ for (int i = 0, len = predicates.size(); i < len; ++i) { ++ walkBlockPredicates(predicates.getMap(i), fromVersion, toVersion); ++ } ++ } ++ // Not handled by DFU: simple encoding does not require "predicates" ++ walkBlockPredicates(canPlaceOn, fromVersion, toVersion); ++ } ++ ++ WalkerUtils.convertList(MCTypeRegistry.ITEM_STACK, root, "minecraft:charged_projectiles", fromVersion, toVersion); ++ WalkerUtils.convertListPath(MCTypeRegistry.ITEM_STACK, root, "minecraft:container", "item", fromVersion, toVersion); ++ WalkerUtils.convert(MCTypeRegistry.ENTITY, root, "minecraft:entity_data", fromVersion, toVersion); ++ WalkerUtils.convertList(MCTypeRegistry.ITEM_NAME, root, "minecraft:pot_decorations", fromVersion, toVersion); ++ WalkerUtils.convert(MCTypeRegistry.ITEM_STACK, root, "minecraft:use_remainder", fromVersion, toVersion); ++ ++ final MapType equippable = root.getMap("minecraft:equippable"); ++ if (equippable != null) { ++ WalkerUtils.convert(MCTypeRegistry.ENTITY_NAME, equippable, "allowed_entities", fromVersion, toVersion); ++ WalkerUtils.convertList(MCTypeRegistry.ENTITY_NAME, equippable, "allowed_entities", fromVersion, toVersion); ++ } ++ ++ return null; ++ } ++ }); ++ ++ MCTypeRegistry.DATA_COMPONENTS.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final MapType food = data.getMap("minecraft:food"); ++ if (food == null) { ++ return null; ++ } ++ ++ final TypeUtil typeUtil = data.getTypeUtil(); ++ ++ final float eatSeconds = food.getFloat("eat_seconds", 1.6F); ++ ++ final ListType oldEffects = food.getList("effects", ObjectType.MAP); ++ final ListType newEffects = typeUtil.createEmptyList(); ++ if (oldEffects != null) { ++ for (int i = 0, len = oldEffects.size(); i < len; ++i) { ++ final MapType oldEffect = oldEffects.getMap(i); ++ ++ final MapType newEffect = typeUtil.createEmptyMap(); ++ newEffects.addMap(newEffect); ++ ++ newEffect.setString("type", "minecraft:apply_effects"); ++ ++ final Object oldEffectEffect = oldEffect.getGeneric("effect"); ++ final ListType newEffectEffects = typeUtil.createEmptyList(); ++ newEffectEffects.addGeneric(oldEffectEffect); ++ newEffect.setList("effects", newEffectEffects); ++ ++ newEffect.setFloat("probability", oldEffect.getFloat("probability", 1.0F)); ++ } ++ } ++ ++ final Object convertsTo = food.getGeneric("using_converts_to"); ++ if (convertsTo != null) { ++ data.setGeneric("minecraft:use_remainder", convertsTo); ++ } ++ ++ food.remove("eat_seconds"); ++ food.remove("effects"); ++ food.remove("using_converts_to"); ++ ++ final MapType consumable = typeUtil.createEmptyMap(); ++ data.setMap("minecraft:consumable", consumable); ++ ++ consumable.setFloat("consume_seconds", eatSeconds); ++ consumable.setList("on_consume_effects", newEffects); ++ ++ return null; ++ } ++ }); ++ } ++ ++ private V4059() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4061.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4061.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4061.java +@@ -0,0 +0,0 @@ ++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; ++import ca.spottedleaf.dataconverter.types.nbt.NBTMapType; ++import com.mojang.brigadier.exceptions.CommandSyntaxException; ++import com.mojang.datafixers.util.Pair; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.nbt.TagParser; ++import java.util.HashMap; ++import java.util.Map; ++ ++public final class V4061 { ++ ++ private static final int VERSION = MCVersions.V24W34A + 1; ++ ++ private static final Map, MapType>, String> CONVERT_MAP = new HashMap<>(); ++ static { ++ addConversion("trial_chamber/breeze", "{simultaneous_mobs: 1.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {id: \"minecraft:breeze\"}}, weight: 1}], ticks_between_spawn: 20, total_mobs: 2.0f, total_mobs_added_per_player: 1.0f}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], simultaneous_mobs: 2.0f, total_mobs: 4.0f}"); ++ addConversion("trial_chamber/melee/husk", "{simultaneous_mobs: 3.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {id: \"minecraft:husk\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], spawn_potentials: [{data: {entity: {id: \"minecraft:husk\"}, equipment: {loot_table: \"minecraft:equipment/trial_chamber_melee\", slot_drop_chances: 0.0f}}, weight: 1}]}"); ++ addConversion("trial_chamber/melee/spider", "{simultaneous_mobs: 3.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {id: \"minecraft:spider\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}],simultaneous_mobs: 4.0f, total_mobs: 12.0f}"); ++ addConversion("trial_chamber/melee/zombie", "{simultaneous_mobs: 3.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {id: \"minecraft:zombie\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}],spawn_potentials: [{data: {entity: {id: \"minecraft:zombie\"}, equipment: {loot_table: \"minecraft:equipment/trial_chamber_melee\", slot_drop_chances: 0.0f}}, weight: 1}]}"); ++ addConversion("trial_chamber/ranged/poison_skeleton", "{simultaneous_mobs: 3.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {id: \"minecraft:bogged\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}],spawn_potentials: [{data: {entity: {id: \"minecraft:bogged\"}, equipment: {loot_table: \"minecraft:equipment/trial_chamber_ranged\", slot_drop_chances: 0.0f}}, weight: 1}]}"); ++ addConversion("trial_chamber/ranged/skeleton", "{simultaneous_mobs: 3.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {id: \"minecraft:skeleton\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], spawn_potentials: [{data: {entity: {id: \"minecraft:skeleton\"}, equipment: {loot_table: \"minecraft:equipment/trial_chamber_ranged\", slot_drop_chances: 0.0f}}, weight: 1}]}"); ++ addConversion("trial_chamber/ranged/stray", "{simultaneous_mobs: 3.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {id: \"minecraft:stray\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], spawn_potentials: [{data: {entity: {id: \"minecraft:stray\"}, equipment: {loot_table: \"minecraft:equipment/trial_chamber_ranged\", slot_drop_chances: 0.0f}}, weight: 1}]}"); ++ addConversion("trial_chamber/slow_ranged/poison_skeleton", "{simultaneous_mobs: 4.0f, simultaneous_mobs_added_per_player: 2.0f, spawn_potentials: [{data: {entity: {id: \"minecraft:bogged\"}}, weight: 1}], ticks_between_spawn: 160}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], spawn_potentials: [{data: {entity: {id: \"minecraft:bogged\"}, equipment: {loot_table: \"minecraft:equipment/trial_chamber_ranged\", slot_drop_chances: 0.0f}}, weight: 1}]}"); ++ addConversion("trial_chamber/slow_ranged/skeleton", "{simultaneous_mobs: 4.0f, simultaneous_mobs_added_per_player: 2.0f, spawn_potentials: [{data: {entity: {id: \"minecraft:skeleton\"}}, weight: 1}], ticks_between_spawn: 160}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], spawn_potentials: [{data: {entity: {id: \"minecraft:skeleton\"}, equipment: {loot_table: \"minecraft:equipment/trial_chamber_ranged\", slot_drop_chances: 0.0f}}, weight: 1}]}"); ++ addConversion("trial_chamber/slow_ranged/stray", "{simultaneous_mobs: 4.0f, simultaneous_mobs_added_per_player: 2.0f, spawn_potentials: [{data: {entity: {id: \"minecraft:stray\"}}, weight: 1}], ticks_between_spawn: 160}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}],spawn_potentials: [{data: {entity: {id: \"minecraft:stray\"}, equipment: {loot_table: \"minecraft:equipment/trial_chamber_ranged\", slot_drop_chances: 0.0f}}, weight: 1}]}"); ++ addConversion("trial_chamber/small_melee/baby_zombie", "{simultaneous_mobs: 2.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {IsBaby: 1b, id: \"minecraft:zombie\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], spawn_potentials: [{data: {entity: {IsBaby: 1b, id: \"minecraft:zombie\"}, equipment: {loot_table: \"minecraft:equipment/trial_chamber_melee\", slot_drop_chances: 0.0f}}, weight: 1}]}"); ++ addConversion("trial_chamber/small_melee/cave_spider", "{simultaneous_mobs: 3.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {id: \"minecraft:cave_spider\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], simultaneous_mobs: 4.0f, total_mobs: 12.0f}"); ++ addConversion("trial_chamber/small_melee/silverfish", "{simultaneous_mobs: 3.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {id: \"minecraft:silverfish\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], simultaneous_mobs: 4.0f, total_mobs: 12.0f}"); ++ addConversion("trial_chamber/small_melee/slime", "{simultaneous_mobs: 3.0f, simultaneous_mobs_added_per_player: 0.5f, spawn_potentials: [{data: {entity: {Size: 1, id: \"minecraft:slime\"}}, weight: 3}, {data: {entity: {Size: 2, id: \"minecraft:slime\"}}, weight: 1}], ticks_between_spawn: 20}", "{loot_tables_to_eject: [{data: \"minecraft:spawners/ominous/trial_chamber/key\", weight: 3}, {data: \"minecraft:spawners/ominous/trial_chamber/consumables\", weight: 7}], simultaneous_mobs: 4.0f, total_mobs: 12.0f}"); ++ } ++ ++ private static void addConversion(final String keyPath, final String normalsNBT, final String ominoussNBT) { ++ final String fullKey = "minecraft:".concat(keyPath); ++ ++ final CompoundTag normalNBT = parseNBT(normalsNBT); ++ final MapType normalMapType = new NBTMapType(normalNBT); ++ final CompoundTag ominousNBT = parseNBT(ominoussNBT); ++ ++ final CompoundTag ominousMerged = normalNBT.copy().merge(ominousNBT); ++ ++ CONVERT_MAP.put(Pair.of(normalMapType, new NBTMapType(ominousNBT)), fullKey); ++ CONVERT_MAP.put(Pair.of(normalMapType, new NBTMapType(ominousMerged)), fullKey); ++ CONVERT_MAP.put(Pair.of(normalMapType, new NBTMapType(removeDefaults(ominousMerged.copy()))), fullKey); ++ } ++ ++ private static CompoundTag parseNBT(final String sNBT) { ++ try { ++ return TagParser.parseTag(sNBT); ++ } catch (final CommandSyntaxException ex) { ++ throw new IllegalArgumentException("Failed to parse NBT: " + sNBT, ex); ++ } ++ } ++ ++ private static CompoundTag removeDefaults(final CompoundTag config) { ++ if (config.getInt("spawn_range") == 4) { ++ config.remove("spawn_range"); ++ } ++ ++ if (config.getFloat("total_mobs") == 6.0F) { ++ config.remove("total_mobs"); ++ } ++ ++ if (config.getFloat("simultaneous_mobs") == 2.0F) { ++ config.remove("simultaneous_mobs"); ++ } ++ ++ if (config.getFloat("total_mobs_added_per_player") == 2.0F) { ++ config.remove("total_mobs_added_per_player"); ++ } ++ ++ if (config.getFloat("simultaneous_mobs_added_per_player") == 1.0F) { ++ config.remove("simultaneous_mobs_added_per_player"); ++ } ++ ++ if (config.getInt("ticks_between_spawn") == 40) { ++ config.remove("ticks_between_spawn"); ++ } ++ ++ return config; ++ } ++ ++ public static void register() { ++ MCTypeRegistry.TILE_ENTITY.addConverterForId("minecraft:trial_spawner", new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final MapType normalConfig = data.getMap("normal_config"); ++ final MapType ominousConfig = data.getMap("ominous_config"); ++ ++ if (normalConfig == null || ominousConfig == null) { ++ return null; ++ } ++ ++ final String newKey = CONVERT_MAP.get(new Pair<>(normalConfig, ominousConfig)); ++ if (newKey == null) { ++ return null; ++ } ++ ++ data.setString("normal_config", newKey.concat("/normal")); ++ data.setString("ominous_config", newKey.concat("/ominous")); ++ ++ return null; ++ } ++ }); ++ } ++ ++ private V4061() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4064.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4064.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4064.java +@@ -0,0 +0,0 @@ ++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 V4064 { ++ ++ private static final int VERSION = MCVersions.V24W36A + 1; ++ ++ public static void register() { ++ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final MapType components = data.getMap("components"); ++ if (components == null) { ++ return null; ++ } ++ ++ if (components.hasKey("minecraft:fire_resistant")) { ++ components.remove("minecraft:fire_resistant"); ++ ++ final MapType damageResistant = components.getTypeUtil().createEmptyMap(); ++ components.setMap("minecraft:damage_resistant", damageResistant); ++ ++ damageResistant.setString("types", "#minecraft:is_fire"); ++ } ++ ++ return null; ++ } ++ }); ++ } ++ ++ private V4064() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4067.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4067.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4067.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.converters.DataConverter; ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.converters.leveldat.ConverterRemoveFeatureFlag; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; ++import ca.spottedleaf.dataconverter.types.MapType; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.HashSet; ++import java.util.Map; ++ ++public final class V4067 { ++ ++ private static final int VERSION = MCVersions.V24W38A + 1; ++ ++ private static final record BoatType(String name, String suffix) {} ++ private static final BoatType[] BOAT_TYPES = new BoatType[] { ++ new BoatType("oak", "boat"), ++ new BoatType("spruce", "boat"), ++ new BoatType("birch", "boat"), ++ new BoatType("jungle", "boat"), ++ new BoatType("acacia", "boat"), ++ new BoatType("cherry", "boat"), ++ new BoatType("dark_oak", "boat"), ++ new BoatType("mangrove", "boat"), ++ new BoatType("bamboo", "raft") ++ }; ++ ++ private static void registerChestBoat(final String id) { ++ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("Items")); ++ } ++ ++ public static void register() { ++ // minecraft:oak_boat is a simple entity ++ // minecraft:spruce_boat is a simple entity ++ // minecraft:birch_boat is a simple entity ++ // minecraft:jungle_boat is a simple entity ++ // minecraft:acacia_boat is a simple entity ++ // minecraft:cherry_boat is a simple entity ++ // minecraft:dark_oak_boat is a simple entity ++ // minecraft:mangrove_boat is a simple entity ++ // minecraft:bamboo_raft is a simple entity ++ ++ registerChestBoat("minecraft:oak_chest_boat"); ++ registerChestBoat("minecraft:spruce_chest_boat"); ++ registerChestBoat("minecraft:birch_chest_boat"); ++ registerChestBoat("minecraft:jungle_chest_boat"); ++ registerChestBoat("minecraft:acacia_chest_boat"); ++ registerChestBoat("minecraft:cherry_chest_boat"); ++ registerChestBoat("minecraft:dark_oak_chest_boat"); ++ registerChestBoat("minecraft:mangrove_chest_boat"); ++ registerChestBoat("minecraft:bamboo_chest_raft"); ++ ++ // we do not update V704 to set the new boat types, as the new ids are only registered here ++ // if we updated V704 to set the new boat types, then the registered walkers for the chest_boat would not run before ++ // V4067 as they are only registered here ++ ++ // to ensure that the id is correctly set eventually, we will force Type to the correct value based on the item id ++ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { ++ private static final Map BOAT_TYPES_BY_ITEM_ID = new HashMap<>(); ++ static { ++ for (final BoatType boatType : BOAT_TYPES) { ++ BOAT_TYPES_BY_ITEM_ID.put(boatType.name() + "_" + boatType.suffix(), boatType.name()); ++ BOAT_TYPES_BY_ITEM_ID.put(boatType.name() + "_chest_" + boatType.suffix(), boatType.name()); ++ } ++ } ++ ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final String id = data.getString("id"); ++ final String boatType = BOAT_TYPES_BY_ITEM_ID.get(id); ++ ++ if (boatType == null) { ++ return null; ++ } ++ ++ final MapType components = data.getMap("components"); ++ if (components == null) { ++ return null; ++ } ++ ++ final MapType entityData = components.getMap("minecraft:entity_data"); ++ if (entityData == null) { ++ return null; ++ } ++ ++ entityData.setString("Type", boatType); ++ ++ return null; ++ } ++ }); ++ ++ MCTypeRegistry.ENTITY.addStructureConverter(new DataConverter<>(VERSION) { ++ private static final Map NORMAL_REMAPPING = new HashMap<>(BOAT_TYPES.length); ++ static { ++ for (final BoatType type : BOAT_TYPES) { ++ NORMAL_REMAPPING.put(type.name(), type.name() + "_" + type.suffix()); ++ } ++ } ++ private static final Map CHEST_REMAPPING = new HashMap<>(BOAT_TYPES.length); ++ static { ++ for (final BoatType type : BOAT_TYPES) { ++ CHEST_REMAPPING.put(type.name(), type.name() + "_chest_" + type.suffix()); ++ } ++ } ++ ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final String id = data.getString("id"); ++ if (id == null) { ++ // wat ++ return null; ++ } ++ ++ final boolean normalBoat = id.equals("minecraft:boat"); ++ final boolean chestBoat = id.equals("minecraft:chest_boat"); ++ ++ if (!normalBoat && !chestBoat) { ++ return null; ++ } ++ ++ final String type = data.getString("Type"); ++ data.remove("Type"); ++ ++ if (normalBoat) { ++ data.setString("id", NORMAL_REMAPPING.getOrDefault(type, "minecraft:oak_boat")); ++ } else { ++ data.setString("id", CHEST_REMAPPING.getOrDefault(type, "minecraft:oak_chest_boat")); ++ } ++ ++ return null; ++ } ++ }); ++ ++ MCTypeRegistry.LEVEL.addStructureConverter( ++ new ConverterRemoveFeatureFlag(VERSION, new HashSet<>(Arrays.asList("minecraft:bundle"))) ++ ); ++ } ++ ++ private V4067() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4068.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4068.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4068.java +@@ -0,0 +0,0 @@ ++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; ++import ca.spottedleaf.dataconverter.types.TypeUtil; ++import com.google.common.escape.Escaper; ++import com.google.common.escape.Escapers; ++ ++public final class V4068 { ++ public static final Escaper ESCAPER = Escapers.builder().addEscape('"', "\\\"").addEscape('\\', "\\\\").build(); ++ ++ private static final int VERSION = MCVersions.V24W38A + 2; ++ ++ private static void convertLock(final MapType root, final String srcPath, final String dstPath) { ++ if (root == null) { ++ return; ++ } ++ ++ final Object lockGeneric = root.getGeneric(srcPath); ++ if (lockGeneric == null) { ++ return; ++ } ++ ++ final TypeUtil typeUtil = root.getTypeUtil(); ++ ++ final MapType newLock = typeUtil.createEmptyMap(); ++ root.remove(srcPath); ++ root.setMap(dstPath, newLock); ++ ++ if (lockGeneric instanceof String lock) { ++ final MapType lockComponents = typeUtil.createEmptyMap(); ++ newLock.setMap("components", lockComponents); ++ ++ lockComponents.setString("minecraft:custom_name", ESCAPER.escape(lock)); ++ } ++ } ++ ++ public static void register() { ++ MCTypeRegistry.ITEM_STACK.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ final MapType components = data.getMap("components"); ++ if (components == null) { ++ return null; ++ } ++ ++ convertLock(components, "minecraft:lock", "minecraft:lock"); ++ ++ return null; ++ } ++ }); ++ MCTypeRegistry.TILE_ENTITY.addStructureConverter(new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ convertLock(data, "Lock", "lock"); ++ return null; ++ } ++ }); ++ } ++ ++ private V4068() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4070.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4070.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4070.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++import ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry; ++import ca.spottedleaf.dataconverter.minecraft.walkers.itemstack.DataWalkerItemLists; ++ ++public final class V4070 { ++ ++ private static final int VERSION = MCVersions.V24W39A + 1; ++ ++ private static void registerChestBoat(final String id) { ++ MCTypeRegistry.ENTITY.addWalker(VERSION, id, new DataWalkerItemLists("Items")); ++ } ++ ++ public static void register() { ++ // minecraft:pale_oak_boat is a simple entity ++ ++ registerChestBoat("minecraft:pale_oak_chest_boat"); ++ } ++ ++ private V4070() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4071.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4071.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4071.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.dataconverter.minecraft.versions; ++ ++import ca.spottedleaf.dataconverter.minecraft.MCVersions; ++ ++public final class V4071 { ++ ++ private static final int VERSION = MCVersions.V24W39A + 2; ++ ++ private static void registerMob(final String id) { ++ V100.registerEquipment(VERSION, 0, id); ++ } ++ ++ public static void register() { ++ registerMob("minecraft:creaking"); ++ registerMob("minecraft:creaking_transient"); ++ ++ // minecraft:creaking_heart is a simple tile entity? not sure what the difference is between remainder and optional ++ } ++ ++ private V4071() {} ++} +diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4081.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4081.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/versions/V4081.java +@@ -0,0 +0,0 @@ ++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 V4081 { ++ ++ private static final int VERSION = MCVersions.V1_21_2 + 1; ++ ++ public static void register() { ++ MCTypeRegistry.ENTITY.addConverterForId("minecraft:salmon", new DataConverter<>(VERSION) { ++ @Override ++ public MapType convert(final MapType data, final long sourceVersion, final long toVersion) { ++ if ("large".equals(data.getString("type"))) { ++ return null; ++ } ++ ++ data.setString("type", "medium"); ++ return null; ++ } ++ }); ++ } ++ ++ private V4081() {} ++} 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..0000000000000000000000000000000000000000 @@ -28156,6 +29023,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import net.minecraft.commands.arguments.ComponentArgument; +import net.minecraft.commands.arguments.CompoundTagArgument; +import net.minecraft.commands.arguments.ResourceLocationArgument; ++import net.minecraft.commands.arguments.blocks.BlockStateArgument; +import net.minecraft.commands.arguments.coordinates.Vec3Argument; +import net.minecraft.commands.arguments.item.ItemArgument; +import net.minecraft.core.Holder; @@ -28186,6 +29054,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return new CommandArgumentUpgrader(functionPermissionLevel, builder -> { + builder.registerReplacement(ItemArgument.class, (argument, ctx) -> new ItemParser_1_20_4()); + builder.registerReplacement(ComponentArgument.class, (argument, ctx) -> new ComponentParser_1_20_4()); ++ builder.registerReplacement(BlockStateArgument.class, (argument, ctx) -> new BlockStateParser_1_20_4()); + builder.registerExtraCommand(CommandArgumentUpgrader::registerSummon_1_20_4_to_1_20_5); + }); + } @@ -28367,6 +29236,105 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + ++ private static class BlockStateParser_1_20_4 implements ArgumentType { ++ @Override ++ public UpgradedArgument parse(final StringReader reader) throws CommandSyntaxException { ++ String block = ResourceLocation.read(reader).toString(); ++ ++ StringBuilder properties = new StringBuilder(); ++ if (reader.canRead() && reader.peek() == '[') { ++ char c; ++ do { ++ c = reader.read(); ++ properties.append(c); ++ } while (reader.canRead() && c != ']'); ++ } ++ ++ if (!reader.canRead() || reader.peek() != '{') { ++ return new UpgradedArgument(block + properties); ++ } ++ ++ CompoundTag tag = new TagParser(reader).readStruct(); ++ boolean missId = !tag.contains("id", Tag.TAG_STRING); ++ if (missId) { // Data converter can't upgrade tile entities without it ++ tag.putString("id", CommandArgumentUpgrader.blockToTileEntity(block)); ++ } ++ tag = MCDataConverter.convertTag( ++ MCTypeRegistry.TILE_ENTITY, tag, MCVersions.V1_20_4, SharedConstants.getCurrentVersion().getDataVersion().getVersion() ++ ); ++ if (missId) { ++ tag.remove("id"); ++ } ++ ++ return new UpgradedArgument(block + properties + tag); ++ } ++ } ++ ++ private static String blockToTileEntity(String block) { ++ return switch (block) { ++ case "minecraft:acacia_sign", "minecraft:jungle_wall_sign", "minecraft:oak_sign", ++ "minecraft:cherry_sign", "minecraft:birch_wall_sign", "minecraft:dark_oak_sign", ++ "minecraft:mangrove_wall_sign", "minecraft:cherry_wall_sign", "minecraft:jungle_sign", ++ "minecraft:mangrove_sign", "minecraft:spruce_wall_sign", "minecraft:crimson_sign", ++ "minecraft:oak_wall_sign", "minecraft:crimson_wall_sign", "minecraft:bamboo_sign", ++ "minecraft:warped_wall_sign", "minecraft:bamboo_wall_sign", "minecraft:acacia_wall_sign", ++ "minecraft:spruce_sign", "minecraft:warped_sign", "minecraft:dark_oak_wall_sign", ++ "minecraft:birch_sign" ++ -> "minecraft:sign"; ++ case "minecraft:acacia_hanging_sign", "minecraft:crimson_wall_hanging_sign", ++ "minecraft:jungle_wall_hanging_sign", "minecraft:dark_oak_wall_hanging_sign", ++ "minecraft:crimson_hanging_sign", "minecraft:bamboo_wall_hanging_sign", ++ "minecraft:bamboo_hanging_sign", "minecraft:oak_wall_hanging_sign", ++ "minecraft:cherry_wall_hanging_sign", "minecraft:warped_wall_hanging_sign", ++ "minecraft:birch_hanging_sign", "minecraft:mangrove_hanging_sign", ++ "minecraft:birch_wall_hanging_sign", "minecraft:jungle_hanging_sign", ++ "minecraft:cherry_hanging_sign", "minecraft:spruce_hanging_sign", ++ "minecraft:warped_hanging_sign", "minecraft:mangrove_wall_hanging_sign", ++ "minecraft:spruce_wall_hanging_sign", "minecraft:dark_oak_hanging_sign", ++ "minecraft:oak_hanging_sign", "minecraft:acacia_wall_hanging_sign" ++ -> "minecraft:hanging_sign"; ++ case "minecraft:spawner" -> "minecraft:mob_spawner"; ++ case "minecraft:moving_piston" -> "minecraft:piston"; ++ case "minecraft:skeleton_skull" , "minecraft:skeleton_wall_skull", "minecraft:player_wall_head", ++ "minecraft:creeper_wall_head", "minecraft:zombie_head", "minecraft:wither_skeleton_skull", ++ "minecraft:creeper_head", "minecraft:wither_skeleton_wall_skull", "minecraft:dragon_head", ++ "minecraft:piglin_wall_head", "minecraft:dragon_wall_head", "minecraft:player_head", ++ "minecraft:zombie_wall_head", "minecraft:piglin_head" ++ -> "minecraft:skull"; ++ case "minecraft:black_banner", "minecraft:orange_wall_banner", "minecraft:gray_wall_banner", ++ "minecraft:magenta_banner", "minecraft:red_banner", "minecraft:brown_wall_banner", ++ "minecraft:pink_banner", "minecraft:light_blue_banner", "minecraft:cyan_wall_banner", ++ "minecraft:purple_banner", "minecraft:brown_banner", "minecraft:light_gray_wall_banner", ++ "minecraft:black_wall_banner", "minecraft:gray_banner", "minecraft:yellow_wall_banner", ++ "minecraft:light_gray_banner", "minecraft:red_wall_banner", "minecraft:light_blue_wall_banner", ++ "minecraft:pink_wall_banner", "minecraft:white_banner", "minecraft:green_wall_banner", ++ "minecraft:white_wall_banner", "minecraft:magenta_wall_banner", "minecraft:green_banner", ++ "minecraft:orange_banner", "minecraft:blue_wall_banner", "minecraft:cyan_banner", ++ "minecraft:purple_wall_banner", "minecraft:lime_wall_banner", "minecraft:yellow_banner", ++ "minecraft:lime_banner", "minecraft:blue_banner" ++ -> "minecraft:banner"; ++ case "minecraft:repeating_command_block", "minecraft:chain_command_block" ++ -> "minecraft:command_block"; ++ case "minecraft:brown_shulker_box", "minecraft:light_blue_shulker_box", "minecraft:white_shulker_box", ++ "minecraft:green_shulker_box", "minecraft:black_shulker_box", "minecraft:lime_shulker_box", ++ "minecraft:pink_shulker_box", "minecraft:light_gray_shulker_box", "minecraft:magenta_shulker_box", ++ "minecraft:orange_shulker_box", "minecraft:purple_shulker_box", "minecraft:cyan_shulker_box", ++ "minecraft:yellow_shulker_box", "minecraft:red_shulker_box", "minecraft:blue_shulker_box", ++ "minecraft:gray_shulker_box" ++ -> "minecraft:shulker_box"; ++ case "minecraft:purple_bed", "minecraft:light_blue_bed", "minecraft:yellow_bed", ++ "minecraft:orange_bed", "minecraft:light_gray_bed", "minecraft:red_bed", ++ "minecraft:gray_bed", "minecraft:brown_bed", "minecraft:cyan_bed", "minecraft:magenta_bed", ++ "minecraft:green_bed", "minecraft:white_bed", "minecraft:black_bed", "minecraft:blue_bed", ++ "minecraft:pink_bed", "minecraft:lime_bed" ++ -> "minecraft:bed"; ++ case "minecraft:soul_campfire" -> "minecraft:campfire"; ++ case "minecraft:bee_nest" -> "minecraft:beehive"; ++ case "minecraft:suspicious_sand", "minecraft:suspicious_gravel" -> "minecraft:brushable_block"; ++ default -> block; ++ }; ++ } ++ + // important: leadingSlash should not just be the result of a startsWith on command, + // it should reflect whether the command use is in a place that will skip a leading slash when parsing + public String upgradeCommandArguments(final String command, final boolean leadingSlash) { @@ -28557,7 +29525,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + new HolderLookup.Provider() { + + @Override -+ public Stream>> listRegistries() { ++ public Stream>> listRegistryKeys() { + return Stream.of(); + } + @@ -29218,52 +30186,72 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return correct.equals(value) ? null : correct; + } +} -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/ChunkSystemConverters.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/ChunkSystemConverters.java +diff --git a/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/ChunkSystemConverters.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/ChunkSystemConverters.java -@@ -0,0 +0,0 @@ public final class ChunkSystemConverters { - public static CompoundTag convertPoiCompoundTag(final CompoundTag data, final ServerLevel world) { - final int dataVersion = getDataVersion(data, DEFAULT_POI_DATA_VERSION); - -- return DataFixTypes.POI_CHUNK.update(world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion()); -+ // Paper start - dataconverter -+ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( -+ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.POI_CHUNK, data, dataVersion, getCurrentVersion() -+ ); -+ // Paper end - dataconverter - } - - public static CompoundTag convertEntityChunkCompoundTag(final CompoundTag data, final ServerLevel world) { - final int dataVersion = getDataVersion(data, DEFAULT_ENTITY_CHUNK_DATA_VERSION); - -- return DataFixTypes.ENTITY_CHUNK.update(world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion()); -+ // Paper start - dataconverter -+ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( -+ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY_CHUNK, data, dataVersion, getCurrentVersion() -+ ); -+ // Paper end - dataconverter - } - - private ChunkSystemConverters() {} +--- a/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java ++++ b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java +@@ -0,0 +0,0 @@ public final class PaperHooks implements PlatformHooks { + @Override + public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt, + final int fromVersion, final int toVersion) { ++ // Paper start - optimise data conversion ++ if (type == net.minecraft.util.datafix.fixes.References.PLAYER) { ++ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( ++ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.PLAYER, nbt, fromVersion, toVersion ++ ); ++ } ++ if (type == net.minecraft.util.datafix.fixes.References.CHUNK) { ++ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( ++ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, nbt, fromVersion, toVersion ++ ); ++ } ++ if (type == net.minecraft.util.datafix.fixes.References.STRUCTURE) { ++ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( ++ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.STRUCTURE, nbt, fromVersion, toVersion ++ ); ++ } ++ if (type == net.minecraft.util.datafix.fixes.References.POI_CHUNK) { ++ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( ++ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.POI_CHUNK, nbt, fromVersion, toVersion ++ ); ++ } ++ if (type == net.minecraft.util.datafix.fixes.References.ENTITY_CHUNK) { ++ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( ++ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY_CHUNK, nbt, fromVersion, toVersion ++ ); ++ } ++ if (type == net.minecraft.util.datafix.fixes.References.ITEM_STACK) { ++ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( ++ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ITEM_STACK, nbt, fromVersion, toVersion ++ ); ++ } ++ if (type == net.minecraft.util.datafix.fixes.References.ENTITY || type == net.minecraft.util.datafix.fixes.References.ENTITY_TREE) { ++ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( ++ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY, nbt, fromVersion, toVersion ++ ); ++ } ++ // Paper end - optimise data conversion + return (CompoundTag)dataFixer.update( + type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion + ).getValue(); diff --git a/src/main/java/net/minecraft/data/structures/StructureUpdater.java b/src/main/java/net/minecraft/data/structures/StructureUpdater.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/data/structures/StructureUpdater.java +++ b/src/main/java/net/minecraft/data/structures/StructureUpdater.java @@ -0,0 +0,0 @@ public class StructureUpdater implements SnbtToNbt.Filter { - LOGGER.warn("SNBT Too old, do not forget to update: {} < {}: {}", i, 3937, name); + LOGGER.warn("SNBT Too old, do not forget to update: {} < {}: {}", i, 4053, name); } - CompoundTag compoundTag = DataFixTypes.STRUCTURE.updateToCurrentVersion(DataFixers.getDataFixer(), nbt, i); + CompoundTag compoundTag = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.STRUCTURE, nbt, i, net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion()); // Paper - structureTemplate.load(BuiltInRegistries.BLOCK.asLookup(), compoundTag); + structureTemplate.load(BuiltInRegistries.BLOCK, compoundTag); return structureTemplate.save(new CompoundTag()); } 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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 -@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable, ca.spottedleaf.moonrise.patc +@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable { } else { try { // CraftBukkit start @@ -29272,7 +30260,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 CompoundTag level = nbttagcompound.getCompound("Level"); if (level.getBoolean("TerrainPopulated") && !level.getBoolean("LightPopulated")) { ServerChunkCache cps = (generatoraccess == null) ? null : ((ServerLevel) generatoraccess).getChunkSource(); -@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable, ca.spottedleaf.moonrise.patc +@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable { // CraftBukkit end if (i < 1493) { @@ -29281,7 +30269,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) { LegacyStructureDataHandler persistentstructurelegacy = this.getLegacyStructureHandler(resourcekey, supplier); -@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable, ca.spottedleaf.moonrise.patc +@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable { // Spigot end ChunkStorage.injectDatafixingContext(nbttagcompound, resourcekey, optional); diff --git a/patches/server/fixup-Moonrise-optimisation-patches.patch b/patches/server/fixup-Moonrise-optimisation-patches.patch index 0aa1522c1e..d3492994ca 100644 --- a/patches/server/fixup-Moonrise-optimisation-patches.patch +++ b/patches/server/fixup-Moonrise-optimisation-patches.patch @@ -371,27 +371,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.SharedConstants; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; + import net.minecraft.server.level.ServerLevel; +-import net.minecraft.util.datafix.DataFixTypes; ++import net.minecraft.util.datafix.fixes.References; + + public final class ChunkSystemConverters { + @@ -0,0 +0,0 @@ public final class ChunkSystemConverters { public static CompoundTag convertPoiCompoundTag(final CompoundTag data, final ServerLevel world) { final int dataVersion = getDataVersion(data, DEFAULT_POI_DATA_VERSION); -- // Paper start - dataconverter -- return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( -- ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.POI_CHUNK, data, dataVersion, getCurrentVersion() -- ); -- // Paper end - dataconverter -+ return PlatformHooks.get().convertNBT(DataFixTypes.POI_CHUNK, world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion()); +- return DataFixTypes.POI_CHUNK.update(world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion()); ++ return PlatformHooks.get().convertNBT(References.POI_CHUNK, world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion()); } public static CompoundTag convertEntityChunkCompoundTag(final CompoundTag data, final ServerLevel world) { final int dataVersion = getDataVersion(data, DEFAULT_ENTITY_CHUNK_DATA_VERSION); -- // Paper start - dataconverter -- return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag( -- ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY_CHUNK, data, dataVersion, getCurrentVersion() -- ); -- // Paper end - dataconverter -+ return PlatformHooks.get().convertNBT(DataFixTypes.ENTITY_CHUNK, world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion()); +- return DataFixTypes.ENTITY_CHUNK.update(world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion()); ++ return PlatformHooks.get().convertNBT(References.ENTITY_CHUNK, world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion()); } private ChunkSystemConverters() {} @@ -3902,18 +3900,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } final ListTag entitiesTag = new ListTag(); -- final java.util.Map, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk - for (final Entity entity : entities) { -- // Paper start - Entity load/save limit per chunk -- final EntityType entityType = entity.getType(); -- final int saveLimit = world.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1); -- if (saveLimit > -1) { -- if (savedEntityCounts.getOrDefault(entityType, 0) >= saveLimit) { -- continue; -- } -- savedEntityCounts.merge(entityType, 1, Integer::sum); -- } -- // Paper end - Entity load/save limit per chunk + for (final Entity entity : PlatformHooks.get().modifySavedEntities(world, chunkPos.x, chunkPos.z, entities)) { CompoundTag compoundTag = new CompoundTag(); if (entity.save(compoundTag)) { @@ -3964,9 +3951,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - // Paper end - - private List getAllEntities() { +- private List getAllEntities() { ++ public List getAllEntities() { final int len = this.entities.size(); if (len == 0) { + return new ArrayList<>(); @@ -0,0 +0,0 @@ public final class ChunkEntitySlices { return false; } @@ -4426,15 +4415,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.player.connection.send(this.updateClientChunkRadius(sendViewDistance)); this.player.connection.send(this.updateClientSimulationDistance(tickViewDistance)); @@ -0,0 +0,0 @@ public final class RegionizedPlayerChunkLoader { + // now all tickets should be removed, which is all of our external state } - -- // For external checks -- public it.unimi.dsi.fastutil.longs.LongOpenHashSet getSentChunksRaw() { ++ + public LongOpenHashSet getSentChunksRaw() { - return this.sentChunks; - } ++ return this.sentChunks; ++ } } + } diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java @@ -6210,7 +6199,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 final ProtoChunk protoChunk = (ProtoChunk)this.fromChunk; chunk = new LevelChunk(this.world, protoChunk, (final LevelChunk unused) -> { - ChunkStatusTasks.postLoadProtoChunk(world, protoChunk.getEntities(), protoChunk.getPos()); // Paper - pass chunk pos -+ ChunkStatusTasks.postLoadProtoChunk(world, protoChunk.getEntities()); ++ PlatformHooks.get().postLoadProtoChunk(world, protoChunk); }); this.chunkHolder.replaceProtoChunk(new ImposterProtoChunk(chunk, false)); } @@ -10001,8 +9990,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/core/MappedRegistry.java +++ b/src/main/java/net/minecraft/core/MappedRegistry.java @@ -0,0 +0,0 @@ public class MappedRegistry implements WritableRegistry { - }; - private final Object tagAdditionLock = new Object(); + return this.getTags(); + } + // Paper start - fluid method optimisations + private void injectFluidRegister( @@ -10021,21 +10010,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this(key, lifecycle, false); } @@ -0,0 +0,0 @@ public class MappedRegistry implements WritableRegistry { - this.toId.put(value, i); - this.registrationInfos.put(key, info); - this.registryLifecycle = this.registryLifecycle.add(info.lifecycle()); -+ this.injectFluidRegister(key, value); // Paper - fluid method optimisations - return reference; + this.toId.put(value, i); + this.registrationInfos.put(key, info); + this.registryLifecycle = this.registryLifecycle.add(info.lifecycle()); ++ this.injectFluidRegister(key, value); // Paper - fluid method optimisations + return reference; + } } - diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop states = section.states; @@ -10289,7 +10278,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } } -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper end - optimise random ticking public void tickChunk(LevelChunk chunk, int randomTickSpeed) { @@ -10297,8 +10286,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ChunkPos chunkcoordintpair = chunk.getPos(); boolean flag = this.isRaining(); int j = chunkcoordintpair.getMinBlockX(); -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. - ProfilerFiller gameprofilerfiller = this.getProfiler(); +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + ProfilerFiller gameprofilerfiller = Profiler.get(); gameprofilerfiller.push("thunder"); - if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder @@ -10306,7 +10295,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockPos blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15)); if (this.isRainingAt(blockposition)) { -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe if (!this.paperConfig().environment.disableIceAndSnow) { // Paper - Option to disable ice and snow for (int l = 0; l < randomTickSpeed; ++l) { @@ -10935,11 +10924,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (collisionShape.isEmpty()) { + continue; + } ++ ++ final AABB toCollide = boundingBox.move(-(double)blockX, -(double)blockY, -(double)blockZ); - if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.voxelShapeIntersectNoEmpty(collisionShape, toCollide)) { - return true; -+ final AABB toCollide = boundingBox.move(-(double)blockX, -(double)blockY, -(double)blockZ); -+ + final AABB singleAABB = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)collisionShape).moonrise$getSingleAABBRepresentation(); + if (singleAABB != null) { + if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.voxelShapeIntersect(singleAABB, toCollide)) { @@ -10982,32 +10971,36 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - Vec3 vec3d = Vec3.ZERO; - int k1 = 0; - BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); -+ } - +- - for (int l1 = i; l1 < j; ++l1) { - for (int i2 = k; i2 < l; ++i2) { - for (int j2 = i1; j2 < j1; ++j2) { - blockposition_mutableblockposition.set(l1, i2, j2); - FluidState fluid = this.level().getFluidState(blockposition_mutableblockposition); -+ final AABB boundingBox = this.getBoundingBox().deflate(1.0E-3); - +- - if (fluid.is(tag)) { - double d2 = (double) ((float) i2 + fluid.getHeight(this.level(), blockposition_mutableblockposition)); -+ final Level world = this.level; -+ final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(world); - +- - if (d2 >= axisalignedbb.minY) { - flag1 = true; - d1 = Math.max(d2 - axisalignedbb.minY, d1); - if (flag) { - Vec3 vec3d1 = fluid.getFlow(this.level(), blockposition_mutableblockposition); -+ final int minBlockX = Mth.floor(boundingBox.minX); -+ final int minBlockY = Math.max((minSection << 4), Mth.floor(boundingBox.minY)); -+ final int minBlockZ = Mth.floor(boundingBox.minZ); - +- - if (d1 < 0.4D) { - vec3d1 = vec3d1.scale(d1); - } ++ } ++ ++ final AABB boundingBox = this.getBoundingBox().deflate(1.0E-3); ++ ++ final Level world = this.level; ++ final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(world); ++ ++ final int minBlockX = Mth.floor(boundingBox.minX); ++ final int minBlockY = Math.max((minSection << 4), Mth.floor(boundingBox.minY)); ++ final int minBlockZ = Mth.floor(boundingBox.minZ); ++ + // note: bounds are exclusive in Vanilla, so we subtract 1 - our loop expects bounds to be inclusive + final int maxBlockX = Mth.ceil(boundingBox.maxX) - 1; + final int maxBlockY = Math.min((ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxSection(world) << 4) | 15, Mth.ceil(boundingBox.maxY) - 1); @@ -11015,9 +11008,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + final boolean isPushable = this.isPushedByFluid(); + final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); - -- vec3d = vec3d.add(vec3d1); -- ++k1; ++ + Vec3 pushVector = Vec3.ZERO; + double totalPushes = 0.0; + double maxHeightDiff = 0.0; @@ -11037,7 +11028,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { + for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) { + final net.minecraft.world.level.chunk.LevelChunkSection[] sections = chunkSource.getChunk(currChunkX, currChunkZ, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, false).getSections(); -+ + +- vec3d = vec3d.add(vec3d1); +- ++k1; + // bound y + for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) { + final int sectionIdx = currChunkY - minSection; @@ -11066,10 +11059,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + if (fluidState.isEmpty() || !fluidState.is(fluid)) { + continue; - } -- // CraftBukkit start - store last lava contact location -- if (tag == FluidTags.LAVA) { -- this.lastLavaContact = blockposition_mutableblockposition.immutable(); ++ } + + mutablePos.set(currX | (currChunkX << 4), currY | (currChunkY << 4), currZ | (currChunkZ << 4)); + @@ -11085,7 +11075,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + if (!isPushable) { + continue; -+ } + } +- // CraftBukkit start - store last lava contact location +- if (tag == FluidTags.LAVA) { +- this.lastLavaContact = blockposition_mutableblockposition.immutable(); + + ++totalPushes; + @@ -11154,7 +11147,7 @@ diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager. index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage implements ca.spotted +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage im ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Accessing poi chunk off-main"); @@ -11164,7 +11157,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return ret == null ? Optional.empty() : ret.getSectionForVanilla(chunkY); } -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage implements ca.spotted +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage im public final void moonrise$onUnload(final long coordinate) { // Paper - rewrite chunk system final int chunkX = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(coordinate); final int chunkZ = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(coordinate); @@ -11180,7 +11173,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.updateDistanceTracking(sectionPos); } } -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage implements ca.spotted +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage im public final void moonrise$loadInPoiChunk(final ca.spottedleaf.moonrise.patches.chunk_system.level.poi.PoiChunk poiChunk) { final int chunkX = poiChunk.chunkX; final int chunkZ = poiChunk.chunkZ; @@ -11194,35 +11187,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 final PoiSection section = poiChunk.getSection(sectionY); if (section != null && !((ca.spottedleaf.moonrise.patches.chunk_system.level.poi.ChunkSystemPoiSection)section).moonrise$isEmpty()) { this.onSectionLoad(SectionPos.asLong(chunkX, sectionY, chunkZ)); -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage implements ca.spotted - - @Override - public final net.minecraft.nbt.CompoundTag moonrise$read(final int chunkX, final int chunkZ) throws java.io.IOException { -- if (!ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.isRegionFileThread()) { -- return ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.loadData( -- this.world, chunkX, chunkZ, ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.RegionFileType.POI_DATA, -- ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.getIOBlockingPriorityForCurrentThread() -- ); -- } -- return this.moonrise$getRegionStorage().read(new ChunkPos(chunkX, chunkZ)); -+ return ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.loadData( -+ this.world, chunkX, chunkZ, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionFileType.POI_DATA, -+ ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.getIOBlockingPriorityForCurrentThread() -+ ); - } - - @Override - public final void moonrise$write(final int chunkX, final int chunkZ, final net.minecraft.nbt.CompoundTag data) throws java.io.IOException { -- if (!ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.isRegionFileThread()) { -- ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.scheduleSave(this.world, chunkX, chunkZ, data, ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.RegionFileType.POI_DATA); -- return; -- } -- this.moonrise$getRegionStorage().write(new ChunkPos(chunkX, chunkZ), data); -+ ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.scheduleSave(this.world, chunkX, chunkZ, data, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionFileType.POI_DATA); - } - // Paper end - rewrite chunk system - -@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage implements ca.spotted +@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage im } public int sectionsToVillage(SectionPos pos) { @@ -11240,7 +11205,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java @@ -0,0 +0,0 @@ public class PoiSection implements ca.spottedleaf.moonrise.patches.chunk_system. - } + private boolean isValid; // Paper start - rewrite chunk system - private final Optional noAllocOptional = Optional.of((PoiSection)(Object)this);; @@ -11387,12 +11352,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - lastChunk = (LevelChunk)chunkSource.getChunk(newChunkX, newChunkZ, ChunkStatus.FULL, false); - } + final ChunkSource chunkSource = this.getChunkSource(); -+ + +- if (lastChunk == null) { + for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { + for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) { + final ChunkAccess chunk = chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, false); - -- if (lastChunk == null) { ++ + if (chunk == null) { continue; } @@ -11615,7 +11580,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl // Paper end - optimise random ticking - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config & Anti-Xray + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator) { // Paper - create paper world config + // Paper start - getblock optimisations - cache world height/sections + final DimensionType dimType = holder.value(); + this.minY = dimType.minY(); @@ -11628,6 +11593,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config this.generator = gen; +@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + if (slices == null) { + return new org.bukkit.entity.Entity[0]; + } +- return slices.getChunkEntities(); ++ ++ List ret = new java.util.ArrayList<>(); ++ for (Entity entity : slices.getAllEntities()) { ++ org.bukkit.entity.Entity bukkit = entity.getBukkitEntity(); ++ if (bukkit != null && bukkit.isValid()) { ++ ret.add(bukkit); ++ } ++ } ++ ++ return ret.toArray(new org.bukkit.entity.Entity[0]); + } + // Paper end - rewrite chunk system + diff --git a/src/main/java/net/minecraft/world/level/biome/BiomeManager.java b/src/main/java/net/minecraft/world/level/biome/BiomeManager.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/biome/BiomeManager.java @@ -11647,7 +11630,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java @@ -0,0 +0,0 @@ public abstract class BlockBehaviour implements FeatureElement { - private boolean isRandomlyTicking; + private int lightBlock; // Paper start - rewrite chunk system - private int opacityIfCached; @@ -11719,7 +11702,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected BlockStateBase(Block block, Reference2ObjectArrayMap, Comparable> propertyMap, MapCodec codec) { @@ -0,0 +0,0 @@ public abstract class BlockBehaviour implements FeatureElement { - this.legacySolid = this.calculateSolid(); + this.lightBlock = ((Block) this.owner).getLightBlock(this.asState()); // Paper start - rewrite chunk system this.isConditionallyFullOpaque = this.canOcclude & this.useShapeForLightOcclusion; - this.opacityIfCached = this.cache == null || this.isConditionallyFullOpaque ? -1 : this.cache.lightBlock; @@ -11790,8 +11773,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }; protected final O owner; - private final Reference2ObjectArrayMap, Comparable> values; -+ private Reference2ObjectArrayMap, Comparable> values; // Paper - optimise blockstate property access - remove final - private Table, Comparable, S> neighbours; ++ private Reference2ObjectArrayMap, Comparable> values; // Paper - optimise blockstate property access - remove final + private Map, S[]> neighbours; protected final MapCodec propertiesCodec; + // Paper start - optimise blockstate property access @@ -11845,21 +11828,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public > Optional getOptionalValue(Property property) { @@ -0,0 +0,0 @@ public abstract class StateHolder { + + @Nullable + public > T getNullableValue(Property property) { +- Comparable comparable = this.values.get(property); +- return comparable == null ? null : property.getValueClass().cast(comparable); ++ return property == null ? null : this.optimisedTable.get(this.tableIndex, property); // Paper - optimise blockstate property access } public , V extends T> S setValue(Property property, V value) { - Comparable comparable = this.values.get(property); - if (comparable == null) { - throw new IllegalArgumentException("Cannot set property " + property + " as it does not exist in " + this.owner); -- } else if (comparable.equals(value)) { -- return (S)this; - } else { -- S object = this.neighbours.get(property, value); -- if (object == null) { -- throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value"); -- } else { -- return object; -- } +- return this.setValueInternal(property, value, comparable); + // Paper start - optimise blockstate property access + final S ret = this.optimisedTable.set(this.tableIndex, property, value); + if (ret != null) { @@ -11871,19 +11853,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public , V extends T> S trySetValue(Property property, V value) { - Comparable comparable = this.values.get(property); -- if (comparable != null && !comparable.equals(value)) { -- S object = this.neighbours.get(property, value); -- if (object == null) { -- throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value"); -- } else { -- return object; -- } -- } else { -- return (S)this; +- return (S)(comparable == null ? this : this.setValueInternal(property, value, comparable)); + // Paper start - optimise blockstate property access + if (property == null) { + return (S)(StateHolder)(Object)this; - } ++ } + final S ret = this.optimisedTable.trySet(this.tableIndex, property, value, (S)(StateHolder)(Object)this); + if (ret != null) { + return ret; @@ -11892,33 +11866,44 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - optimise blockstate property access } + private , V extends T> S setValueInternal(Property property, V newValue, Comparable oldValue) { +@@ -0,0 +0,0 @@ public abstract class StateHolder { + } + public void populateNeighbours(Map, Comparable>, S> states) { +- if (this.neighbours != null) { +- throw new IllegalStateException(); +- } else { +- Map, S[]> map = new Reference2ObjectArrayMap<>(this.values.size()); + // Paper start - optimise blockstate property access + final Map, Comparable>, S> map = states; -+ if (true) { -+ if (this.optimisedTable.isLoaded()) { -+ return; -+ } -+ this.optimisedTable.loadInTable(map); -+ -+ // de-duplicate the tables -+ for (final Map.Entry, Comparable>, S> entry : map.entrySet()) { -+ final S value = entry.getValue(); -+ ((StateHolder)value).optimisedTable = this.optimisedTable; -+ } -+ -+ // remove values arrays -+ for (final Map.Entry, Comparable>, S> entry : map.entrySet()) { -+ final S value = entry.getValue(); -+ ((StateHolder)value).values = null; -+ } -+ ++ if (this.optimisedTable.isLoaded()) { + return; + } -+ // Paper end - optimise blockstate property access - if (this.neighbours != null) { - throw new IllegalStateException(); - } else { ++ this.optimisedTable.loadInTable(map); + +- for (Entry, Comparable> entry : this.values.entrySet()) { +- Property property = entry.getKey(); +- map.put(property, property.getPossibleValues().stream().map(value -> states.get(this.makeNeighbourValues(property, value))).toArray()); +- } ++ // de-duplicate the tables ++ for (final Map.Entry, Comparable>, S> entry : map.entrySet()) { ++ final S value = entry.getValue(); ++ ((StateHolder)value).optimisedTable = this.optimisedTable; ++ } + +- this.neighbours = map; ++ // remove values arrays ++ for (final Map.Entry, Comparable>, S> entry : map.entrySet()) { ++ final S value = entry.getValue(); ++ ((StateHolder)value).values = null; + } ++ ++ return; ++ // Paper end optimise blockstate property access + } + + private Map, Comparable> makeNeighbourValues(Property property, Comparable value) { @@ -0,0 +0,0 @@ public abstract class StateHolder { } @@ -11936,13 +11921,15 @@ diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/Bool index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java +++ b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -@@ -0,0 +0,0 @@ import com.google.common.collect.ImmutableSet; - import java.util.Collection; +@@ -0,0 +0,0 @@ package net.minecraft.world.level.block.state.properties; + import java.util.List; import java.util.Optional; --public class BooleanProperty extends Property { -+public class BooleanProperty extends Property implements ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess { // Paper - optimise blockstate property access - private final ImmutableSet values = ImmutableSet.of(true, false); +-public final class BooleanProperty extends Property { ++public final class BooleanProperty extends Property implements ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess { // Paper - optimise blockstate property access + private static final List VALUES = List.of(true, false); + private static final int TRUE_INDEX = 0; + private static final int FALSE_INDEX = 1; + // Paper start - optimise blockstate property access + private static final Boolean[] BY_ID = new Boolean[]{ Boolean.FALSE, Boolean.TRUE }; @@ -11953,7 +11940,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - optimise blockstate property access + - protected BooleanProperty(String name) { + private BooleanProperty(String name) { super(name, Boolean.class); + this.moonrise$setById(BY_ID); // Paper - optimise blockstate property access } @@ -11967,10 +11954,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import java.util.stream.Collectors; import net.minecraft.util.StringRepresentable; --public class EnumProperty & StringRepresentable> extends Property { -+public class EnumProperty & StringRepresentable> extends Property implements ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess { // Paper - optimise blockstate property access - private final ImmutableSet values; - private final Map names = Maps.newHashMap(); +-public final class EnumProperty & StringRepresentable> extends Property { ++public final class EnumProperty & StringRepresentable> extends Property implements ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess { // Paper - optimise blockstate property access + private final List values; + private final Map names; + private final int[] ordinalToIndex; + // Paper start - optimise blockstate property access + private int[] idLookupTable; @@ -11982,7 +11970,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + private void init() { -+ final Collection values = this.getPossibleValues(); ++ final java.util.Collection values = this.getPossibleValues(); + final Class clazz = this.getValueClass(); + + int id = 0; @@ -12000,12 +11988,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - optimise blockstate property access + - protected EnumProperty(String name, Class type, Collection values) { + private EnumProperty(String name, Class type, List values) { super(name, type); - this.values = ImmutableSet.copyOf(values); -@@ -0,0 +0,0 @@ public class EnumProperty & StringRepresentable> extends Prope + if (values.isEmpty()) { +@@ -0,0 +0,0 @@ public final class EnumProperty & StringRepresentable> extends - this.names.put(string, enum_); + this.names = builder.buildOrThrow(); } + this.init(); // Paper - optimise blockstate property access } @@ -12015,13 +12003,13 @@ diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/Inte index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java +++ b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -@@ -0,0 +0,0 @@ import java.util.Collection; +@@ -0,0 +0,0 @@ import java.util.List; import java.util.Optional; - import java.util.Set; + import java.util.stream.IntStream; --public class IntegerProperty extends Property { -+public class IntegerProperty extends Property implements ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess { // Paper - optimise blockstate property access - private final ImmutableSet values; +-public final class IntegerProperty extends Property { ++public final class IntegerProperty extends Property implements ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.PropertyAccess { // Paper - optimise blockstate property access + private final IntImmutableList values; public final int min; public final int max; @@ -12047,12 +12035,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - optimise blockstate property access + - protected IntegerProperty(String name, int min, int max) { + private IntegerProperty(String name, int min, int max) { super(name, Integer.class); if (min < 0) { -@@ -0,0 +0,0 @@ public class IntegerProperty extends Property { - - this.values = ImmutableSet.copyOf(set); +@@ -0,0 +0,0 @@ public final class IntegerProperty extends Property { + this.max = max; + this.values = IntImmutableList.toList(IntStream.range(min, max + 1)); } + this.init(); // Paper - optimise blockstate property access } @@ -12148,12 +12136,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 static final Logger LOGGER = LogUtils.getLogger(); private static final TickingBlockEntity NULL_TICKER = new TickingBlockEntity() { +@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + */ + org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); + server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration)); +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(this.locX, this.locZ).getEntityChunk().callEntitiesLoadEvent(); // Paper - rewrite chunk system ++ org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesLoadEvent(this.level, this.chunkPos, ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(this.locX, this.locZ).getEntityChunk().getAllEntities()); // Paper - rewrite chunk system + + if (this.needsDecoration) { + try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper +@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + public void unloadCallback() { + if (!this.loadedTicketLevel) { LOGGER.error("Double calling chunk unload!", new Throwable()); } // Paper + org.bukkit.Server server = this.level.getCraftServer(); +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(this.locX, this.locZ).getEntityChunk().callEntitiesUnloadEvent(); // Paper - rewrite chunk system ++ org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(this.level, this.chunkPos, ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(this.locX, this.locZ).getEntityChunk().getAllEntities()); // Paper - rewrite chunk system + org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); + org.bukkit.event.world.ChunkUnloadEvent unloadEvent = new org.bukkit.event.world.ChunkUnloadEvent(bukkitChunk, true); // Paper - rewrite chunk system - force save to true so that mustNotSave is correctly set below + server.getPluginManager().callEvent(unloadEvent); diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java @@ -0,0 +0,0 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ - private PalettedContainer> biomes; + private PalettedContainer> biomes; // CraftBukkit - read/write // Paper start - block counting - private static final it.unimi.dsi.fastutil.ints.IntArrayList FULL_LIST = new it.unimi.dsi.fastutil.ints.IntArrayList(16*16*16); @@ -12384,7 +12390,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java +++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java @@ -0,0 +0,0 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - // this.threadingDetector.checkAndUnlock(); // Paper - disable this + ); } + // Paper start - optimise palette reads @@ -12414,25 +12420,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - optimise palette reads + - // Paper start - Anti-Xray - Add preset values - @Deprecated @io.papermc.paper.annotation.DoNotUse public static Codec> codecRW(IdMap idList, Codec entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) { return PalettedContainer.codecRW(idList, entryCodec, paletteProvider, defaultValue, null); } - public static Codec> codecRW(IdMap idList, Codec entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues) { + public PalettedContainer( + IdMap idList, + PalettedContainer.Strategy paletteProvider, @@ -0,0 +0,0 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - } - } - // Paper end + this.registry = idList; + this.strategy = paletteProvider; + this.data = new PalettedContainer.Data<>(dataProvider, storage, dataProvider.factory().create(dataProvider.bits(), idList, this, paletteEntries)); + this.updateData(this.data); // Paper - optimise palette reads } - // Paper start - Anti-Xray - Add preset values -@@ -0,0 +0,0 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + private PalettedContainer(IdMap idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Data data) { this.registry = idList; this.strategy = paletteProvider; this.data = data; + this.updateData(this.data); // Paper - optimise palette reads } - // Paper start - Anti-Xray - Add preset values + private PalettedContainer(PalettedContainer container) { @@ -0,0 +0,0 @@ public class PalettedContainer implements PaletteResize, PalettedContainer this.registry = idList; this.data = this.createOrReuseData(null, 0); @@ -12446,9 +12451,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 data2.copyFrom(data.palette, data.storage); this.data = data2; + this.updateData(this.data); // Paper - optimise palette reads - this.addPresetValues(); - return object == null ? -1 : data2.palette.idFor(object); - // Paper end + return data2.palette.idFor(object); + } + @@ -0,0 +0,0 @@ public class PalettedContainer implements PaletteResize, PalettedContainer } @@ -12483,9 +12488,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 buf.readLongArray(data.storage.getRaw()); this.data = data; + this.updateData(this.data); // Paper - optimise palette reads - this.addPresetValues(); // Paper - Anti-Xray - Add preset values (inefficient, but this isn't used by the server) } finally { this.release(); + } @@ -0,0 +0,0 @@ public class PalettedContainer implements PaletteResize, PalettedContainer void accept(T object, int count); } @@ -12590,7 +12595,7 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.ja index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -0,0 +0,0 @@ import net.minecraft.nbt.NbtIo; // Paper +@@ -0,0 +0,0 @@ import net.minecraft.util.profiling.jfr.JvmProfiler; import net.minecraft.world.level.ChunkPos; import org.slf4j.Logger; @@ -12600,12 +12605,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static final Logger LOGGER = LogUtils.getLogger(); private static final int SECTOR_BYTES = 4096; @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { - private final IntBuffer timestamps; @VisibleForTesting protected final RegionBitmap usedSectors; + + // Paper start - rewrite chunk system + @Override -+ public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(final CompoundTag data, final ChunkPos pos) throws IOException { ++ public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(final net.minecraft.nbt.CompoundTag data, final ChunkPos pos) throws IOException { + final RegionFile.ChunkBuffer buffer = ((RegionFile)(Object)this).new ChunkBuffer(pos); + ((ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemChunkBuffer)buffer).moonrise$setWriteOnClose(false); + @@ -12617,9 +12622,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ); + } + // Paper end - rewrite chunk system - // Paper start - Attempt to recalculate regionfile header if it is corrupt - private static long roundToSectors(long bytes) { - long sectors = bytes >>> 12; // 4096 = 2^12 ++ + public RegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { + this(storageKey, directory, path, RegionFileVersion.getSelected(), dsync); + } @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { @Nullable @@ -12638,9 +12644,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!Files.isRegularFile(path, new LinkOption[0])) { @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { - } - // Paper end + + public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails - private class ChunkBuffer extends ByteArrayOutputStream { + private class ChunkBuffer extends ByteArrayOutputStream implements ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemChunkBuffer { // Paper - rewrite chunk system @@ -12788,10 +12794,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } // Paper end - rewrite chunk system - // Paper start - recalculate region file headers - private final boolean isChunkData; + + protected RegionFileStorage(RegionStorageInfo storageKey, Path directory, boolean dsync) { // Paper - protected @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers + this.info = storageKey; } + // Paper start - rewrite chunk system @@ -12860,8 +12866,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -- private boolean canPassThroughWall(Direction face, BlockGetter world, BlockPos pos, BlockState state, BlockPos fromPos, BlockState fromState) { -- Object2ByteLinkedOpenHashMap object2bytelinkedopenhashmap; +- private static boolean canPassThroughWall(Direction face, BlockGetter world, BlockPos pos, BlockState state, BlockPos fromPos, BlockState fromState) { +- VoxelShape voxelshape = fromState.getCollisionShape(world, fromPos); + // Paper start - fluid method optimisations + private static boolean canPassThroughWall(final Direction direction, final BlockGetter level, + final BlockPos fromPos, final BlockState fromState, @@ -12871,56 +12877,71 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return true; + } -- if (!state.getBlock().hasDynamicShape() && !fromState.getBlock().hasDynamicShape()) { -- object2bytelinkedopenhashmap = (Object2ByteLinkedOpenHashMap) FlowingFluid.OCCLUSION_CACHE.get(); -- } else { -- object2bytelinkedopenhashmap = null; +- if (voxelshape == Shapes.block()) { + if (((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)fromState).moonrise$occludesFullBlock() | ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)toState).moonrise$occludesFullBlock()) { + // don't even try to cache simple cases -+ return false; - } + return false; +- } else { +- VoxelShape voxelshape1 = state.getCollisionShape(world, pos); +- +- if (voxelshape1 == Shapes.block()) { +- return false; +- } else if (voxelshape1 == Shapes.empty() && voxelshape == Shapes.empty()) { +- return true; +- } else { +- Object2ByteLinkedOpenHashMap object2bytelinkedopenhashmap; +- +- if (!state.getBlock().hasDynamicShape() && !fromState.getBlock().hasDynamicShape()) { +- object2bytelinkedopenhashmap = (Object2ByteLinkedOpenHashMap) FlowingFluid.OCCLUSION_CACHE.get(); +- } else { +- object2bytelinkedopenhashmap = null; +- } ++ } -- Block.BlockStatePairKey block_a; +- FlowingFluid.BlockStatePairKey fluidtypeflowing_a; + final ca.spottedleaf.moonrise.patches.collisions.util.FluidOcclusionCacheKey[] cache = ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)fromState).moonrise$hasCache() & ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)toState).moonrise$hasCache() ? + COLLISION_OCCLUSION_CACHE.get() : null; -- if (object2bytelinkedopenhashmap != null) { -- block_a = new Block.BlockStatePairKey(state, fromState, face); -- byte b0 = object2bytelinkedopenhashmap.getAndMoveToFirst(block_a); +- if (object2bytelinkedopenhashmap != null) { +- fluidtypeflowing_a = new FlowingFluid.BlockStatePairKey(state, fromState, face); +- byte b0 = object2bytelinkedopenhashmap.getAndMoveToFirst(fluidtypeflowing_a); + final int keyIndex + = (((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)fromState).moonrise$uniqueId1() ^ ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)toState).moonrise$uniqueId2() ^ ((ca.spottedleaf.moonrise.patches.collisions.util.CollisionDirection)(Object)direction).moonrise$uniqueId()) + & (COLLISION_OCCLUSION_CACHE_SIZE - 1); -- if (b0 != 127) { -- return b0 != 0; +- if (b0 != 127) { +- return b0 != 0; +- } +- } else { +- fluidtypeflowing_a = null; +- } +- +- boolean flag = !Shapes.mergedFaceOccludes(voxelshape1, voxelshape, face); + if (cache != null) { + final ca.spottedleaf.moonrise.patches.collisions.util.FluidOcclusionCacheKey cached = cache[keyIndex]; + if (cached != null && cached.first() == fromState && cached.second() == toState && cached.direction() == direction) { + return cached.result(); - } -- } else { -- block_a = null; - } ++ } ++ } -- VoxelShape voxelshape = state.getCollisionShape(world, pos); -- VoxelShape voxelshape1 = fromState.getCollisionShape(world, fromPos); -- boolean flag = !Shapes.mergedFaceOccludes(voxelshape, voxelshape1, face); +- if (object2bytelinkedopenhashmap != null) { +- if (object2bytelinkedopenhashmap.size() == 200) { +- object2bytelinkedopenhashmap.removeLastByte(); +- } + final VoxelShape shape1 = fromState.getCollisionShape(level, fromPos); + final VoxelShape shape2 = toState.getCollisionShape(level, toPos); -- if (object2bytelinkedopenhashmap != null) { -- if (object2bytelinkedopenhashmap.size() == 200) { -- object2bytelinkedopenhashmap.removeLastByte(); -- } +- object2bytelinkedopenhashmap.putAndMoveToFirst(fluidtypeflowing_a, (byte) (flag ? 1 : 0)); +- } + final boolean result = !Shapes.mergedFaceOccludes(shape1, shape2, direction); -- object2bytelinkedopenhashmap.putAndMoveToFirst(block_a, (byte) (flag ? 1 : 0)); +- return flag; +- } + if (cache != null) { + // we can afford to replace in-use keys more often due to the excessive caching the collision patch does in mergedFaceOccludes + cache[keyIndex] = new ca.spottedleaf.moonrise.patches.collisions.util.FluidOcclusionCacheKey(fromState, toState, direction, result); } - -- return flag; ++ + return result; } + // Paper end - fluid method optimisations @@ -12951,7 +12972,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - fluid method optimisations } - protected abstract boolean canConvertToSource(Level world); + protected abstract boolean canConvertToSource(ServerLevel world); diff --git a/src/main/java/net/minecraft/world/level/material/FluidState.java b/src/main/java/net/minecraft/world/level/material/FluidState.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/material/FluidState.java @@ -13024,7 +13045,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.isRandomlyTicking; // Paper - fluid method optimisations } - public void randomTick(Level world, BlockPos pos, RandomSource random) { + public void randomTick(ServerLevel world, BlockPos pos, RandomSource random) { @@ -0,0 +0,0 @@ public final class FluidState extends StateHolder { } @@ -13072,30 +13093,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end - optimise collisions } -@@ -0,0 +0,0 @@ public final class Shapes { - } - - public static VoxelShape getFaceShape(VoxelShape shape, Direction direction) { -- return ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)shape).moonrise$getFaceShapeClamped(direction); // Paper - optimise collisions -+ if (shape == block()) { -+ return block(); -+ } else { -+ Direction.Axis axis = direction.getAxis(); -+ boolean bl; -+ int i; -+ if (direction.getAxisDirection() == Direction.AxisDirection.POSITIVE) { -+ bl = DoubleMath.fuzzyEquals(shape.max(axis), 1.0, 1.0E-7); -+ i = shape.shape.getSize(axis) - 1; -+ } else { -+ bl = DoubleMath.fuzzyEquals(shape.min(axis), 0.0, 1.0E-7); -+ i = 0; -+ } -+ -+ return (VoxelShape)(!bl ? empty() : new SliceShape(shape, axis, i)); -+ } - } - - // Paper start - optimise collisions diff --git a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java @@ -13314,19 +13311,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return AABB.clip(((VoxelShape)(Object)this).toAabbs(), from, to, offset); @@ -0,0 +0,0 @@ public abstract class VoxelShape implements ca.spottedleaf.moonrise.patches.coll + } } - private VoxelShape calculateFace(Direction direction) { -- Direction.Axis axis = direction.getAxis(); -- DoubleList doubleList = this.getCoords(axis); -- if (doubleList.size() == 2 -- && DoubleMath.fuzzyEquals(doubleList.getDouble(0), 0.0, 1.0E-7) -- && DoubleMath.fuzzyEquals(doubleList.getDouble(1), 1.0, 1.0E-7)) { +- private VoxelShape calculateFace(Direction facing) { +- Direction.Axis axis = facing.getAxis(); +- if (this.isCubeLikeAlong(axis)) { - return this; - } else { -- Direction.AxisDirection axisDirection = direction.getAxisDirection(); +- Direction.AxisDirection axisDirection = facing.getAxisDirection(); - int i = this.findIndex(axis, axisDirection == Direction.AxisDirection.POSITIVE ? 0.9999999 : 1.0E-7); -- return new SliceShape(this, axis, i); +- SliceShape sliceShape = new SliceShape(this, axis, i); +- if (sliceShape.isEmpty()) { +- return Shapes.empty(); +- } else { +- return (VoxelShape)(sliceShape.isCubeLike() ? Shapes.block() : sliceShape); ++ private VoxelShape calculateFace(Direction direction) { + // Paper start - optimise collisions + final Direction.Axis axis = direction.getAxis(); + switch (axis) { @@ -13341,9 +13341,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + default: { + throw new IllegalStateException("Unknown axis: " + axis); -+ } + } } + // Paper end - optimise collisions } - // Paper start - optimise collisions + protected boolean isCubeLike() { diff --git a/patches/server/fixup-Paper-config-files.patch b/patches/server/fixup-Paper-config-files.patch new file mode 100644 index 0000000000..fd60eec905 --- /dev/null +++ b/patches/server/fixup-Paper-config-files.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Thu, 24 Oct 2024 08:11:12 -0700 +Subject: [PATCH] fixup! Paper config files + + +diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java ++++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +@@ -0,0 +0,0 @@ public class GlobalConfiguration extends ConfigurationPart { + public static GlobalConfiguration get() { + return instance; + } ++ ++ public ChunkLoadingBasic chunkLoadingBasic; ++ ++ public class ChunkLoadingBasic extends ConfigurationPart { ++ @Comment("The maximum rate in chunks per second that the server will send to any individual player. Set to -1 to disable this limit.") ++ public double playerMaxChunkSendRate = 75.0; ++ ++ @Comment( ++ "The maximum rate at which chunks will load for any individual player. " + ++ "Note that this setting also affects chunk generations, since a chunk load is always first issued to test if a" + ++ "chunk is already generated. Set to -1 to disable this limit." ++ ) ++ public double playerMaxChunkLoadRate = 100.0; ++ ++ @Comment("The maximum rate at which chunks will generate for any individual player. Set to -1 to disable this limit.") ++ public double playerMaxChunkGenerateRate = -1.0; ++ } ++ ++ public ChunkLoadingAdvanced chunkLoadingAdvanced; ++ ++ public class ChunkLoadingAdvanced extends ConfigurationPart { ++ @Comment( ++ "Set to true if the server will match the chunk send radius that clients have configured" + ++ "in their view distance settings if the client is less-than the server's send distance." ++ ) ++ public boolean autoConfigSendDistance = true; ++ ++ @Comment( ++ "Specifies the maximum amount of concurrent chunk loads that an individual player can have." + ++ "Set to 0 to let the server configure it automatically per player, or set it to -1 to disable the limit." ++ ) ++ public int playerMaxConcurrentChunkLoads = 0; ++ ++ @Comment( ++ "Specifies the maximum amount of concurrent chunk generations that an individual player can have." + ++ "Set to 0 to let the server configure it automatically per player, or set it to -1 to disable the limit." ++ ) ++ public int playerMaxConcurrentChunkGenerates = 0; ++ } + static void set(GlobalConfiguration instance) { + GlobalConfiguration.instance = instance; + } +@@ -0,0 +0,0 @@ public class GlobalConfiguration extends ConfigurationPart { + public int incomingPacketThreshold = 300; + } + +- public ChunkLoading chunkLoading; +- +- public class ChunkLoading extends ConfigurationPart { +- public int minLoadRadius = 2; +- public int maxConcurrentSends = 2; +- public boolean autoconfigSendDistance = true; +- public double targetPlayerChunkSendRate = 100.0; +- public double globalMaxChunkSendRate = -1.0; +- public boolean enableFrustumPriority = false; +- public double globalMaxChunkLoadRate = -1.0; +- public double playerMaxConcurrentLoads = 20.0; +- public double globalMaxConcurrentLoads = 500.0; +- public double playerMaxChunkLoadRate = -1.0; +- } +- + public UnsupportedSettings unsupportedSettings; + + public class UnsupportedSettings extends ConfigurationPart { +@@ -0,0 +0,0 @@ public class GlobalConfiguration extends ConfigurationPart { + + @PostProcess + private void postProcess() { +- //io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.init(this); ++ ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.init(this); + } + } + diff --git a/patches/unapplied/server/Custom-table-implementation-for-blockstate-state-loo.patch b/patches/unapplied/server/Custom-table-implementation-for-blockstate-state-loo.patch deleted file mode 100644 index 80c373202c..0000000000 --- a/patches/unapplied/server/Custom-table-implementation-for-blockstate-state-loo.patch +++ /dev/null @@ -1,343 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Thu, 11 Mar 2021 20:05:44 -0800 -Subject: [PATCH] Custom table implementation for blockstate state lookups - -Testing some redstone intensive machines showed to bring about a 10% -improvement. - -diff --git a/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java b/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java -@@ -0,0 +0,0 @@ -+package io.papermc.paper.util.table; -+ -+import com.google.common.collect.Table; -+import net.minecraft.world.level.block.state.StateHolder; -+import net.minecraft.world.level.block.state.properties.Property; -+import java.util.Collection; -+import java.util.HashSet; -+import java.util.Map; -+import java.util.Set; -+ -+public final class ZeroCollidingReferenceStateTable { -+ -+ // upper 32 bits: starting index -+ // lower 32 bits: bitset for contained ids -+ protected final long[] this_index_table; -+ protected final Comparable[] this_table; -+ protected final StateHolder this_state; -+ -+ protected long[] index_table; -+ protected StateHolder[][] value_table; -+ -+ public ZeroCollidingReferenceStateTable(final StateHolder state, final Map, Comparable> this_map) { -+ this.this_state = state; -+ this.this_index_table = this.create_table(this_map.keySet()); -+ -+ int max_id = -1; -+ for (final Property property : this_map.keySet()) { -+ final int id = lookup_vindex(property, this.this_index_table); -+ if (id > max_id) { -+ max_id = id; -+ } -+ } -+ -+ this.this_table = new Comparable[max_id + 1]; -+ for (final Map.Entry, Comparable> entry : this_map.entrySet()) { -+ this.this_table[lookup_vindex(entry.getKey(), this.this_index_table)] = entry.getValue(); -+ } -+ } -+ -+ public void loadInTable(final Table, Comparable, StateHolder> table, -+ final Map, Comparable> this_map) { -+ final Set> combined = new HashSet<>(table.rowKeySet()); -+ combined.addAll(this_map.keySet()); -+ -+ this.index_table = this.create_table(combined); -+ -+ int max_id = -1; -+ for (final Property property : combined) { -+ final int id = lookup_vindex(property, this.index_table); -+ if (id > max_id) { -+ max_id = id; -+ } -+ } -+ -+ this.value_table = new StateHolder[max_id + 1][]; -+ -+ final Map, Map, StateHolder>> map = table.rowMap(); -+ for (final Property property : map.keySet()) { -+ final Map, StateHolder> propertyMap = map.get(property); -+ -+ final int id = lookup_vindex(property, this.index_table); -+ final StateHolder[] states = this.value_table[id] = new StateHolder[property.getPossibleValues().size()]; -+ -+ for (final Map.Entry, StateHolder> entry : propertyMap.entrySet()) { -+ if (entry.getValue() == null) { -+ // TODO what -+ continue; -+ } -+ -+ states[((Property)property).getIdFor(entry.getKey())] = entry.getValue(); -+ } -+ } -+ -+ -+ for (final Map.Entry, Comparable> entry : this_map.entrySet()) { -+ final Property property = entry.getKey(); -+ final int index = lookup_vindex(property, this.index_table); -+ -+ if (this.value_table[index] == null) { -+ this.value_table[index] = new StateHolder[property.getPossibleValues().size()]; -+ } -+ -+ this.value_table[index][((Property)property).getIdFor(entry.getValue())] = this.this_state; -+ } -+ } -+ -+ -+ protected long[] create_table(final Collection> collection) { -+ int max_id = -1; -+ for (final Property property : collection) { -+ final int id = property.getId(); -+ if (id > max_id) { -+ max_id = id; -+ } -+ } -+ -+ final long[] ret = new long[((max_id + 1) + 31) >>> 5]; // ceil((max_id + 1) / 32) -+ -+ for (final Property property : collection) { -+ final int id = property.getId(); -+ -+ ret[id >>> 5] |= (1L << (id & 31)); -+ } -+ -+ int total = 0; -+ for (int i = 1, len = ret.length; i < len; ++i) { -+ ret[i] |= (long)(total += Long.bitCount(ret[i - 1] & 0xFFFFFFFFL)) << 32; -+ } -+ -+ return ret; -+ } -+ -+ public Comparable get(final Property state) { -+ final Comparable[] table = this.this_table; -+ final int index = lookup_vindex(state, this.this_index_table); -+ -+ if (index < 0 || index >= table.length) { -+ return null; -+ } -+ return table[index]; -+ } -+ -+ public StateHolder get(final Property property, final Comparable with) { -+ final int withId = ((Property)property).getIdFor(with); -+ if (withId < 0) { -+ return null; -+ } -+ -+ final int index = lookup_vindex(property, this.index_table); -+ final StateHolder[][] table = this.value_table; -+ if (index < 0 || index >= table.length) { -+ return null; -+ } -+ -+ final StateHolder[] values = table[index]; -+ -+ if (withId >= values.length) { -+ return null; -+ } -+ -+ return values[withId]; -+ } -+ -+ protected static int lookup_vindex(final Property property, final long[] index_table) { -+ final int id = property.getId(); -+ final long bitset_mask = (1L << (id & 31)); -+ final long lower_mask = bitset_mask - 1; -+ final int index = id >>> 5; -+ if (index >= index_table.length) { -+ return -1; -+ } -+ final long index_value = index_table[index]; -+ final long contains_check = ((index_value & bitset_mask) - 1) >> (Long.SIZE - 1); // -1L if doesn't contain -+ -+ // index = total bits set in lower table values (upper 32 bits of index_value) plus total bits set in lower indices below id -+ // contains_check is 0 if the bitset had id set, else it's -1: so index is unaffected if contains_check == 0, -+ // otherwise it comes out as -1. -+ return (int)(((index_value >>> 32) + Long.bitCount(index_value & lower_mask)) | contains_check); -+ } -+} -diff --git a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java -+++ b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java -@@ -0,0 +0,0 @@ public abstract class StateHolder { - private final Reference2ObjectArrayMap, Comparable> values; - private Table, Comparable, S> neighbours; - protected final MapCodec propertiesCodec; -+ protected final io.papermc.paper.util.table.ZeroCollidingReferenceStateTable optimisedTable; // Paper - optimise state lookup - - protected StateHolder(O owner, Reference2ObjectArrayMap, Comparable> propertyMap, MapCodec codec) { - this.owner = owner; - this.values = propertyMap; - this.propertiesCodec = codec; -+ this.optimisedTable = new io.papermc.paper.util.table.ZeroCollidingReferenceStateTable(this, propertyMap); // Paper - optimise state lookup - } - - public > S cycle(Property property) { -@@ -0,0 +0,0 @@ public abstract class StateHolder { - } - - public > boolean hasProperty(Property property) { -- return this.values.containsKey(property); -+ return this.optimisedTable.get(property) != null; // Paper - optimise state lookup - } - - public > T getValue(Property property) { -- Comparable comparable = this.values.get(property); -+ Comparable comparable = this.optimisedTable.get(property); // Paper - optimise state lookup - if (comparable == null) { - throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner); - } else { -@@ -0,0 +0,0 @@ public abstract class StateHolder { - } - - public > Optional getOptionalValue(Property property) { -- Comparable comparable = this.values.get(property); -+ Comparable comparable = this.optimisedTable.get(property); // Paper - optimise state lookup - return comparable == null ? Optional.empty() : Optional.of(property.getValueClass().cast(comparable)); - } - - public , V extends T> S setValue(Property property, V value) { -- Comparable comparable = this.values.get(property); -- if (comparable == null) { -- throw new IllegalArgumentException("Cannot set property " + property + " as it does not exist in " + this.owner); -- } else if (comparable.equals(value)) { -- return (S)this; -- } else { -- S object = this.neighbours.get(property, value); -- if (object == null) { -- throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value"); -- } else { -- return object; -- } -+ // Paper start - optimise state lookup -+ final S ret = (S)this.optimisedTable.get(property, value); -+ if (ret == null) { -+ throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value"); - } -+ return ret; -+ // Paper end - optimise state lookup - } - - public , V extends T> S trySetValue(Property property, V value) { -@@ -0,0 +0,0 @@ public abstract class StateHolder { - } - } - -- this.neighbours = (Table, Comparable, S>)(table.isEmpty() ? table : ArrayTable.create(table)); -+ this.neighbours = (Table, Comparable, S>)(table.isEmpty() ? table : ArrayTable.create(table)); this.optimisedTable.loadInTable((Table)this.neighbours, this.values); // Paper - optimise state lookup - } - } - -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java -@@ -0,0 +0,0 @@ import java.util.Optional; - public class BooleanProperty extends Property { - private final ImmutableSet values = ImmutableSet.of(true, false); - -+ // Paper start - optimise iblockdata state lookup -+ @Override -+ public final int getIdFor(final Boolean value) { -+ return value.booleanValue() ? 1 : 0; -+ } -+ // Paper end - optimise iblockdata state lookup -+ - protected BooleanProperty(String name) { - super(name, Boolean.class); - } -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java -@@ -0,0 +0,0 @@ public class EnumProperty & StringRepresentable> extends Prope - private final ImmutableSet values; - private final Map names = Maps.newHashMap(); - -+ // Paper start - optimise iblockdata state lookup -+ private int[] idLookupTable; -+ -+ @Override -+ public final int getIdFor(final T value) { -+ return this.idLookupTable[value.ordinal()]; -+ } -+ // Paper end - optimise iblockdata state lookup -+ - protected EnumProperty(String name, Class type, Collection values) { - super(name, type); - this.values = ImmutableSet.copyOf(values); -@@ -0,0 +0,0 @@ public class EnumProperty & StringRepresentable> extends Prope - - this.names.put(string, enum_); - } -+ // Paper start - optimise BlockState lookup -+ int id = 0; -+ this.idLookupTable = new int[type.getEnumConstants().length]; -+ java.util.Arrays.fill(this.idLookupTable, -1); -+ for (final T value : this.getPossibleValues()) { -+ this.idLookupTable[value.ordinal()] = id++; -+ } -+ // Paper end - optimise BlockState lookup - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java -@@ -0,0 +0,0 @@ public class IntegerProperty extends Property { - public final int min; - public final int max; - -+ // Paper start - optimise iblockdata state lookup -+ @Override -+ public final int getIdFor(final Integer value) { -+ final int val = value.intValue(); -+ final int ret = val - this.min; -+ -+ return ret | ((this.max - ret) >> 31); -+ } -+ // Paper end - optimise iblockdata state lookup -+ - protected IntegerProperty(String name, int min, int max) { - super(name, Integer.class); - if (min < 0) { -diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java -+++ b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java -@@ -0,0 +0,0 @@ public abstract class Property> { - ); - private final Codec> valueCodec = this.codec.xmap(this::value, Property.Value::value); - -+ // Paper start - optimise iblockdata state lookup -+ private static final java.util.concurrent.atomic.AtomicInteger ID_GENERATOR = new java.util.concurrent.atomic.AtomicInteger(); -+ private final int id = ID_GENERATOR.getAndIncrement(); -+ -+ public final int getId() { -+ return this.id; -+ } -+ -+ public abstract int getIdFor(final T value); -+ // Paper end - optimise state lookup -+ - protected Property(String name, Class type) { - this.clazz = type; - this.name = name;