diff options
-rw-r--r-- | paper-server/patches/features/0018-Moonrise-optimisation-patches.patch (renamed from feature-patches/0018-Moonrise-optimisation-patches.patch) | 6316 |
1 files changed, 2744 insertions, 3572 deletions
diff --git a/feature-patches/0018-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0018-Moonrise-optimisation-patches.patch index b20c8eacca..16ce461d49 100644 --- a/feature-patches/0018-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0018-Moonrise-optimisation-patches.patch @@ -17,35 +17,6 @@ Currently includes: See https://github.com/Tuinity/Moonrise -diff --git a/ca/spottedleaf/moonrise/common/PlatformHooks.java b/ca/spottedleaf/moonrise/common/PlatformHooks.java -index 6c98d420ea84c10ef4f15d4deb3f04e610ed8548..9b879cbc037a17ffeb9a963111fd3f303a935eef 100644 ---- a/ca/spottedleaf/moonrise/common/PlatformHooks.java -+++ b/ca/spottedleaf/moonrise/common/PlatformHooks.java -@@ -1,5 +1,6 @@ - package ca.spottedleaf.moonrise.common; - -+import ca.spottedleaf.moonrise.common.util.ChunkSystemHooks; - import com.mojang.datafixers.DSL; - import com.mojang.datafixers.DataFixer; - import net.minecraft.core.BlockPos; -@@ -23,7 +24,7 @@ import java.util.List; - import java.util.ServiceLoader; - import java.util.function.Predicate; - --public interface PlatformHooks { -+public interface PlatformHooks extends ChunkSystemHooks { - public static PlatformHooks get() { - return Holder.INSTANCE; - } -@@ -63,8 +64,6 @@ public interface PlatformHooks { - - public void entityMove(final Entity entity, final long oldSection, final long newSection); - -- public boolean screenEntity(final ServerLevel world, final Entity entity, final boolean fromDisk, final boolean event); -- - public boolean configFixMC224294(); - - public boolean configAutoConfigSendDistance(); diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java new file mode 100644 index 0000000000000000000000000000000000000000..1b8193587814225c2ef2c5d9e667436eb50ff6c5 @@ -325,257 +296,65 @@ index 0000000000000000000000000000000000000000..1b8193587814225c2ef2c5d9e667436e + } + } +} -diff --git a/ca/spottedleaf/moonrise/common/util/BaseChunkSystemHooks.java b/ca/spottedleaf/moonrise/common/util/BaseChunkSystemHooks.java -new file mode 100644 -index 0000000000000000000000000000000000000000..89406dbda09eea03579ed724fda0df2d42e2e504 ---- /dev/null -+++ b/ca/spottedleaf/moonrise/common/util/BaseChunkSystemHooks.java -@@ -0,0 +1,190 @@ -+package ca.spottedleaf.moonrise.common.util; -+ -+import ca.spottedleaf.concurrentutil.util.Priority; -+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 ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache; -+import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.FullChunkStatus; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.level.progress.ChunkProgressListener; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.LevelChunk; -+import net.minecraft.world.level.chunk.status.ChunkStatus; -+import java.util.List; -+import java.util.function.Consumer; -+ -+public abstract class BaseChunkSystemHooks implements ChunkSystemHooks { -+ -+ @Override -+ public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { -+ scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL); -+ } -+ -+ @Override -+ public 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); -+ } -+ -+ @Override -+ public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, -+ final ChunkStatus toStatus, final boolean addTicket, final Priority priority, -+ final Consumer<ChunkAccess> onComplete) { -+ ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, gen, toStatus, addTicket, priority, onComplete); -+ } -+ -+ @Override -+ public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, -+ final boolean addTicket, final Priority priority, final Consumer<ChunkAccess> onComplete) { -+ ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ } -+ -+ @Override -+ public void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, -+ final FullChunkStatus toStatus, final boolean addTicket, -+ final Priority priority, final Consumer<LevelChunk> onComplete) { -+ ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ } -+ -+ @Override -+ public List<ChunkHolder> getVisibleChunkHolders(final ServerLevel level) { -+ return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.getOldChunkHolders(); -+ } -+ -+ @Override -+ public List<ChunkHolder> getUpdatingChunkHolders(final ServerLevel level) { -+ return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.getOldChunkHolders(); -+ } -+ -+ @Override -+ public int getVisibleChunkHolderCount(final ServerLevel level) { -+ return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.size(); -+ } -+ -+ @Override -+ public int getUpdatingChunkHolderCount(final ServerLevel level) { -+ return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.size(); -+ } -+ -+ @Override -+ public boolean hasAnyChunkHolders(final ServerLevel level) { -+ return getUpdatingChunkHolderCount(level) != 0; -+ } -+ -+ @Override -+ public void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { -+ -+ } -+ -+ @Override -+ public void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { -+ // Update progress listener for LevelLoadingScreen -+ final ChunkProgressListener progressListener = level.getChunkSource().chunkMap.progressListener; -+ if (progressListener != null) { -+ this.scheduleChunkTask(level, holder.getPos().x, holder.getPos().z, () -> { -+ progressListener.onStatusChange(holder.getPos(), null); -+ }); -+ } -+ } -+ -+ @Override -+ public void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ ((ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource()) -+ .moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, chunk); -+ } -+ -+ @Override -+ public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().add( -+ ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() -+ ); -+ chunk.loadCallback(); -+ } -+ -+ @Override -+ public void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().remove( -+ ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() -+ ); -+ chunk.unloadCallback(); -+ } -+ -+ @Override -+ public void onChunkPostNotBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ ((ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource()) -+ .moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, null); -+ } -+ -+ @Override -+ public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().add( -+ ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() -+ ); -+ if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) { -+ chunk.postProcessGeneration((ServerLevel)chunk.getLevel()); -+ } -+ ((ServerLevel)chunk.getLevel()).startTickingChunk(chunk); -+ ((ServerLevel)chunk.getLevel()).getChunkSource().chunkMap.tickingGenerated.incrementAndGet(); -+ ((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$markChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration -+ } -+ -+ @Override -+ public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove( -+ ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() -+ ); -+ ((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration -+ } -+ -+ @Override -+ public void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().add( -+ ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() -+ ); -+ } -+ -+ @Override -+ public void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().remove( -+ ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() -+ ); -+ } -+ -+ @Override -+ public ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { -+ return null; -+ } -+ -+ @Override -+ public int getSendViewDistance(final ServerPlayer player) { -+ return RegionizedPlayerChunkLoader.getAPISendViewDistance(player); -+ } -+ -+ @Override -+ public int getViewDistance(final ServerPlayer player) { -+ return RegionizedPlayerChunkLoader.getAPIViewDistance(player); -+ } -+ -+ @Override -+ public int getTickViewDistance(final ServerPlayer player) { -+ return RegionizedPlayerChunkLoader.getAPITickViewDistance(player); -+ } -+ -+ @Override -+ public void addPlayerToDistanceMaps(final ServerLevel world, final ServerPlayer player) { -+ ((ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().addPlayer(player); -+ } -+ -+ @Override -+ public void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player) { -+ ((ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().removePlayer(player); -+ } -+ -+ @Override -+ public void updateMaps(final ServerLevel world, final ServerPlayer player) { -+ ((ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().updatePlayer(player); -+ } -+} -diff --git a/ca/spottedleaf/moonrise/common/util/ChunkSystem.java b/ca/spottedleaf/moonrise/common/util/ChunkSystem.java -deleted file mode 100644 -index 58a99bc38e137431f10af36fa9e2d04fe61694aa..0000000000000000000000000000000000000000 ---- a/ca/spottedleaf/moonrise/common/util/ChunkSystem.java -+++ /dev/null -@@ -1,288 +0,0 @@ --package ca.spottedleaf.moonrise.common.util; -- --import ca.spottedleaf.concurrentutil.util.Priority; --import ca.spottedleaf.moonrise.common.PlatformHooks; --import com.mojang.logging.LogUtils; --import net.minecraft.server.level.ChunkHolder; --import net.minecraft.server.level.FullChunkStatus; --import net.minecraft.server.level.ServerLevel; --import net.minecraft.server.level.ServerPlayer; --import net.minecraft.world.entity.Entity; --import net.minecraft.world.level.chunk.ChunkAccess; --import net.minecraft.world.level.chunk.LevelChunk; --import net.minecraft.world.level.chunk.status.ChunkStatus; --import org.slf4j.Logger; --import java.util.List; --import java.util.function.Consumer; -- --public final class ChunkSystem { -- +diff --git a/ca/spottedleaf/moonrise/paper/PaperHooks.java b/ca/spottedleaf/moonrise/paper/PaperHooks.java +index c2dfbce23af5741b7f78ddd6df9bcbce69915ae9..5955a56a63e91edafbac07ac1f0c640a4f7cbb26 100644 +--- a/ca/spottedleaf/moonrise/paper/PaperHooks.java ++++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java +@@ -268,7 +268,7 @@ public final class PaperHooks extends BaseChunkSystemHooks implements PlatformHo + + @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/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java b/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java +index 34b45bc11124efb22f0f3ae5b2ad8f445c719476..62a9e62711a46283931d22b0e72b2b1903d973a1 100644 +--- a/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java ++++ b/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java +@@ -23,218 +23,59 @@ import java.util.function.Consumer; + + public abstract class BaseChunkSystemHooks implements ca.spottedleaf.moonrise.common.util.ChunkSystemHooks { + - private static final Logger LOGGER = LogUtils.getLogger(); -- private static final net.minecraft.world.level.chunk.status.ChunkStep FULL_CHUNK_STEP = net.minecraft.world.level.chunk.status.ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.FULL); +- private static final ChunkStep FULL_CHUNK_STEP = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.FULL); +- private static final TicketType<Long> CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); +- +- private long chunkLoadCounter = 0L; - - private static int getDistance(final ChunkStatus status) { - return FULL_CHUNK_STEP.getAccumulatedRadiusOf(status); - } - -- public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { -- scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL); -- } -- -- public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority priority) { + @Override + public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { +- this.scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL); ++ scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL); + } + + @Override + public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority 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 Priority priority, -- final Consumer<ChunkAccess> onComplete) { ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkTask(chunkX, chunkZ, run, priority); + } + + @Override + public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, + final ChunkStatus toStatus, final boolean addTicket, final Priority priority, + final Consumer<ChunkAccess> onComplete) { - if (gen) { -- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- this.scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); - return; - } -- scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { +- this.scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { - if (chunk == null) { - if (onComplete != null) { - onComplete.accept(null); - } - } else { - if (chunk.getPersistedStatus().isOrAfter(toStatus)) { -- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- BaseChunkSystemHooks.this.scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); - } else { - if (onComplete != null) { - onComplete.accept(null); @@ -583,23 +362,22 @@ index 58a99bc38e137431f10af36fa9e2d04fe61694aa..00000000000000000000000000000000 - } - } - }); -- } -- -- static final net.minecraft.server.level.TicketType<Long> CHUNK_LOAD = net.minecraft.server.level.TicketType.create("chunk_load", Long::compareTo); -- -- 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 Priority priority, final Consumer<ChunkAccess> onComplete) { -- if (!org.bukkit.Bukkit.isOwnedByCurrentRegion(level.getWorld(), chunkX, chunkZ)) { -- scheduleChunkTask(level, chunkX, chunkZ, () -> { -- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, gen, toStatus, addTicket, priority, onComplete); + } + + @Override + public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, + final boolean addTicket, final Priority priority, final Consumer<ChunkAccess> onComplete) { +- if (!Bukkit.isOwnedByCurrentRegion(level.getWorld(), chunkX, chunkZ)) { +- this.scheduleChunkTask(level, chunkX, chunkZ, () -> { +- BaseChunkSystemHooks.this.scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); - }, priority); - return; - } - - final int minLevel = 33 + getDistance(toStatus); -- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -- final net.minecraft.world.level.ChunkPos chunkPos = new net.minecraft.world.level.ChunkPos(chunkX, chunkZ); +- final Long chunkReference = addTicket ? Long.valueOf(++this.chunkLoadCounter) : null; +- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - - if (addTicket) { - level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); @@ -622,50 +400,52 @@ index 58a99bc38e137431f10af36fa9e2d04fe61694aa..00000000000000000000000000000000 - } - }; - -- final ChunkHolder holder = level.chunkSource.chunkMap.updatingChunkMap.get(CoordinateUtils.getChunkKey(chunkX, chunkZ)); +- final ChunkHolder holder = level.chunkSource.chunkMap.updatingChunkMap.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); - - if (holder == null || holder.getTicketLevel() > minLevel) { - loadCallback.accept(null); - return; - } - -- final java.util.concurrent.CompletableFuture<net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.ChunkAccess>> loadFuture = holder.scheduleChunkGenerationTask(toStatus, level.chunkSource.chunkMap); +- final CompletableFuture<ChunkResult<ChunkAccess>> loadFuture = holder.scheduleChunkGenerationTask(toStatus, level.chunkSource.chunkMap); - - if (loadFuture.isDone()) { - loadCallback.accept(loadFuture.join().orElse(null)); - return; - } - -- loadFuture.whenCompleteAsync((final net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.ChunkAccess> result, final Throwable thr) -> { +- loadFuture.whenCompleteAsync((final ChunkResult<ChunkAccess> result, final Throwable thr) -> { - if (thr != null) { - loadCallback.accept(null); - return; - } - loadCallback.accept(result.orElse(null)); - }, (final Runnable r) -> { -- scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST); +- BaseChunkSystemHooks.this.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 Priority priority, final Consumer<LevelChunk> onComplete) { ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); + } + + @Override + public void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, + final FullChunkStatus toStatus, final boolean addTicket, + final Priority priority, final Consumer<LevelChunk> onComplete) { - // This method goes unused until the chunk system rewrite - if (toStatus == FullChunkStatus.INACCESSIBLE) { - throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); - } - -- if (!org.bukkit.Bukkit.isOwnedByCurrentRegion(level.getWorld(), chunkX, chunkZ)) { -- scheduleChunkTask(level, chunkX, chunkZ, () -> { -- scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- if (!Bukkit.isOwnedByCurrentRegion(level.getWorld(), chunkX, chunkZ)) { +- this.scheduleChunkTask(level, chunkX, chunkZ, () -> { +- BaseChunkSystemHooks.this.scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); - }, priority); - return; - } - - final int minLevel = 33 - (toStatus.ordinal() - 1); - final int radius = toStatus.ordinal() - 1; -- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -- final net.minecraft.world.level.ChunkPos chunkPos = new net.minecraft.world.level.ChunkPos(chunkX, chunkZ); +- final Long chunkReference = addTicket ? Long.valueOf(++this.chunkLoadCounter) : null; +- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - - if (addTicket) { - level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); @@ -682,20 +462,20 @@ index 58a99bc38e137431f10af36fa9e2d04fe61694aa..00000000000000000000000000000000 - com.destroystokyo.paper.util.SneakyThrow.sneaky(thr); - } finally { - if (addTicket) { -- level.chunkSource.addTicketAtLevel(net.minecraft.server.level.TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); +- level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); - level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); - } - } - }; - -- final ChunkHolder holder = level.chunkSource.chunkMap.updatingChunkMap.get(CoordinateUtils.getChunkKey(chunkX, chunkZ)); +- final ChunkHolder holder = level.chunkSource.chunkMap.updatingChunkMap.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); - - if (holder == null || holder.getTicketLevel() > minLevel) { - loadCallback.accept(null); - return; - } - -- final java.util.concurrent.CompletableFuture<net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk>> tickingState; +- final CompletableFuture<ChunkResult<LevelChunk>> tickingState; - switch (toStatus) { - case FULL: { - tickingState = holder.getFullChunkFuture(); @@ -719,220 +499,184 @@ index 58a99bc38e137431f10af36fa9e2d04fe61694aa..00000000000000000000000000000000 - return; - } - -- tickingState.whenCompleteAsync((final net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk> result, final Throwable thr) -> { +- tickingState.whenCompleteAsync((final ChunkResult<LevelChunk> result, final Throwable thr) -> { - if (thr != null) { - loadCallback.accept(null); - return; - } - loadCallback.accept(result.orElse(null)); - }, (final Runnable r) -> { -- scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST); +- BaseChunkSystemHooks.this.scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST); - }); -- } -- -- public static List<ChunkHolder> getVisibleChunkHolders(final ServerLevel level) { -- return new java.util.ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); -- } -- -- public static List<ChunkHolder> getUpdatingChunkHolders(final ServerLevel level) { -- return new java.util.ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); -- } -- -- public static int getVisibleChunkHolderCount(final ServerLevel level) { ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); + } + + @Override + public List<ChunkHolder> getVisibleChunkHolders(final ServerLevel level) { +- return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.getOldChunkHolders(); + } + + @Override + public List<ChunkHolder> getUpdatingChunkHolders(final ServerLevel level) { +- return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.getOldChunkHolders(); + } + + @Override + public int getVisibleChunkHolderCount(final ServerLevel level) { - return level.chunkSource.chunkMap.visibleChunkMap.size(); -- } -- -- public static int getUpdatingChunkHolderCount(final ServerLevel level) { ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.size(); + } + + @Override + public int getUpdatingChunkHolderCount(final ServerLevel level) { - return level.chunkSource.chunkMap.updatingChunkMap.size(); -- } -- -- public static boolean hasAnyChunkHolders(final ServerLevel level) { -- return getUpdatingChunkHolderCount(level) != 0; -- } -- -- public static boolean screenEntity(final ServerLevel level, final Entity entity, final boolean fromDisk, final boolean event) { -- if (!PlatformHooks.get().screenEntity(level, entity, fromDisk, event)) { -- return false; -- } -- return true; -- } -- -- public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { -- -- } -- -- public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { -- -- } -- -- public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { -- -- } -- -- public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { -- -- } ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.size(); + } + + @Override + public boolean hasAnyChunkHolders(final ServerLevel level) { +- return this.getUpdatingChunkHolderCount(level) != 0; ++ return getUpdatingChunkHolderCount(level) != 0; + } + + @Override +@@ -244,89 +85,110 @@ public abstract class BaseChunkSystemHooks implements ca.spottedleaf.moonrise.co + + @Override + public void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { - -- public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ // Update progress listener for LevelLoadingScreen ++ final net.minecraft.server.level.progress.ChunkProgressListener progressListener = level.getChunkSource().chunkMap.progressListener; ++ if (progressListener != null) { ++ this.scheduleChunkTask(level, holder.getPos().x, holder.getPos().z, () -> { ++ progressListener.onStatusChange(holder.getPos(), null); ++ }); ++ } + } + + @Override + public void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder) { - -- } ++ ((ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource()) ++ .moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, chunk); + } + + @Override + public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { - -- public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().add( ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() ++ ); ++ chunk.loadCallback(); + } + + @Override + public void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { - -- } ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().remove( ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() ++ ); ++ chunk.unloadCallback(); + } + + @Override + public void onChunkPostNotBorder(final LevelChunk chunk, final ChunkHolder holder) { - -- public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ ((ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource()) ++ .moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, null); + } + + @Override + public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { - -- } ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().add( ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() ++ ); ++ if (!((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) { ++ chunk.postProcessGeneration((ServerLevel)chunk.getLevel()); ++ } ++ ((ServerLevel)chunk.getLevel()).startTickingChunk(chunk); ++ ((ServerLevel)chunk.getLevel()).getChunkSource().chunkMap.tickingGenerated.incrementAndGet(); ++ ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$markChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration + } + + @Override + public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { - -- public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove( ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() ++ ); ++ ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration + } + + @Override + public void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { - -- } ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().add( ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() ++ ); + } + + @Override + public void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { - -- public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().remove( ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() ++ ); + } + + @Override + public ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { - return level.chunkSource.chunkMap.getUnloadingChunkHolder(chunkX, chunkZ); -- } -- -- public static int getSendViewDistance(final ServerPlayer player) { -- return getViewDistance(player); -- } -- -- public static int getViewDistance(final ServerPlayer player) { ++ return null; + } + + @Override + public int getSendViewDistance(final ServerPlayer player) { +- return this.getViewDistance(player); ++ return ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.getAPISendViewDistance(player); + } + + @Override + public int getViewDistance(final ServerPlayer player) { - final ServerLevel level = player.serverLevel(); - if (level == null) { -- return org.bukkit.Bukkit.getViewDistance(); +- return Bukkit.getViewDistance(); - } - return level.chunkSource.chunkMap.serverViewDistance; -- } -- -- public static int getTickViewDistance(final ServerPlayer player) { ++ return ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.getAPIViewDistance(player); + } + + @Override + public int getTickViewDistance(final ServerPlayer player) { - final ServerLevel level = player.serverLevel(); - if (level == null) { -- return org.bukkit.Bukkit.getSimulationDistance(); +- return Bukkit.getSimulationDistance(); - } - return level.chunkSource.chunkMap.distanceManager.simulationDistance; -- } -- -- private ChunkSystem() {} --} -diff --git a/ca/spottedleaf/moonrise/common/util/ChunkSystemHooks.java b/ca/spottedleaf/moonrise/common/util/ChunkSystemHooks.java -new file mode 100644 -index 0000000000000000000000000000000000000000..427079ae47b6e0e1aa42013a8760fbefa76941f2 ---- /dev/null -+++ b/ca/spottedleaf/moonrise/common/util/ChunkSystemHooks.java -@@ -0,0 +1,77 @@ -+package ca.spottedleaf.moonrise.common.util; -+ -+import ca.spottedleaf.concurrentutil.util.Priority; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.FullChunkStatus; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.LevelChunk; -+import net.minecraft.world.level.chunk.status.ChunkStatus; -+import java.util.List; -+import java.util.function.Consumer; -+ -+public interface ChunkSystemHooks { -+ -+ public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run); -+ -+ public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority priority); -+ -+ public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, -+ final ChunkStatus toStatus, final boolean addTicket, final Priority priority, -+ final Consumer<ChunkAccess> onComplete); -+ -+ public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, -+ final boolean addTicket, final Priority priority, final Consumer<ChunkAccess> onComplete); -+ -+ public void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, -+ final FullChunkStatus toStatus, final boolean addTicket, -+ final Priority priority, final Consumer<LevelChunk> onComplete); -+ -+ public List<ChunkHolder> getVisibleChunkHolders(final ServerLevel level); -+ -+ public List<ChunkHolder> getUpdatingChunkHolders(final ServerLevel level); -+ -+ public int getVisibleChunkHolderCount(final ServerLevel level); -+ -+ public int getUpdatingChunkHolderCount(final ServerLevel level); -+ -+ public boolean hasAnyChunkHolders(final ServerLevel level); -+ -+ public boolean screenEntity(final ServerLevel level, final Entity entity, final boolean fromDisk, final boolean event); -+ -+ public void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder); -+ -+ public void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder); -+ -+ public void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder); -+ -+ public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder); -+ -+ public void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder); -+ -+ public void onChunkPostNotBorder(final LevelChunk chunk, final ChunkHolder holder); -+ -+ public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder); -+ -+ public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder); -+ -+ public void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder); -+ -+ public void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder); -+ -+ public ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ); -+ -+ public int getSendViewDistance(final ServerPlayer player); -+ -+ public int getViewDistance(final ServerPlayer player); -+ -+ public int getTickViewDistance(final ServerPlayer player); -+ -+ public void addPlayerToDistanceMaps(final ServerLevel world, final ServerPlayer player); -+ -+ public void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player); -+ -+ public void updateMaps(final ServerLevel world, final ServerPlayer player); -+} -diff --git a/ca/spottedleaf/moonrise/common/util/ThreadUnsafeRandom.java b/ca/spottedleaf/moonrise/common/util/ThreadUnsafeRandom.java -index 12eb3add0931a4d77acdf6e875c42dda9c313dc3..5239993a681d6113eec99fa627b85508656ed7ac 100644 ---- a/ca/spottedleaf/moonrise/common/util/ThreadUnsafeRandom.java -+++ b/ca/spottedleaf/moonrise/common/util/ThreadUnsafeRandom.java -@@ -9,7 +9,7 @@ import net.minecraft.world.level.levelgen.PositionalRandomFactory; - /** - * Avoid costly CAS of superclass - */ --public final class ThreadUnsafeRandom implements BitRandomSource { -+public class ThreadUnsafeRandom implements BitRandomSource { // Paper - replace random - - private static final long MULTIPLIER = 25214903917L; - private static final long ADDEND = 11L; -diff --git a/ca/spottedleaf/moonrise/paper/PaperHooks.java b/ca/spottedleaf/moonrise/paper/PaperHooks.java -index 11cfe9cc29666ce3a6a40281069fb9eb4fa0ded2..8c197c59eb35e02f163ec98b8aa0888e4ff40b1a 100644 ---- a/ca/spottedleaf/moonrise/paper/PaperHooks.java -+++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java -@@ -27,7 +27,7 @@ import net.minecraft.world.phys.AABB; - import java.util.List; - import java.util.function.Predicate; - --public final class PaperHooks implements PlatformHooks { -+public final class PaperHooks extends ca.spottedleaf.moonrise.common.util.BaseChunkSystemHooks implements PlatformHooks { // Paper - rewrite chunk system ++ return ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.getAPITickViewDistance(player); + } @Override - public String getBrand() { -@@ -267,7 +267,7 @@ public final class PaperHooks implements PlatformHooks { + public void addPlayerToDistanceMaps(final ServerLevel world, final ServerPlayer player) { +- ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().addPlayer(player); + } @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 + public void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player) { +- ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().removePlayer(player); } @Override + public void updateMaps(final ServerLevel world, final ServerPlayer player) { +- ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().updatePlayer(player); + } + } diff --git a/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java b/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java new file mode 100644 index 0000000000000000000000000000000000000000..93bc56daec4526f373c84763b8c7ccb4a30e800b @@ -23024,7 +22768,7 @@ index 0000000000000000000000000000000000000000..689ce367164e79e0426eeecb81dbbc52 + private SaveUtil() {} +} diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java -index a6779295bff446ee79e7c9d41e405447becc2966..efc7f4071655201c59c912e9c84e35a8da66e34c 100644 +index 764daee7cd619c56314bcea9a4c35702afcb262d..e54355728183c594643f2e28ba2e92b1502882ac 100644 --- a/io/papermc/paper/FeatureHooks.java +++ b/io/papermc/paper/FeatureHooks.java @@ -1,6 +1,8 @@ @@ -23036,7 +22780,7 @@ index a6779295bff446ee79e7c9d41e405447becc2966..efc7f4071655201c59c912e9c84e35a8 import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.longs.LongSets; -@@ -29,9 +31,12 @@ import org.bukkit.World; +@@ -30,9 +32,12 @@ import org.bukkit.World; public final class FeatureHooks { public static void initChunkTaskScheduler(final boolean useParallelGen) { @@ -23471,7 +23215,7 @@ index 0000000000000000000000000000000000000000..8424cf9d4617b4732d44cc460d25b044 + +} diff --git a/net/minecraft/core/Direction.java b/net/minecraft/core/Direction.java -index 690e1d2394e68356c56a39ac083cc53ee0388d71..928f38fd6beb00753c92ae9f4678f7507519a39b 100644 +index 3d3eec1db91cb47395f40c4f47aa77164ad42175..216f97207dac88cc1dc3df59c6ee8a62c7614b4a 100644 --- a/net/minecraft/core/Direction.java +++ b/net/minecraft/core/Direction.java @@ -28,7 +28,7 @@ import org.joml.Quaternionf; @@ -23529,7 +23273,7 @@ index 690e1d2394e68356c56a39ac083cc53ee0388d71..928f38fd6beb00753c92ae9f4678f750 + // Paper end - optimise collisions private Direction( - final int id, + final int data3d, @@ -147,14 +187,13 @@ public enum Direction implements StringRepresentable { } @@ -23580,7 +23324,7 @@ index 690e1d2394e68356c56a39ac083cc53ee0388d71..928f38fd6beb00753c92ae9f4678f750 + // Paper end - optimise collisions } diff --git a/net/minecraft/core/MappedRegistry.java b/net/minecraft/core/MappedRegistry.java -index 063630c1ffcce099139c59d598fc5a210e21f640..a61153c5d99bdc26f37a10f33baf839e943e17e1 100644 +index 47b1fafd91b39e73c4e9134b0b8048000fba108a..76994c1491221c06cca5405ba239e6ff642b19ed 100644 --- a/net/minecraft/core/MappedRegistry.java +++ b/net/minecraft/core/MappedRegistry.java @@ -50,6 +50,19 @@ public class MappedRegistry<T> implements WritableRegistry<T> { @@ -23600,53 +23344,44 @@ index 063630c1ffcce099139c59d598fc5a210e21f640..a61153c5d99bdc26f37a10f33baf839e + } + // Paper end - fluid method optimisations + - public MappedRegistry(ResourceKey<? extends Registry<T>> key, Lifecycle lifecycle) { - this(key, lifecycle, false); + public MappedRegistry(ResourceKey<? extends Registry<T>> key, Lifecycle registryLifecycle) { + this(key, registryLifecycle, false); } @@ -114,6 +127,7 @@ public class MappedRegistry<T> implements WritableRegistry<T> { - this.toId.put(value, i); - this.registrationInfos.put(key, info); - this.registryLifecycle = this.registryLifecycle.add(info.lifecycle()); + this.toId.put(value, size); + this.registrationInfos.put(key, registrationInfo); + this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle()); + this.injectFluidRegister(key, value); // Paper - fluid method optimisations return reference; } } diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java -index 731bdabd53fd4a3d17494f26781223097a5d6e16..42d46c7a7437bea5335a23cbee5708ac57131474 100644 +index 4437283a5d157eede121b98be0112c1067eded5e..e627618f2368258d7cb9cd35908d0f42a9c504f5 100644 --- a/net/minecraft/server/Main.java +++ b/net/minecraft/server/Main.java -@@ -322,6 +322,7 @@ public class Main { - - convertable_conversionsession.saveDataTag(iregistrycustom_dimension, savedata); +@@ -320,6 +320,7 @@ public class Main { + WorldData worldData = worldStem.worldData(); + levelStorageAccess.saveDataTag(frozen, worldData); */ + Class.forName(net.minecraft.world.entity.npc.VillagerTrades.class.getName()); // Paper - load this sync so it won't fail later async - final DedicatedServer dedicatedserver = (DedicatedServer) MinecraftServer.spin((thread) -> { - DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, worldLoader.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), services, LoggerChunkProgressListener::createFromGameruleRadius); - + final DedicatedServer dedicatedServer = MinecraftServer.spin( + thread1 -> { + DedicatedServer dedicatedServer1 = new DedicatedServer( diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 807d05097f7313361eadb600187421d25e294413..5e7ba47247fc9b6bc8da86d8f67c6cd923cd0b1e 100644 +index 646c2f2b617ed706021c83c9fc4492860dfdd4e9..b4dcb4178b49af49cf6e654788efda3dd10c767e 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -204,7 +204,7 @@ import org.bukkit.event.server.ServerLoadEvent; - // CraftBukkit end - +@@ -173,7 +173,7 @@ import net.minecraft.world.phys.Vec2; + import net.minecraft.world.phys.Vec3; + import org.slf4j.Logger; -public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements ServerInfo, ChunkIOErrorReporter, CommandSource { +public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> 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(); -@@ -333,7 +333,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa - public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) { - ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system - AtomicReference<S> atomicreference = new AtomicReference(); -- Thread thread = new Thread(() -> { -+ Thread thread = new ca.spottedleaf.moonrise.common.util.TickThread(() -> { // Paper - rewrite chunk system - ((MinecraftServer) atomicreference.get()).runServer(); - }, "Server thread"); - -@@ -352,6 +352,77 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa - return s0; + public static final net.kyori.adventure.text.logger.slf4j.ComponentLogger COMPONENT_LOGGER = net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(LOGGER.getName()); // Paper +@@ -316,6 +316,77 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + return minecraftServer; } + // Paper start - rewrite chunk system @@ -23720,73 +23455,71 @@ index 807d05097f7313361eadb600187421d25e294413..5e7ba47247fc9b6bc8da86d8f67c6cd9 + } + // Paper end - rewrite chunk system + - public MinecraftServer(OptionSet options, WorldLoader.DataLoadContext worldLoader, Thread thread, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PackRepository resourcepackrepository, WorldStem worldstem, Proxy proxy, DataFixer datafixer, Services services, ChunkProgressListenerFactory worldloadlistenerfactory) { - super("Server"); - SERVER = this; // Paper - better singleton -@@ -672,7 +743,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + public MinecraftServer( + // CraftBukkit start + joptsimple.OptionSet options, +@@ -626,7 +697,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.forceDifficulty(); - for (ServerLevel worldserver : this.getAllLevels()) { - this.prepareLevels(worldserver.getChunkSource().chunkMap.progressListener, worldserver); -- worldserver.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API + for (ServerLevel serverLevel : this.getAllLevels()) { + this.prepareLevels(serverLevel.getChunkSource().chunkMap.progressListener, serverLevel); +- serverLevel.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API + // Paper - rewrite chunk system - this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(worldserver.getWorld())); + this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(serverLevel.getWorld())); } -@@ -888,6 +959,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -825,6 +896,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa public abstract boolean shouldRconBroadcast(); - public boolean saveAllChunks(boolean suppressLogs, boolean flush, boolean force) { + public boolean saveAllChunks(boolean suppressLog, boolean flush, boolean forced) { + // Paper start - add close param -+ return this.saveAllChunks(suppressLogs, flush, force, false); ++ return this.saveAllChunks(suppressLog, flush, forced, false); + } -+ public boolean saveAllChunks(boolean suppressLogs, boolean flush, boolean force, boolean close) { ++ public boolean saveAllChunks(boolean suppressLog, boolean flush, boolean forced, boolean close) { + // Paper end - add close param - boolean flag3 = false; + boolean flag = false; - for (Iterator iterator = this.getAllLevels().iterator(); iterator.hasNext(); flag3 = true) { -@@ -897,7 +973,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa - MinecraftServer.LOGGER.info("Saving chunks for level '{}'/{}", worldserver, worldserver.dimension().location()); + for (ServerLevel serverLevel : this.getAllLevels()) { +@@ -832,7 +908,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + LOGGER.info("Saving chunks for level '{}'/{}", serverLevel, serverLevel.dimension().location()); } -- worldserver.save((ProgressListener) null, flush, worldserver.noSave && !force); -+ worldserver.save((ProgressListener) null, flush, worldserver.noSave && !force, close); // Paper - add close param +- serverLevel.save(null, flush, serverLevel.noSave && !forced); ++ serverLevel.save(null, flush, serverLevel.noSave && !forced, close); // Paper - add close param + flag = true; } - // CraftBukkit start - moved to WorldServer.save -@@ -998,7 +1074,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -923,7 +999,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa } } -- while (this.levels.values().stream().anyMatch((worldserver1) -> { -+ while (false && this.levels.values().stream().anyMatch((worldserver1) -> { // Paper - rewrite chunk system - return worldserver1.getChunkSource().chunkMap.hasWork(); - })) { +- while (this.levels.values().stream().anyMatch(level -> level.getChunkSource().chunkMap.hasWork())) { ++ while (false && this.levels.values().stream().anyMatch(level -> level.getChunkSource().chunkMap.hasWork())) { // Paper - rewrite chunk system this.nextTickTimeNanos = Util.getNanos() + TimeUtil.NANOSECONDS_PER_MILLISECOND; -@@ -1015,19 +1091,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + + for (ServerLevel serverLevelx : this.getAllLevels()) { +@@ -934,17 +1010,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.waitUntilNextTick(); } - this.saveAllChunks(false, true, false); -- iterator = this.getAllLevels().iterator(); - -- while (iterator.hasNext()) { -- worldserver = (ServerLevel) iterator.next(); -- if (worldserver != null) { +- for (ServerLevel serverLevelx : this.getAllLevels()) { +- if (serverLevelx != null) { - try { -- worldserver.close(); -- } catch (IOException ioexception) { -- MinecraftServer.LOGGER.error("Exception closing the level", ioexception); +- serverLevelx.close(); +- } catch (IOException var5) { +- LOGGER.error("Exception closing the level", (Throwable)var5); - } - } - } -+ this.saveAllChunks(false, true, true, true); // Paper - rewrite chunk system ++ this.saveAllChunks(false, true, false, true); // Paper - rewrite chunk system this.isSaving = false; this.resources.close(); -@@ -1047,6 +1111,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -963,6 +1029,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + this.getProfileCache().save(false); // Paper - Perf: Async GameProfileCache saving } // Spigot end - + // Paper start - rewrite chunk system + LOGGER.info("Waiting for I/O tasks to complete..."); + ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.flush((MinecraftServer)(Object)this); @@ -23798,21 +23531,21 @@ index 807d05097f7313361eadb600187421d25e294413..5e7ba47247fc9b6bc8da86d8f67c6cd9 } public String getLocalIp() { -@@ -1228,6 +1300,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa - 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; -@@ -1432,6 +1511,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -1133,6 +1207,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + profilerFiller.push("tick"); + this.tickFrame.start(); + this.tickServer(flag ? () -> 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(); + profilerFiller.popPush("nextTickWait"); + this.mayHaveDelayedTasks = true; +@@ -1305,6 +1386,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa private boolean pollTaskInternal() { if (super.pollTask()) { @@ -23820,8 +23553,8 @@ index 807d05097f7313361eadb600187421d25e294413..5e7ba47247fc9b6bc8da86d8f67c6cd9 return true; } else { boolean ret = false; // Paper - force execution of all worlds, do not just bias the first -@@ -2713,6 +2793,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa - +@@ -2425,6 +2507,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + } } + // Paper start - rewrite chunk system @@ -23830,23 +23563,22 @@ index 807d05097f7313361eadb600187421d25e294413..5e7ba47247fc9b6bc8da86d8f67c6cd9 + return ca.spottedleaf.moonrise.common.util.TickThread.isTickThread(); + } + // Paper end - rewrite chunk system -+ + // CraftBukkit start public boolean isDebugging() { - return false; diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 2f47d95943c00020a24ea3ff1a49e64e114de675..0dd9ed7465d222505d5368781654ec4954f6e5c3 100644 +index 1ad96b964cdcf10b9f81d32d07e03c1a0ab6fe0a..ab356d1afb352f1f134d25dfa17ce5476a2039cd 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -458,7 +458,33 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - return world.dimension() == net.minecraft.world.level.Level.NETHER ? this.getProperties().allowNether : true; +@@ -432,7 +432,33 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + return level.dimension() != Level.NETHER || this.getProperties().allowNether; } + private static final java.util.concurrent.atomic.AtomicInteger ASYNC_DEBUG_CHUNKS_COUNT = new java.util.concurrent.atomic.AtomicInteger(); // Paper - rewrite chunk system + - public void handleConsoleInput(String command, CommandSourceStack commandSource) { + public void handleConsoleInput(String msg, CommandSourceStack source) { + // Paper start - rewrite chunk system -+ if (command.equalsIgnoreCase("paper debug chunks --async")) { ++ if (msg.equalsIgnoreCase("paper debug chunks --async")) { + LOGGER.info("Scheduling async debug chunks"); + Runnable run = () -> { + LOGGER.info("Async debug chunks executing"); @@ -23869,42 +23601,41 @@ index 2f47d95943c00020a24ea3ff1a49e64e114de675..0dd9ed7465d222505d5368781654ec49 + return; + } + // Paper end - rewrite chunk system - this.serverCommandQueue.add(new ConsoleInput(command, commandSource)); // Paper - Perf: use proper queue + this.serverCommandQueue.add(new ConsoleInput(msg, source)); // Paper - Perf: use proper queue } diff --git a/net/minecraft/server/level/ChunkHolder.java b/net/minecraft/server/level/ChunkHolder.java -index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f977e09e7e0 100644 +index cc63e49b7d1b4ba6e8df87aff4cf71036d3de5c5..a37cc96ec26c92a60b0f0ca43d48705cd2bb072e 100644 --- a/net/minecraft/server/level/ChunkHolder.java +++ b/net/minecraft/server/level/ChunkHolder.java -@@ -32,46 +32,125 @@ import net.minecraft.world.level.lighting.LevelLightEngine; - import net.minecraft.server.MinecraftServer; - // CraftBukkit end +@@ -29,27 +29,112 @@ import net.minecraft.world.level.chunk.LevelChunkSection; + import net.minecraft.world.level.chunk.status.ChunkStatus; + import net.minecraft.world.level.lighting.LevelLightEngine; -public class ChunkHolder extends GenerationChunkHolder { +public class ChunkHolder extends GenerationChunkHolder implements ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder { // Paper - rewrite chunk system - public static final ChunkResult<LevelChunk> UNLOADED_LEVEL_CHUNK = ChunkResult.error("Unloaded level chunk"); - private static final CompletableFuture<ChunkResult<LevelChunk>> UNLOADED_LEVEL_CHUNK_FUTURE = CompletableFuture.completedFuture(ChunkHolder.UNLOADED_LEVEL_CHUNK); + private static final CompletableFuture<ChunkResult<LevelChunk>> UNLOADED_LEVEL_CHUNK_FUTURE = CompletableFuture.completedFuture(UNLOADED_LEVEL_CHUNK); private final LevelHeightAccessor levelHeightAccessor; -- private volatile CompletableFuture<ChunkResult<LevelChunk>> fullChunkFuture; private int fullChunkCreateCount; private volatile boolean isFullChunkReady; // Paper - cache chunk ticking stage -- private volatile CompletableFuture<ChunkResult<LevelChunk>> tickingChunkFuture; private volatile boolean isTickingReady; // Paper - cache chunk ticking stage -- private volatile CompletableFuture<ChunkResult<LevelChunk>> entityTickingChunkFuture; private volatile boolean isEntityTickingReady; // Paper - cache chunk ticking stage +- private volatile CompletableFuture<ChunkResult<LevelChunk>> fullChunkFuture = UNLOADED_LEVEL_CHUNK_FUTURE; private int fullChunkCreateCount; private volatile boolean isFullChunkReady; // Paper - cache chunk ticking stage +- private volatile CompletableFuture<ChunkResult<LevelChunk>> tickingChunkFuture = UNLOADED_LEVEL_CHUNK_FUTURE; private volatile boolean isTickingReady; // Paper - cache chunk ticking stage +- private volatile CompletableFuture<ChunkResult<LevelChunk>> entityTickingChunkFuture = UNLOADED_LEVEL_CHUNK_FUTURE; private volatile boolean isEntityTickingReady; // Paper - cache chunk ticking stage - public int oldTicketLevel; - private int ticketLevel; - private int queueLevel; + // Paper - rewrite chunk system private boolean hasChangedSections; private final ShortSet[] changedBlocksPerSection; - private final BitSet blockChangedLightSectionFilter; - private final BitSet skyChangedLightSectionFilter; + private final BitSet blockChangedLightSectionFilter = new BitSet(); + private final BitSet skyChangedLightSectionFilter = new BitSet(); private final LevelLightEngine lightEngine; - private final ChunkHolder.LevelChangeListener onLevelChange; + // Paper - rewrite chunk system public final ChunkHolder.PlayerProvider playerProvider; - private boolean wasAccessibleSinceLastSave; -- private CompletableFuture<?> pendingFullStateConfirmation; -- private CompletableFuture<?> sendSync; -- private CompletableFuture<?> saveSync; +- private CompletableFuture<?> pendingFullStateConfirmation = CompletableFuture.completedFuture(null); +- private CompletableFuture<?> sendSync = CompletableFuture.completedFuture(null); +- private CompletableFuture<?> saveSync = CompletableFuture.completedFuture(null); + // Paper - rewrite chunk system + + // Paper start - rewrite chunk system @@ -24000,31 +23731,23 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 + } + // Paper end - rewrite chunk system - public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) { + public ChunkHolder( + ChunkPos pos, +@@ -62,11 +147,9 @@ public class ChunkHolder extends GenerationChunkHolder { super(pos); -- this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -- this.tickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -- this.entityTickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; + this.levelHeightAccessor = levelHeightAccessor; + this.lightEngine = lightEngine; +- this.onLevelChange = onLevelChange; + // Paper - rewrite chunk system - this.blockChangedLightSectionFilter = new BitSet(); - this.skyChangedLightSectionFilter = new BitSet(); -- this.pendingFullStateConfirmation = CompletableFuture.completedFuture(null); // CraftBukkit - decompile error -- this.sendSync = CompletableFuture.completedFuture(null); // CraftBukkit - decompile error -- this.saveSync = CompletableFuture.completedFuture(null); // CraftBukkit - decompile error -+ // Paper - rewrite chunk system - this.levelHeightAccessor = world; - this.lightEngine = lightingProvider; -- this.onLevelChange = levelUpdateListener; -+ // Paper - rewrite chunk system - this.playerProvider = playersWatchingChunkProvider; + this.playerProvider = playerProvider; - this.oldTicketLevel = ChunkLevel.MAX_LEVEL + 1; - this.ticketLevel = this.oldTicketLevel; - this.queueLevel = this.oldTicketLevel; + // Paper - rewrite chunk system - this.setTicketLevel(level); - this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()]; + this.setTicketLevel(ticketLevel); + this.changedBlocksPerSection = new ShortSet[levelHeightAccessor.getSectionsCount()]; } -@@ -79,7 +158,7 @@ public class ChunkHolder extends GenerationChunkHolder { +@@ -74,7 +157,7 @@ public class ChunkHolder extends GenerationChunkHolder { // CraftBukkit start public LevelChunk getFullChunkNow() { // Note: We use the oldTicketLevel for isLoaded checks. @@ -24033,7 +23756,7 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 return this.getFullChunkNowUnchecked(); } -@@ -89,64 +168,65 @@ public class ChunkHolder extends GenerationChunkHolder { +@@ -84,58 +167,63 @@ public class ChunkHolder extends GenerationChunkHolder { // CraftBukkit end public CompletableFuture<ChunkResult<LevelChunk>> getTickingChunkFuture() { @@ -24052,8 +23775,8 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 } @Nullable - public final LevelChunk getTickingChunk() { // Paper - final for inline -- return (LevelChunk) ((ChunkResult) this.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).orElse(null); // CraftBukkit - decompile error + public LevelChunk getTickingChunk() { +- return this.getTickingChunkFuture().getNow(UNLOADED_LEVEL_CHUNK).orElse(null); + // Paper start - rewrite chunk system + if (this.newChunkHolder.isTickingReady()) { + if (this.newChunkHolder.getCurrentChunk() instanceof LevelChunk levelChunk) { @@ -24081,16 +23804,13 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public void addSendDependency(CompletableFuture<?> postProcessingFuture) { + public void addSendDependency(CompletableFuture<?> dependency) { - if (this.sendSync.isDone()) { -- this.sendSync = postProcessingFuture; +- this.sendSync = dependency; - } else { -- this.sendSync = this.sendSync.thenCombine(postProcessingFuture, (object, object1) -> { -- return null; -- }); +- this.sendSync = this.sendSync.thenCombine((CompletionStage<? extends Object>)dependency, (object, object1) -> null); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system - } public CompletableFuture<?> getSaveSyncFuture() { @@ -24104,52 +23824,49 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 } @Override - protected void addSaveDependency(CompletableFuture<?> savingFuture) { + protected void addSaveDependency(CompletableFuture<?> dependency) { - if (this.saveSync.isDone()) { -- this.saveSync = savingFuture; +- this.saveSync = dependency; - } else { -- this.saveSync = this.saveSync.thenCombine(savingFuture, (object, object1) -> { -- return null; -- }); +- this.saveSync = this.saveSync.thenCombine((CompletionStage<? extends Object>)dependency, (object, object1) -> null); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system - } public boolean blockChanged(BlockPos pos) { -- LevelChunk chunk = this.getTickingChunk(); -+ LevelChunk chunk = this.playersSentChunkTo.size() == 0 ? null : this.getChunkToSend(); // Paper - rewrite chunk system - - if (chunk == null) { +- LevelChunk tickingChunk = this.getTickingChunk(); ++ LevelChunk tickingChunk = this.playersSentChunkTo.size() == 0 ? null : this.getChunkToSend(); // Paper - rewrite chunk system + if (tickingChunk == null) { return false; -@@ -172,7 +252,7 @@ public class ChunkHolder extends GenerationChunkHolder { + } else { +@@ -158,7 +246,7 @@ public class ChunkHolder extends GenerationChunkHolder { return false; } else { - ichunkaccess.markUnsaved(); -- LevelChunk chunk = this.getTickingChunk(); -+ LevelChunk chunk = this.playersSentChunkTo.size() == 0 ? null : this.getChunkToSend(); // Paper - rewrite chunk system - - if (chunk == null) { + chunkIfPresent.markUnsaved(); +- LevelChunk tickingChunk = this.getTickingChunk(); ++ LevelChunk tickingChunk = this.playersSentChunkTo.size() == 0 ? null : this.getChunkToSend(); // Paper - rewrite chunk system + if (tickingChunk == null) { return false; -@@ -207,7 +287,7 @@ public class ChunkHolder extends GenerationChunkHolder { - List list; - + } else { +@@ -188,7 +276,7 @@ public class ChunkHolder extends GenerationChunkHolder { + if (this.hasChangesToBroadcast()) { + Level level = chunk.getLevel(); if (!this.skyChangedLightSectionFilter.isEmpty() || !this.blockChangedLightSectionFilter.isEmpty()) { -- list = this.playerProvider.getPlayers(this.pos, true); -+ list = this.moonrise$getPlayers(true); // Paper - rewrite chunk system - if (!list.isEmpty()) { - ClientboundLightUpdatePacket packetplayoutlightupdate = new ClientboundLightUpdatePacket(chunk.getPos(), this.lightEngine, this.skyChangedLightSectionFilter, this.blockChangedLightSectionFilter); - -@@ -219,7 +299,7 @@ public class ChunkHolder extends GenerationChunkHolder { +- List<ServerPlayer> players = this.playerProvider.getPlayers(this.pos, true); ++ List<ServerPlayer> players = this.moonrise$getPlayers(true); // Paper - rewrite chunk system + if (!players.isEmpty()) { + ClientboundLightUpdatePacket clientboundLightUpdatePacket = new ClientboundLightUpdatePacket( + chunk.getPos(), this.lightEngine, this.skyChangedLightSectionFilter, this.blockChangedLightSectionFilter +@@ -201,7 +289,7 @@ public class ChunkHolder extends GenerationChunkHolder { } if (this.hasChangedSections) { -- list = this.playerProvider.getPlayers(this.pos, false); -+ list = this.moonrise$getPlayers(false); // Paper - rewrite chunk system +- List<ServerPlayer> players = this.playerProvider.getPlayers(this.pos, false); ++ List<ServerPlayer> players = this.moonrise$getPlayers(false); // Paper - rewrite chunk system - for (int i = 0; i < this.changedBlocksPerSection.length; ++i) { - ShortSet shortset = this.changedBlocksPerSection[i]; -@@ -285,201 +365,48 @@ public class ChunkHolder extends GenerationChunkHolder { + for (int i = 0; i < this.changedBlocksPerSection.length; i++) { + ShortSet set = this.changedBlocksPerSection[i]; +@@ -256,193 +344,50 @@ public class ChunkHolder extends GenerationChunkHolder { @Override public int getTicketLevel() { @@ -24163,8 +23880,8 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void setQueueLevel(int level) { -- this.queueLevel = level; + private void setQueueLevel(int queueLevel) { +- this.queueLevel = queueLevel; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -24173,41 +23890,36 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 + // Paper - rewrite chunk system } - private void scheduleFullChunkPromotion(ChunkMap chunkLoadingManager, CompletableFuture<ChunkResult<LevelChunk>> chunkFuture, Executor executor, FullChunkStatus target) { + private void scheduleFullChunkPromotion( + ChunkMap chunkMap, CompletableFuture<ChunkResult<LevelChunk>> future, Executor executor, FullChunkStatus fullChunkStatus + ) { - this.pendingFullStateConfirmation.cancel(false); -- CompletableFuture<Void> completablefuture1 = new CompletableFuture(); -- -- completablefuture1.thenRunAsync(() -> { -- chunkLoadingManager.onFullChunkStatusChange(this.pos, target); -- }, executor); -- this.pendingFullStateConfirmation = completablefuture1; -- chunkFuture.thenAccept((chunkresult) -> { -- chunkresult.ifSuccess((chunk) -> { -- completablefuture1.complete(null); // CraftBukkit - decompile error -- }); -- }); +- CompletableFuture<Void> completableFuture = new CompletableFuture<>(); +- completableFuture.thenRunAsync(() -> chunkMap.onFullChunkStatusChange(this.pos, fullChunkStatus), executor); +- this.pendingFullStateConfirmation = completableFuture; +- future.thenAccept(chunkResult -> chunkResult.ifSuccess(levelChunk -> completableFuture.complete(null))); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void demoteFullChunk(ChunkMap chunkLoadingManager, FullChunkStatus target) { + private void demoteFullChunk(ChunkMap chunkMap, FullChunkStatus fullChunkStatus) { - this.pendingFullStateConfirmation.cancel(false); -- chunkLoadingManager.onFullChunkStatusChange(this.pos, target); +- chunkMap.onFullChunkStatusChange(this.pos, fullChunkStatus); + 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) { + protected void callEventIfUnloading(ChunkMap chunkMap) { - FullChunkStatus oldFullChunkStatus = ChunkLevel.fullStatus(this.oldTicketLevel); - FullChunkStatus newFullChunkStatus = ChunkLevel.fullStatus(this.ticketLevel); - boolean oldIsFull = oldFullChunkStatus.isOrAfter(FullChunkStatus.FULL); - boolean newIsFull = newFullChunkStatus.isOrAfter(FullChunkStatus.FULL); - if (oldIsFull && !newIsFull) { - this.getFullChunkFuture().thenAccept((either) -> { -- LevelChunk chunk = (LevelChunk) either.orElse(null); +- LevelChunk chunk = either.orElse(null); - if (chunk != null) { -- playerchunkmap.callbackExecutor.execute(() -> { +- chunkMap.callbackExecutor.execute(() -> { - // 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. @@ -24217,34 +23929,33 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 - } - }).exceptionally((throwable) -> { - // ensure exceptions are printed, by default this is not the case -- MinecraftServer.LOGGER.error("Failed to schedule unload callback for chunk " + ChunkHolder.this.pos, throwable); +- net.minecraft.server.MinecraftServer.LOGGER.error("Failed to schedule unload callback for chunk " + ChunkHolder.this.pos, throwable); - return null; - }); - - // Run callback right away if the future was already done -- playerchunkmap.callbackExecutor.run(); +- chunkMap.callbackExecutor.run(); - } + 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); -- boolean flag = fullchunkstatus.isOrAfter(FullChunkStatus.FULL); -- boolean flag1 = fullchunkstatus1.isOrAfter(FullChunkStatus.FULL); -- -- this.wasAccessibleSinceLastSave |= flag1; -- if (!flag && flag1) { + protected void updateFutures(ChunkMap chunkMap, Executor executor) { +- FullChunkStatus fullChunkStatus = ChunkLevel.fullStatus(this.oldTicketLevel); +- FullChunkStatus fullChunkStatus1 = ChunkLevel.fullStatus(this.ticketLevel); +- boolean isOrAfter = fullChunkStatus.isOrAfter(FullChunkStatus.FULL); +- boolean isOrAfter1 = fullChunkStatus1.isOrAfter(FullChunkStatus.FULL); +- this.wasAccessibleSinceLastSave |= isOrAfter1; +- if (!isOrAfter && isOrAfter1) { - int expectCreateCount = ++this.fullChunkCreateCount; // Paper -- this.fullChunkFuture = chunkLoadingManager.prepareAccessibleChunk(this); -- this.scheduleFullChunkPromotion(chunkLoadingManager, this.fullChunkFuture, executor, FullChunkStatus.FULL); +- this.fullChunkFuture = chunkMap.prepareAccessibleChunk(this); +- this.scheduleFullChunkPromotion(chunkMap, this.fullChunkFuture, executor, FullChunkStatus.FULL); - // Paper start - cache ticking ready status - this.fullChunkFuture.thenAccept(chunkResult -> { - chunkResult.ifSuccess(chunk -> { - if (ChunkHolder.this.fullChunkCreateCount == expectCreateCount) { - ChunkHolder.this.isFullChunkReady = true; -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkBorder(chunk, this); +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkBorder(chunk, this); - } - }); - }); @@ -24252,99 +23963,97 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 - this.addSaveDependency(this.fullChunkFuture); - } - -- if (flag && !flag1) { +- if (isOrAfter && !isOrAfter1) { - // Paper start - if (this.isFullChunkReady) { -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkNotBorder(this.fullChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkNotBorder(this.fullChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper - } - // Paper end -- this.fullChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); -- this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; +- this.fullChunkFuture.complete(UNLOADED_LEVEL_CHUNK); +- this.fullChunkFuture = UNLOADED_LEVEL_CHUNK_FUTURE; - } - -- boolean flag2 = fullchunkstatus.isOrAfter(FullChunkStatus.BLOCK_TICKING); -- boolean flag3 = fullchunkstatus1.isOrAfter(FullChunkStatus.BLOCK_TICKING); -- -- if (!flag2 && flag3) { -- this.tickingChunkFuture = chunkLoadingManager.prepareTickingChunk(this); -- this.scheduleFullChunkPromotion(chunkLoadingManager, this.tickingChunkFuture, executor, FullChunkStatus.BLOCK_TICKING); +- boolean isOrAfter2 = fullChunkStatus.isOrAfter(FullChunkStatus.BLOCK_TICKING); +- boolean isOrAfter3 = fullChunkStatus1.isOrAfter(FullChunkStatus.BLOCK_TICKING); +- if (!isOrAfter2 && isOrAfter3) { +- this.tickingChunkFuture = chunkMap.prepareTickingChunk(this); +- this.scheduleFullChunkPromotion(chunkMap, this.tickingChunkFuture, executor, FullChunkStatus.BLOCK_TICKING); - // Paper start - cache ticking ready status - this.tickingChunkFuture.thenAccept(chunkResult -> { - chunkResult.ifSuccess(chunk -> { - // note: Here is a very good place to add callbacks to logic waiting on this. - ChunkHolder.this.isTickingReady = true; -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkTicking(chunk, this); +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkTicking(chunk, this); - }); - }); - // Paper end - this.addSaveDependency(this.tickingChunkFuture); - } - -- if (flag2 && !flag3) { +- if (isOrAfter2 && !isOrAfter3) { - // Paper start - if (this.isTickingReady) { -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkNotTicking(this.tickingChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper - } - // Paper end - this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage -- this.tickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; +- this.tickingChunkFuture = UNLOADED_LEVEL_CHUNK_FUTURE; - } - -- boolean flag4 = fullchunkstatus.isOrAfter(FullChunkStatus.ENTITY_TICKING); -- boolean flag5 = fullchunkstatus1.isOrAfter(FullChunkStatus.ENTITY_TICKING); -- -- if (!flag4 && flag5) { -- if (this.entityTickingChunkFuture != ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE) { -- throw (IllegalStateException) Util.pauseInIde(new IllegalStateException()); +- boolean isOrAfter4 = fullChunkStatus.isOrAfter(FullChunkStatus.ENTITY_TICKING); +- boolean isOrAfter5 = fullChunkStatus1.isOrAfter(FullChunkStatus.ENTITY_TICKING); +- if (!isOrAfter4 && isOrAfter5) { +- if (this.entityTickingChunkFuture != UNLOADED_LEVEL_CHUNK_FUTURE) { +- throw (IllegalStateException)Util.pauseInIde(new IllegalStateException()); - } - -- this.entityTickingChunkFuture = chunkLoadingManager.prepareEntityTickingChunk(this); -- this.scheduleFullChunkPromotion(chunkLoadingManager, this.entityTickingChunkFuture, executor, FullChunkStatus.ENTITY_TICKING); +- this.entityTickingChunkFuture = chunkMap.prepareEntityTickingChunk(this); +- this.scheduleFullChunkPromotion(chunkMap, this.entityTickingChunkFuture, executor, FullChunkStatus.ENTITY_TICKING); - // Paper start - cache ticking ready status - this.entityTickingChunkFuture.thenAccept(chunkResult -> { - chunkResult.ifSuccess(chunk -> { - ChunkHolder.this.isEntityTickingReady = true; -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkEntityTicking(chunk, this); +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkEntityTicking(chunk, this); - }); - }); - // Paper end - this.addSaveDependency(this.entityTickingChunkFuture); - } - -- if (flag4 && !flag5) { +- if (isOrAfter4 && !isOrAfter5) { - // Paper start - if (this.isEntityTickingReady) { -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().orElseThrow(IllegalStateException::new), this); +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkNotEntityTicking(this.entityTickingChunkFuture.join().orElseThrow(IllegalStateException::new), this); - } - // Paper end - this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage -- this.entityTickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; +- this.entityTickingChunkFuture = UNLOADED_LEVEL_CHUNK_FUTURE; - } - -- if (!fullchunkstatus1.isOrAfter(fullchunkstatus)) { -- this.demoteFullChunk(chunkLoadingManager, fullchunkstatus1); +- if (!fullChunkStatus1.isOrAfter(fullChunkStatus)) { +- this.demoteFullChunk(chunkMap, fullChunkStatus1); - } - - this.onLevelChange.onLevelChange(this.pos, this::getQueueLevel, this.ticketLevel, this::setQueueLevel); - this.oldTicketLevel = this.ticketLevel; - // CraftBukkit start - // ChunkLoadEvent: Called after the chunk is loaded: isChunkLoaded returns true and chunk is ready to be modified by plugins. -- if (!fullchunkstatus.isOrAfter(FullChunkStatus.FULL) && fullchunkstatus1.isOrAfter(FullChunkStatus.FULL)) { +- if (!fullChunkStatus.isOrAfter(FullChunkStatus.FULL) && fullChunkStatus1.isOrAfter(FullChunkStatus.FULL)) { - this.getFullChunkFuture().thenAccept((either) -> { - LevelChunk chunk = (LevelChunk) either.orElse(null); - if (chunk != null) { -- chunkLoadingManager.callbackExecutor.execute(() -> { +- chunkMap.callbackExecutor.execute(() -> { - chunk.loadCallback(); - }); - } - }).exceptionally((throwable) -> { - // ensure exceptions are printed, by default this is not the case -- MinecraftServer.LOGGER.error("Failed to schedule load callback for chunk " + ChunkHolder.this.pos, throwable); +- net.minecraft.server.MinecraftServer.LOGGER.error("Failed to schedule load callback for chunk " + ChunkHolder.this.pos, throwable); - return null; - }); - - // Run callback right away if the future was already done -- chunkLoadingManager.callbackExecutor.run(); +- chunkMap.callbackExecutor.run(); - } - // CraftBukkit end + throw new UnsupportedOperationException(); // Paper - rewrite chunk system @@ -24362,7 +24071,7 @@ index b9ab241b930edc63a39dbbcf14cd0b5edacb9ea9..8dd9375f2ad2c65a773a3195aeff1f97 @FunctionalInterface diff --git a/net/minecraft/server/level/ChunkLevel.java b/net/minecraft/server/level/ChunkLevel.java -index 11b30b6daa1d049634350e34502c701e9800add4..fae17a075d7efaf24d916877dd5968eb9652bb66 100644 +index e823b8aac00158892538083bc877ccf99895909a..7d871318065f19540748363809de82652613e733 100644 --- a/net/minecraft/server/level/ChunkLevel.java +++ b/net/minecraft/server/level/ChunkLevel.java @@ -7,8 +7,8 @@ import net.minecraft.world.level.chunk.status.ChunkStep; @@ -24377,50 +24086,50 @@ index 11b30b6daa1d049634350e34502c701e9800add4..fae17a075d7efaf24d916877dd5968eb private static final ChunkStep FULL_CHUNK_STEP = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.FULL); public static final int RADIUS_AROUND_FULL_CHUNK = FULL_CHUNK_STEP.accumulatedDependencies().getRadius(); diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e11526dfd7c2f 100644 +index 8c1eea5339b650bd1527b5b3aa010c12d70a6de1..86aaf32de5d80ee222cbe7eff0f6c119a032e04f 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java -@@ -108,7 +108,7 @@ import org.slf4j.Logger; - import org.bukkit.craftbukkit.generator.CustomChunkGenerator; - // CraftBukkit end +@@ -96,7 +96,7 @@ import net.minecraft.world.level.storage.LevelStorageSource; + import org.apache.commons.lang3.mutable.MutableBoolean; + import org.slf4j.Logger; -public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider, GeneratingChunkMap { +public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider, GeneratingChunkMap, ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemChunkMap { // Paper - rewrite chunk system - private static final ChunkResult<List<ChunkAccess>> UNLOADED_CHUNK_LIST_RESULT = ChunkResult.error("Unloaded chunks found in range"); - private static final CompletableFuture<ChunkResult<List<ChunkAccess>>> UNLOADED_CHUNK_LIST_FUTURE = CompletableFuture.completedFuture(ChunkMap.UNLOADED_CHUNK_LIST_RESULT); -@@ -123,10 +123,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private static final CompletableFuture<ChunkResult<List<ChunkAccess>>> UNLOADED_CHUNK_LIST_FUTURE = CompletableFuture.completedFuture( + UNLOADED_CHUNK_LIST_RESULT +@@ -112,10 +112,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public static final int MIN_VIEW_DISTANCE = 2; public static final int MAX_VIEW_DISTANCE = 32; public static final int FORCED_TICKET_LEVEL = ChunkLevel.byStatus(FullChunkStatus.ENTITY_TICKING); -- public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); -- public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap; -- private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads; -- private final List<ChunkGenerationTask> pendingGenerationTasks; +- public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap<>(); +- public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap = this.updatingChunkMap.clone(); +- private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads = new Long2ObjectLinkedOpenHashMap<>(); +- private final List<ChunkGenerationTask> pendingGenerationTasks = new ArrayList<>(); + // Paper - rewrite chunk system public final ServerLevel level; private final ThreadedLevelLightEngine lightEngine; private final BlockableEventLoop<Runnable> mainThreadExecutor; -@@ -136,22 +133,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -125,22 +122,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private final PoiManager poiManager; - public final LongSet toDrop; + public final LongSet toDrop = new LongOpenHashSet(); private boolean modified; - private final ChunkTaskDispatcher worldgenTaskDispatcher; - private final ChunkTaskDispatcher lightTaskDispatcher; + // Paper - rewrite chunk system public final ChunkProgressListener progressListener; private final ChunkStatusUpdateListener chunkStatusListener; - public final ChunkMap.ChunkDistanceManager distanceManager; -- private final AtomicInteger tickingGenerated; -+ public final AtomicInteger tickingGenerated; // Paper - public + public final ChunkMap.DistanceManager distanceManager; +- private final AtomicInteger tickingGenerated = new AtomicInteger(); ++ public final AtomicInteger tickingGenerated = new AtomicInteger(); // Paper - public private final String storageName; - private final PlayerMap playerMap; - public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap; - private final Long2ByteMap chunkTypeCache; -- private final Long2LongMap nextChunkSaveTime; -- private final LongSet chunksToEagerlySave; -- private final Queue<Runnable> unloadQueue; -- private final AtomicInteger activeChunkWrites; + private final PlayerMap playerMap = new PlayerMap(); + public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap = new Int2ObjectOpenHashMap<>(); + private final Long2ByteMap chunkTypeCache = new Long2ByteOpenHashMap(); +- private final Long2LongMap nextChunkSaveTime = new Long2LongOpenHashMap(); +- private final LongSet chunksToEagerlySave = new LongLinkedOpenHashSet(); +- private final Queue<Runnable> unloadQueue = Queues.newConcurrentLinkedQueue(); +- private final AtomicInteger activeChunkWrites = new AtomicInteger(); + // Paper - rewrite chunk system public int serverViewDistance; - private final WorldGenContext worldGenContext; @@ -24428,7 +24137,7 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback() public final CallbackExecutor callbackExecutor = new CallbackExecutor(); -@@ -176,24 +169,26 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -165,9 +158,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper start public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) { @@ -24444,62 +24153,50 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + } + // Paper end - rewrite chunk system - public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) { - super(new RegionStorageInfo(session.getLevelId(), world.dimension(), "chunk"), session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); -- this.visibleChunkMap = this.updatingChunkMap.clone(); -- this.pendingUnloads = new Long2ObjectLinkedOpenHashMap(); -- this.pendingGenerationTasks = new ArrayList(); -+ // Paper - rewrite chunk system - this.toDrop = new LongOpenHashSet(); - this.tickingGenerated = new AtomicInteger(); - this.playerMap = new PlayerMap(); - this.entityMap = new Int2ObjectOpenHashMap(); - this.chunkTypeCache = new Long2ByteOpenHashMap(); -- this.nextChunkSaveTime = new Long2LongOpenHashMap(); -- this.chunksToEagerlySave = new LongLinkedOpenHashSet(); -- this.unloadQueue = Queues.newConcurrentLinkedQueue(); -- this.activeChunkWrites = new AtomicInteger(); + public ChunkMap( + ServerLevel level, +@@ -213,10 +213,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + this.progressListener = progressListener; + this.chunkStatusListener = chunkStatusListener; + ConsecutiveExecutor consecutiveExecutor1 = new ConsecutiveExecutor(dispatcher, "light"); +- this.worldgenTaskDispatcher = new ChunkTaskDispatcher(consecutiveExecutor, dispatcher); +- this.lightTaskDispatcher = new ChunkTaskDispatcher(consecutiveExecutor1, dispatcher); + // Paper - rewrite chunk system - Path path = session.getDimensionPath(world.dimension()); - - this.storageName = path.getFileName().toString(); -@@ -221,18 +216,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.chunkStatusListener = chunkStatusChangeListener; - ConsecutiveExecutor consecutiveexecutor1 = new ConsecutiveExecutor(executor, "light"); - -- 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.lightEngine = new ThreadedLevelLightEngine( +- lightChunk, this, this.level.dimensionType().hasSkyLight(), consecutiveExecutor1, this.lightTaskDispatcher ++ lightChunk, this, this.level.dimensionType().hasSkyLight(), consecutiveExecutor1, null // Paper - rewrite chunk system + ); + this.distanceManager = new ChunkMap.DistanceManager(dispatcher, mainThreadExecutor); + this.overworldDataStorage = overworldDataStorage; +@@ -230,11 +229,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + level + ); this.setServerViewDistance(viewDistance); -- 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 +- this.worldGenContext = new WorldGenContext(level, generator, structureManager, this.lightEngine, mainThreadExecutor, this::setChunkUnsaved); ++ this.worldGenContext = new WorldGenContext(level, generator, structureManager, this.lightEngine, null, this::setChunkUnsaved); // Paper - rewrite chunk system } - private void setChunkUnsaved(ChunkPos pos) { -- this.chunksToEagerlySave.add(pos.toLong()); + private void setChunkUnsaved(ChunkPos chunkPos) { +- this.chunksToEagerlySave.add(chunkPos.toLong()); + // Paper - rewrite chunk system } // Paper start -@@ -263,23 +256,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -264,23 +263,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - boolean isChunkTracked(ServerPlayer player, int chunkX, int chunkZ) { -- return player.getChunkTrackingView().contains(chunkX, chunkZ) && !player.connection.chunkSender.isPending(ChunkPos.asLong(chunkX, chunkZ)); -+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().isChunkSent(player, chunkX, chunkZ); // Paper - rewrite chunk system + boolean isChunkTracked(ServerPlayer player, int x, int z) { +- return player.getChunkTrackingView().contains(x, z) && !player.connection.chunkSender.isPending(ChunkPos.asLong(x, z)); ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().isChunkSent(player, x, z); // Paper - rewrite chunk system } - private boolean isChunkOnTrackedBorder(ServerPlayer player, int chunkX, int chunkZ) { -- if (!this.isChunkTracked(player, chunkX, chunkZ)) { + private boolean isChunkOnTrackedBorder(ServerPlayer player, int x, int z) { +- if (!this.isChunkTracked(player, x, z)) { - return false; - } else { -- for (int k = -1; k <= 1; ++k) { -- for (int l = -1; l <= 1; ++l) { -- if ((k != 0 || l != 0) && !this.isChunkTracked(player, chunkX + k, chunkZ + l)) { +- for (int i = -1; i <= 1; i++) { +- for (int i1 = -1; i1 <= 1; i1++) { +- if ((i != 0 || i1 != 0) && !this.isChunkTracked(player, x + i, z + i1)) { - return true; - } - } @@ -24507,15 +24204,15 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 - - return false; - } -+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().isChunkSent(player, chunkX, chunkZ, true); // Paper - rewrite chunk system ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().isChunkSent(player, x, z, true); // Paper - rewrite chunk system } protected ThreadedLevelLightEngine getLightEngine() { -@@ -288,20 +269,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -289,21 +276,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Nullable - protected ChunkHolder getUpdatingChunkIfPresent(long pos) { -- return (ChunkHolder) this.updatingChunkMap.get(pos); + protected ChunkHolder getUpdatingChunkIfPresent(long chunkPos) { +- return this.updatingChunkMap.get(chunkPos); + // Paper start - rewrite chunk system + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(pos); + return holder == null ? null : holder.vanillaChunkHolder; @@ -24523,73 +24220,65 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 } @Nullable - public ChunkHolder getVisibleChunkIfPresent(long pos) { -- return (ChunkHolder) this.visibleChunkMap.get(pos); + public ChunkHolder getVisibleChunkIfPresent(long chunkPos) { +- return this.visibleChunkMap.get(chunkPos); + // Paper start - rewrite chunk system + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(pos); + return holder == null ? null : holder.vanillaChunkHolder; + // Paper end - rewrite chunk system } - protected IntSupplier getChunkQueueLevel(long pos) { + protected IntSupplier getChunkQueueLevel(long chunkPos) { - return () -> { -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); -- -- return playerchunk == null ? ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1 : Math.min(playerchunk.getQueueLevel(), ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1); +- ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(chunkPos); +- return visibleChunkIfPresent == null +- ? ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1 +- : Math.min(visibleChunkIfPresent.getQueueLevel(), ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1); - }; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public String getChunkDebugData(ChunkPos chunkPos) { -@@ -330,56 +313,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + public String getChunkDebugData(ChunkPos pos) { +@@ -329,47 +317,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - private CompletableFuture<ChunkResult<List<ChunkAccess>>> getChunkRangeFuture(ChunkHolder centerChunk, int margin, IntFunction<ChunkStatus> distanceToStatus) { -- if (margin == 0) { -- ChunkStatus chunkstatus = (ChunkStatus) distanceToStatus.apply(0); -- -- return centerChunk.scheduleChunkGenerationTask(chunkstatus, this).thenApply((chunkresult) -> { -- return chunkresult.map(List::of); -- }); + private CompletableFuture<ChunkResult<List<ChunkAccess>>> getChunkRangeFuture(ChunkHolder chunkHolder, int range, IntFunction<ChunkStatus> statusGetter) { +- if (range == 0) { +- ChunkStatus chunkStatus = statusGetter.apply(0); +- return chunkHolder.scheduleChunkGenerationTask(chunkStatus, this).thenApply(chunkResult -> chunkResult.map(List::of)); - } else { -- int j = Mth.square(margin * 2 + 1); -- List<CompletableFuture<ChunkResult<ChunkAccess>>> list = new ArrayList(j); -- ChunkPos chunkcoordintpair = centerChunk.getPos(); -- -- 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; +- int squared = Mth.square(range * 2 + 1); +- List<CompletableFuture<ChunkResult<ChunkAccess>>> list = new ArrayList<>(squared); +- ChunkPos pos = chunkHolder.getPos(); +- +- for (int i = -range; i <= range; i++) { +- for (int i1 = -range; i1 <= range; i1++) { +- int max = Math.max(Math.abs(i1), Math.abs(i)); +- long packedChunkPos = ChunkPos.asLong(pos.x + i1, pos.z + i); +- ChunkHolder updatingChunkIfPresent = this.getUpdatingChunkIfPresent(packedChunkPos); +- if (updatingChunkIfPresent == null) { +- return UNLOADED_CHUNK_LIST_FUTURE; - } - -- ChunkStatus chunkstatus1 = (ChunkStatus) distanceToStatus.apply(i1); -- -- list.add(playerchunk1.scheduleChunkGenerationTask(chunkstatus1, this)); +- ChunkStatus chunkStatus1 = statusGetter.apply(max); +- list.add(updatingChunkIfPresent.scheduleChunkGenerationTask(chunkStatus1, this)); - } - } - -- return Util.sequence(list).thenApply((list1) -> { -- List<ChunkAccess> list2 = new ArrayList(list1.size()); -- Iterator iterator = list1.iterator(); -- -- while (iterator.hasNext()) { -- ChunkResult<ChunkAccess> chunkresult = (ChunkResult) iterator.next(); +- return Util.sequence(list).thenApply(list1 -> { +- List<ChunkAccess> list2 = new ArrayList<>(list1.size()); - -- if (chunkresult == null) { +- for (ChunkResult<ChunkAccess> chunkResult : list1) { +- if (chunkResult == null) { - throw this.debugFuturesAndCreateReportedException(new IllegalStateException("At least one of the chunk futures were null"), "n/a"); - } - -- ChunkAccess ichunkaccess = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error -- -- if (ichunkaccess == null) { -- return ChunkMap.UNLOADED_CHUNK_LIST_RESULT; +- ChunkAccess chunkAccess = chunkResult.orElse(null); +- if (chunkAccess == null) { +- return UNLOADED_CHUNK_LIST_RESULT; - } - -- list2.add(ichunkaccess); +- list2.add(chunkAccess); - } - - return ChunkResult.of(list2); @@ -24599,49 +24288,44 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 } public ReportedException debugFuturesAndCreateReportedException(IllegalStateException exception, String details) { -@@ -409,104 +343,30 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -401,95 +349,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - public CompletableFuture<ChunkResult<LevelChunk>> prepareEntityTickingChunk(ChunkHolder holder) { -- return this.getChunkRangeFuture(holder, 2, (i) -> { -- return ChunkStatus.FULL; -- }).thenApply((chunkresult) -> { -- return chunkresult.map((list) -> { -- return (LevelChunk) list.get(list.size() / 2); -- }); -- }); + public CompletableFuture<ChunkResult<LevelChunk>> prepareEntityTickingChunk(ChunkHolder chunk) { +- return this.getChunkRangeFuture(chunk, 2, i -> ChunkStatus.FULL) +- .thenApply(chunkResult -> chunkResult.map(list -> (LevelChunk)list.get(list.size() / 2))); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @Nullable - ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k) { -- if (!ChunkLevel.isLoaded(k) && !ChunkLevel.isLoaded(level)) { + ChunkHolder updateChunkScheduling(long chunkPos, int newLevel, @Nullable ChunkHolder holder, int oldLevel) { +- if (!ChunkLevel.isLoaded(oldLevel) && !ChunkLevel.isLoaded(newLevel)) { - return holder; - } else { - if (holder != null) { -- holder.setTicketLevel(level); +- holder.setTicketLevel(newLevel); - } - - if (holder != null) { -- if (!ChunkLevel.isLoaded(level)) { -- this.toDrop.add(pos); +- if (!ChunkLevel.isLoaded(newLevel)) { +- this.toDrop.add(chunkPos); - } else { -- this.toDrop.remove(pos); +- this.toDrop.remove(chunkPos); - } - } - -- if (ChunkLevel.isLoaded(level) && holder == null) { -- holder = (ChunkHolder) this.pendingUnloads.remove(pos); +- if (ChunkLevel.isLoaded(newLevel) && holder == null) { +- holder = this.pendingUnloads.remove(chunkPos); - if (holder != null) { -- holder.setTicketLevel(level); +- holder.setTicketLevel(newLevel); - } else { -- holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this::onLevelChange, this); +- holder = new ChunkHolder(new ChunkPos(chunkPos), newLevel, this.level, this.lightEngine, this::onLevelChange, this); - // Paper start -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderCreate(this.level, holder); +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderCreate(this.level, holder); - // Paper end - } - -- this.updatingChunkMap.put(pos, holder); +- this.updatingChunkMap.put(chunkPos, holder); - this.modified = true; - } - @@ -24650,9 +24334,9 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void onLevelChange(ChunkPos pos, IntSupplier levelGetter, int targetLevel, IntConsumer levelSetter) { -- this.worldgenTaskDispatcher.onLevelChange(pos, levelGetter, targetLevel, levelSetter); -- this.lightTaskDispatcher.onLevelChange(pos, levelGetter, targetLevel, levelSetter); + private void onLevelChange(ChunkPos chunkPos, IntSupplier queueLevelGetter, int ticketLevel, IntConsumer queueLevelSetter) { +- this.worldgenTaskDispatcher.onLevelChange(chunkPos, queueLevelGetter, ticketLevel, queueLevelSetter); +- this.lightTaskDispatcher.onLevelChange(chunkPos, queueLevelGetter, ticketLevel, queueLevelSetter); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -24666,43 +24350,39 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 - super.close(); - } + throw new UnsupportedOperationException("Use ServerChunkCache#close"); // Paper - rewrite chunk system - } protected void saveAllChunks(boolean flush) { - if (flush) { -- List<ChunkHolder> list = ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).toList(); // Paper -- MutableBoolean mutableboolean = new MutableBoolean(); +- List<ChunkHolder> list = ca.spottedleaf.moonrise.common.PlatformHooks.get().getVisibleChunkHolders(this.level) // Paper - moonrise +- //.values() // Paper - moonrise +- .stream() +- .filter(ChunkHolder::wasAccessibleSinceLastSave) +- .peek(ChunkHolder::refreshAccessibility) +- .toList(); +- MutableBoolean mutableBoolean = new MutableBoolean(); - - do { -- mutableboolean.setFalse(); -- list.stream().map((playerchunk) -> { -- BlockableEventLoop iasynctaskhandler = this.mainThreadExecutor; -- -- Objects.requireNonNull(playerchunk); -- iasynctaskhandler.managedBlock(playerchunk::isReadyForSaving); -- return playerchunk.getLatestChunk(); -- }).filter((ichunkaccess) -> { -- return ichunkaccess instanceof ImposterProtoChunk || ichunkaccess instanceof LevelChunk; -- }).filter(this::save).forEach((ichunkaccess) -> { -- mutableboolean.setTrue(); -- }); -- } while (mutableboolean.isTrue()); +- mutableBoolean.setFalse(); +- list.stream() +- .map(chunk -> { +- this.mainThreadExecutor.managedBlock(chunk::isReadyForSaving); +- return chunk.getLatestChunk(); +- }) +- .filter(chunk -> chunk instanceof ImposterProtoChunk || chunk instanceof LevelChunk) +- .filter(this::save) +- .forEach(chunk -> mutableBoolean.setTrue()); +- } while (mutableBoolean.isTrue()); - - this.poiManager.flushAll(); -- this.processUnloads(() -> { -- return true; -- }); +- this.processUnloads(() -> true); - this.flushWorker(); - } else { - this.nextChunkSaveTime.clear(); -- long i = Util.getMillis(); -- Iterator<ChunkHolder> objectiterator = ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper -- -- while (objectiterator.hasNext()) { -- ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); +- long millis = Util.getMillis(); - -- this.saveChunkIfNeeded(playerchunk, i); +- for (ChunkHolder chunkHolder : ca.spottedleaf.moonrise.common.PlatformHooks.get().getVisibleChunkHolders(this.level)) { // Paper +- this.saveChunkIfNeeded(chunkHolder, millis); - } - } + // Paper start - rewrite chunk system @@ -24710,112 +24390,104 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + flush, false, false + ); + // Paper end - rewrite chunk system - } -@@ -524,143 +384,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + protected void tick(BooleanSupplier hasMoreTime) { +@@ -505,130 +387,28 @@ 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.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.worldgenTaskDispatcher.hasWork() || this.lightTaskDispatcher.hasWork() || this.distanceManager.hasTickets(); +- return this.lightEngine.hasLightWork() +- || !this.pendingUnloads.isEmpty() +- || ca.spottedleaf.moonrise.common.PlatformHooks.get().hasAnyChunkHolders(this.level) // Paper - moonrise +- || !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) { -- for (LongIterator longiterator = this.toDrop.iterator(); longiterator.hasNext(); longiterator.remove()) { -- long i = longiterator.nextLong(); -- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.get(i); -- -- if (playerchunk != null) { -- this.updatingChunkMap.remove(i); -- this.pendingUnloads.put(i, playerchunk); + private void processUnloads(BooleanSupplier hasMoreTime) { +- for (LongIterator longIterator = this.toDrop.iterator(); longIterator.hasNext(); longIterator.remove()) { +- long l = longIterator.nextLong(); +- ChunkHolder chunkHolder = this.updatingChunkMap.get(l); +- if (chunkHolder != null) { +- this.updatingChunkMap.remove(l); +- this.pendingUnloads.put(l, chunkHolder); - this.modified = true; -- this.scheduleUnload(i, playerchunk); +- this.scheduleUnload(l, chunkHolder); - } - } - -- int j = Math.max(0, this.unloadQueue.size() - 2000); +- int max = Math.max(0, this.unloadQueue.size() - 2000); - - Runnable runnable; -- -- while ((j > 0 || shouldKeepTicking.getAsBoolean()) && (runnable = (Runnable) this.unloadQueue.poll()) != null) { -- --j; +- while ((max > 0 || hasMoreTime.getAsBoolean()) && (runnable = this.unloadQueue.poll()) != null) { +- max--; - runnable.run(); - } - -- this.saveChunksEagerly(shouldKeepTicking); +- this.saveChunksEagerly(hasMoreTime); + ((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(); + private void saveChunksEagerly(BooleanSupplier hasMoreTime) { +- long millis = Util.getMillis(); +- int i = 0; +- LongIterator longIterator = this.chunksToEagerlySave.iterator(); +- +- while (i < 20 && this.activeChunkWrites.get() < 128 && hasMoreTime.getAsBoolean() && longIterator.hasNext()) { +- long l = longIterator.nextLong(); +- ChunkHolder chunkHolder = this.visibleChunkMap.get(l); +- ChunkAccess chunkAccess = chunkHolder != null ? chunkHolder.getLatestChunk() : null; +- if (chunkAccess == null || !chunkAccess.isUnsaved()) { +- longIterator.remove(); +- } else if (this.saveChunkIfNeeded(chunkHolder, millis)) { +- i++; +- longIterator.remove(); - } - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system - } - private void scheduleUnload(long pos, ChunkHolder chunk) { -- CompletableFuture<?> completablefuture = chunk.getSaveSyncFuture(); -- Runnable runnable = () -> { -- CompletableFuture<?> completablefuture1 = chunk.getSaveSyncFuture(); -- -- if (completablefuture1 != completablefuture) { -- this.scheduleUnload(pos, chunk); + private void scheduleUnload(long chunkPos, ChunkHolder chunkHolder) { +- CompletableFuture<?> saveSyncFuture = chunkHolder.getSaveSyncFuture(); +- saveSyncFuture.thenRunAsync(() -> { +- CompletableFuture<?> saveSyncFuture1 = chunkHolder.getSaveSyncFuture(); +- if (saveSyncFuture1 != saveSyncFuture) { +- this.scheduleUnload(chunkPos, chunkHolder); - } else { -- ChunkAccess ichunkaccess = chunk.getLatestChunk(); +- ChunkAccess latestChunk = chunkHolder.getLatestChunk(); - // Paper start - boolean removed; -- if ((removed = this.pendingUnloads.remove(pos, chunk)) && ichunkaccess != null) { -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderDelete(this.level, chunk); +- if ((removed = this.pendingUnloads.remove(chunkPos, chunkHolder)) && latestChunk != null) { +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderDelete(this.level, chunkHolder); - // Paper end -- LevelChunk chunk1; -- -- if (ichunkaccess instanceof LevelChunk) { -- chunk1 = (LevelChunk) ichunkaccess; -- chunk1.setLoaded(false); +- if (latestChunk instanceof LevelChunk levelChunk) { +- levelChunk.setLoaded(false); - } - -- this.save(ichunkaccess); -- if (ichunkaccess instanceof LevelChunk) { -- chunk1 = (LevelChunk) ichunkaccess; -- this.level.unload(chunk1); +- this.save(latestChunk); +- if (latestChunk instanceof LevelChunk levelChunk) { +- this.level.unload(levelChunk); - } - -- this.lightEngine.updateChunkStatus(ichunkaccess.getPos()); +- this.lightEngine.updateChunkStatus(latestChunk.getPos()); - this.lightEngine.tryScheduleUpdate(); -- this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null); -- this.nextChunkSaveTime.remove(ichunkaccess.getPos().toLong()); +- this.progressListener.onStatusChange(latestChunk.getPos(), null); +- this.nextChunkSaveTime.remove(latestChunk.getPos().toLong()); - } else if (removed) { // Paper start -- ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderDelete(this.level, chunk); +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderDelete(this.level, chunkHolder); - } // Paper end -- - } -- }; -- Queue queue = this.unloadQueue; -- -- Objects.requireNonNull(this.unloadQueue); -- completablefuture.thenRunAsync(runnable, queue::add).whenComplete((ovoid, throwable) -> { -- if (throwable != null) { -- ChunkMap.LOGGER.error("Failed to save chunk {}", chunk.getPos(), throwable); +- }, this.unloadQueue::add).whenComplete((_void, error) -> { +- if (error != null) { +- LOGGER.error("Failed to save chunk {}", chunkHolder.getPos(), error); - } -- - }); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -24831,120 +24503,99 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private CompletableFuture<ChunkAccess> scheduleChunkLoad(ChunkPos pos) { -- CompletableFuture<Optional<SerializableChunkData>> completablefuture = this.readChunk(pos).thenApplyAsync((optional) -> { -- return optional.map((nbttagcompound) -> { -- SerializableChunkData serializablechunkdata = SerializableChunkData.parse(this.level, this.level.registryAccess(), nbttagcompound); + private CompletableFuture<ChunkAccess> scheduleChunkLoad(ChunkPos chunkPos) { +- CompletableFuture<Optional<SerializableChunkData>> completableFuture = this.readChunk(chunkPos).thenApplyAsync(optional -> optional.map(tag -> { +- SerializableChunkData serializableChunkData = SerializableChunkData.parse(this.level, this.level.registryAccess(), tag); +- if (serializableChunkData == null) { +- LOGGER.error("Chunk file at {} is missing level data, skipping", chunkPos); +- } - -- if (serializablechunkdata == null) { -- ChunkMap.LOGGER.error("Chunk file at {} is missing level data, skipping", pos); +- return serializableChunkData; +- }), Util.backgroundExecutor().forName("parseChunk")); +- CompletableFuture<?> completableFuture1 = this.poiManager.prefetch(chunkPos); +- return completableFuture.<Object, Optional<SerializableChunkData>>thenCombine( +- (CompletionStage<? extends Object>)completableFuture1, (optional, object) -> optional +- ) +- .thenApplyAsync(optional -> { +- Profiler.get().incrementCounter("chunkLoad"); +- if (optional.isPresent()) { +- ChunkAccess chunkAccess = optional.get().read(this.level, this.poiManager, this.storageInfo(), chunkPos); +- this.markPosition(chunkPos, chunkAccess.getPersistedStatus().getChunkType()); +- return chunkAccess; +- } else { +- return this.createEmptyChunk(chunkPos); - } -- -- return serializablechunkdata; -- }); -- }, Util.backgroundExecutor().forName("parseChunk")); -- CompletableFuture<?> completablefuture1 = this.poiManager.prefetch(pos); -- -- return completablefuture.thenCombine(completablefuture1, (optional, object) -> { -- return optional; -- }).thenApplyAsync((optional) -> { -- Profiler.get().incrementCounter("chunkLoad"); -- if (optional.isPresent()) { -- ProtoChunk protochunk = ((SerializableChunkData) optional.get()).read(this.level, this.poiManager, this.storageInfo(), pos); -- -- this.markPosition(pos, protochunk.getPersistedStatus().getChunkType()); -- return protochunk; -- } else { -- return this.createEmptyChunk(pos); -- } -- }, this.mainThreadExecutor).exceptionallyAsync((throwable) -> { -- return this.handleChunkLoadFailure(throwable, pos); -- }, this.mainThreadExecutor); +- }, this.mainThreadExecutor) +- .exceptionallyAsync(throwable -> this.handleChunkLoadFailure(throwable, chunkPos), this.mainThreadExecutor); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private ChunkAccess handleChunkLoadFailure(Throwable throwable, ChunkPos chunkPos) { -@@ -716,139 +462,43 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private ChunkAccess handleChunkLoadFailure(Throwable exception, ChunkPos chunkPos) { +@@ -666,108 +446,43 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Override - public GenerationChunkHolder acquireGeneration(long pos) { -- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.get(pos); -- -- playerchunk.increaseGenerationRefCount(); -- return playerchunk; + public GenerationChunkHolder acquireGeneration(long chunkPos) { +- ChunkHolder chunkHolder = this.updatingChunkMap.get(chunkPos); +- chunkHolder.increaseGenerationRefCount(); +- return chunkHolder; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @Override - public void releaseGeneration(GenerationChunkHolder chunkHolder) { -- chunkHolder.decreaseGenerationRefCount(); + public void releaseGeneration(GenerationChunkHolder chunk) { +- chunk.decreaseGenerationRefCount(); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @Override - public CompletableFuture<ChunkAccess> applyStep(GenerationChunkHolder chunkHolder, ChunkStep step, StaticCache2D<GenerationChunkHolder> chunks) { -- ChunkPos chunkcoordintpair = chunkHolder.getPos(); -- + public CompletableFuture<ChunkAccess> applyStep(GenerationChunkHolder chunk, ChunkStep step, StaticCache2D<GenerationChunkHolder> cache) { +- ChunkPos pos = chunk.getPos(); - if (step.targetStatus() == ChunkStatus.EMPTY) { -- return this.scheduleChunkLoad(chunkcoordintpair); +- return this.scheduleChunkLoad(pos); - } else { - try { -- GenerationChunkHolder generationchunkholder1 = (GenerationChunkHolder) chunks.get(chunkcoordintpair.x, chunkcoordintpair.z); -- ChunkAccess ichunkaccess = generationchunkholder1.getChunkIfPresentUnchecked(step.targetStatus().getParent()); -- -- if (ichunkaccess == null) { +- GenerationChunkHolder generationChunkHolder = cache.get(pos.x, pos.z); +- ChunkAccess chunkIfPresentUnchecked = generationChunkHolder.getChunkIfPresentUnchecked(step.targetStatus().getParent()); +- if (chunkIfPresentUnchecked == null) { - throw new IllegalStateException("Parent chunk missing"); - } else { -- CompletableFuture<ChunkAccess> completablefuture = step.apply(this.worldGenContext, chunks, ichunkaccess); -- -- this.progressListener.onStatusChange(chunkcoordintpair, step.targetStatus()); -- return completablefuture; +- CompletableFuture<ChunkAccess> completableFuture = step.apply(this.worldGenContext, cache, chunkIfPresentUnchecked); +- this.progressListener.onStatusChange(pos, step.targetStatus()); +- return completableFuture; - } -- } catch (Exception exception) { -- exception.getStackTrace(); -- CrashReport crashreport = CrashReport.forThrowable(exception, "Exception generating new chunk"); -- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk to be generated"); -- -- crashreportsystemdetails.setDetail("Status being generated", () -> { -- return step.targetStatus().getName(); -- }); -- crashreportsystemdetails.setDetail("Location", (Object) String.format(Locale.ROOT, "%d,%d", chunkcoordintpair.x, chunkcoordintpair.z)); -- crashreportsystemdetails.setDetail("Position hash", (Object) ChunkPos.asLong(chunkcoordintpair.x, chunkcoordintpair.z)); -- crashreportsystemdetails.setDetail("Generator", (Object) this.generator()); +- } catch (Exception var8) { +- var8.getStackTrace(); +- CrashReport crashReport = CrashReport.forThrowable(var8, "Exception generating new chunk"); +- CrashReportCategory crashReportCategory = crashReport.addCategory("Chunk to be generated"); +- crashReportCategory.setDetail("Status being generated", () -> step.targetStatus().getName()); +- crashReportCategory.setDetail("Location", String.format(Locale.ROOT, "%d,%d", pos.x, pos.z)); +- crashReportCategory.setDetail("Position hash", ChunkPos.asLong(pos.x, pos.z)); +- crashReportCategory.setDetail("Generator", this.generator()); - this.mainThreadExecutor.execute(() -> { -- throw new ReportedException(crashreport); +- throw new ReportedException(crashReport); - }); -- throw new ReportedException(crashreport); +- throw new ReportedException(crashReport); - } - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @Override - public ChunkGenerationTask scheduleGenerationTask(ChunkStatus requestedStatus, ChunkPos pos) { -- ChunkGenerationTask chunkgenerationtask = ChunkGenerationTask.create(this, requestedStatus, pos); -- -- this.pendingGenerationTasks.add(chunkgenerationtask); -- return chunkgenerationtask; + public ChunkGenerationTask scheduleGenerationTask(ChunkStatus targetStatus, ChunkPos pos) { +- ChunkGenerationTask chunkGenerationTask = ChunkGenerationTask.create(this, targetStatus, pos); +- this.pendingGenerationTasks.add(chunkGenerationTask); +- return chunkGenerationTask; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - 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(loader); -- }); + private void runGenerationTask(ChunkGenerationTask task) { +- GenerationChunkHolder center = task.getCenter(); +- this.worldgenTaskDispatcher.submit(() -> { +- CompletableFuture<?> completableFuture = task.runUntilWait(); +- if (completableFuture != null) { +- completableFuture.thenRun(() -> this.runGenerationTask(task)); - } -- }; -- long i = generationchunkholder.getPos().toLong(); -- -- Objects.requireNonNull(generationchunkholder); -- chunktaskdispatcher.submit(runnable, i, generationchunkholder::getQueueLevel); +- }, center.getPos().toLong(), center::getQueueLevel); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -24956,46 +24607,34 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 } public CompletableFuture<ChunkResult<LevelChunk>> prepareTickingChunk(ChunkHolder holder) { -- CompletableFuture<ChunkResult<List<ChunkAccess>>> completablefuture = this.getChunkRangeFuture(holder, 1, (i) -> { -- return ChunkStatus.FULL; -- }); -- CompletableFuture<ChunkResult<LevelChunk>> completablefuture1 = completablefuture.thenApplyAsync((chunkresult) -> { -- return chunkresult.map((list) -> { -- 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(holder, chunk); -- } else { -- completablefuture2.thenAcceptAsync((object) -> { -- this.onChunkReadyToSend(holder, chunk); -- }, this.mainThreadExecutor); -- } -- -- return chunk; -- }); -- }, this.mainThreadExecutor); +- CompletableFuture<ChunkResult<List<ChunkAccess>>> chunkRangeFuture = this.getChunkRangeFuture(holder, 1, i -> ChunkStatus.FULL); +- CompletableFuture<ChunkResult<LevelChunk>> completableFuture = chunkRangeFuture.thenApplyAsync(chunk -> chunk.map(list -> { +- LevelChunk levelChunk = (LevelChunk)list.get(list.size() / 2); +- levelChunk.postProcessGeneration(this.level); +- this.level.startTickingChunk(levelChunk); +- CompletableFuture<?> sendSyncFuture = holder.getSendSyncFuture(); +- if (sendSyncFuture.isDone()) { +- this.onChunkReadyToSend(holder, levelChunk); +- } else { +- sendSyncFuture.thenAcceptAsync(object -> this.onChunkReadyToSend(holder, levelChunk), this.mainThreadExecutor); +- } - -- completablefuture1.handle((chunkresult, throwable) -> { +- return levelChunk; +- }), this.mainThreadExecutor); +- completableFuture.handle((chunk, exception) -> { - this.tickingGenerated.getAndIncrement(); - return null; - }); -- return completablefuture1; +- return completableFuture; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } private void onChunkReadyToSend(ChunkHolder chunkHolder, LevelChunk chunk) { -- ChunkPos chunkcoordintpair = chunk.getPos(); -- Iterator iterator = this.playerMap.getAllPlayers().iterator(); -- -- while (iterator.hasNext()) { -- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); +- ChunkPos pos = chunk.getPos(); - -- if (entityplayer.getChunkTrackingView().contains(chunkcoordintpair)) { -- ChunkMap.markChunkPendingToSend(entityplayer, chunk); +- for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) { +- if (serverPlayer.getChunkTrackingView().contains(pos)) { +- markChunkPendingToSend(serverPlayer, chunk); - } - } - @@ -25003,39 +24642,33 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public CompletableFuture<ChunkResult<LevelChunk>> prepareAccessibleChunk(ChunkHolder holder) { -- return this.getChunkRangeFuture(holder, 1, ChunkLevel::getStatusAroundFullChunk).thenApply((chunkresult) -> { -- return chunkresult.map((list) -> { -- return (LevelChunk) list.get(list.size() / 2); -- }); -- }); + public CompletableFuture<ChunkResult<LevelChunk>> prepareAccessibleChunk(ChunkHolder chunk) { +- return this.getChunkRangeFuture(chunk, 1, ChunkLevel::getStatusAroundFullChunk) +- .thenApply(chunkResult -> chunkResult.map(list -> (LevelChunk)list.get(list.size() / 2))); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } public int getTickingGenerated() { -@@ -856,144 +506,80 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -775,125 +490,78 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - private boolean saveChunkIfNeeded(ChunkHolder chunkHolder, long currentTime) { -- if (chunkHolder.wasAccessibleSinceLastSave() && chunkHolder.isReadyForSaving()) { -- ChunkAccess ichunkaccess = chunkHolder.getLatestChunk(); -- -- if (!(ichunkaccess instanceof ImposterProtoChunk) && !(ichunkaccess instanceof LevelChunk)) { + private boolean saveChunkIfNeeded(ChunkHolder chunk, long gametime) { +- if (chunk.wasAccessibleSinceLastSave() && chunk.isReadyForSaving()) { +- ChunkAccess latestChunk = chunk.getLatestChunk(); +- if (!(latestChunk instanceof ImposterProtoChunk) && !(latestChunk instanceof LevelChunk)) { - return false; -- } else if (!ichunkaccess.isUnsaved()) { +- } else if (!latestChunk.isUnsaved()) { - return false; - } else { -- long j = ichunkaccess.getPos().toLong(); -- long k = this.nextChunkSaveTime.getOrDefault(j, -1L); -- -- if (currentTime < k) { +- long packedChunkPos = latestChunk.getPos().toLong(); +- long orDefault = this.nextChunkSaveTime.getOrDefault(packedChunkPos, -1L); +- if (gametime < orDefault) { - return false; - } else { -- boolean flag = this.save(ichunkaccess); -- -- chunkHolder.refreshAccessibility(); +- boolean flag = this.save(latestChunk); +- chunk.refreshAccessibility(); - if (flag) { -- this.nextChunkSaveTime.put(j, currentTime + 10000L); +- this.nextChunkSaveTime.put(packedChunkPos, gametime + 10000L); - } - - return flag; @@ -25052,111 +24685,97 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 - if (!chunk.tryMarkSaved()) { - return false; - } else { -- ChunkPos chunkcoordintpair = chunk.getPos(); +- ChunkPos pos = chunk.getPos(); - - try { -- ChunkStatus chunkstatus = chunk.getPersistedStatus(); -- -- if (chunkstatus.getChunkType() != ChunkType.LEVELCHUNK) { -- if (this.isExistingChunkFull(chunkcoordintpair)) { +- ChunkStatus persistedStatus = chunk.getPersistedStatus(); +- if (persistedStatus.getChunkType() != ChunkType.LEVELCHUNK) { +- if (this.isExistingChunkFull(pos)) { - return false; - } - -- if (chunkstatus == ChunkStatus.EMPTY && chunk.getAllStarts().values().stream().noneMatch(StructureStart::isValid)) { +- if (persistedStatus == ChunkStatus.EMPTY && chunk.getAllStarts().values().stream().noneMatch(StructureStart::isValid)) { - return false; - } - } - - Profiler.get().incrementCounter("chunkSave"); - this.activeChunkWrites.incrementAndGet(); -- SerializableChunkData serializablechunkdata = SerializableChunkData.copyOf(this.level, chunk); -- -- Objects.requireNonNull(serializablechunkdata); -- CompletableFuture<CompoundTag> 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); +- SerializableChunkData serializableChunkData = SerializableChunkData.copyOf(this.level, chunk); +- CompletableFuture<CompoundTag> completableFuture = CompletableFuture.supplyAsync(serializableChunkData::write, Util.backgroundExecutor()); +- this.write(pos, completableFuture::join).handle((_void, exception1) -> { +- if (exception1 != null) { +- this.level.getServer().reportChunkSaveFailure(exception1, this.storageInfo(), pos); - } - - this.activeChunkWrites.decrementAndGet(); - return null; - }); -- this.markPosition(chunkcoordintpair, chunkstatus.getChunkType()); +- this.markPosition(pos, persistedStatus.getChunkType()); - return true; -- } catch (Exception exception) { -- this.level.getServer().reportChunkSaveFailure(exception, this.storageInfo(), chunkcoordintpair); +- } catch (Exception var6) { +- this.level.getServer().reportChunkSaveFailure(var6, this.storageInfo(), pos); - return false; - } - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private boolean isExistingChunkFull(ChunkPos pos) { -- byte b0 = this.chunkTypeCache.get(pos.toLong()); -- -- if (b0 != 0) { -- return b0 == 1; + private boolean isExistingChunkFull(ChunkPos chunkPos) { +- byte b = this.chunkTypeCache.get(chunkPos.toLong()); +- if (b != 0) { +- return b == 1; - } else { -- CompoundTag nbttagcompound; -- +- CompoundTag compoundTag; - try { -- nbttagcompound = (CompoundTag) ((Optional) this.readChunk(pos).join()).orElse((Object) null); -- if (nbttagcompound == null) { -- this.markPositionReplaceable(pos); +- compoundTag = this.readChunk(chunkPos).join().orElse(null); +- if (compoundTag == null) { +- this.markPositionReplaceable(chunkPos); - return false; - } -- } catch (Exception exception) { -- ChunkMap.LOGGER.error("Failed to read chunk {}", pos, exception); -- this.markPositionReplaceable(pos); +- } catch (Exception var5) { +- LOGGER.error("Failed to read chunk {}", chunkPos, var5); +- this.markPositionReplaceable(chunkPos); - return false; - } - -- ChunkType chunktype = SerializableChunkData.getChunkTypeFromTag(nbttagcompound); -- -- return this.markPosition(pos, chunktype) == 1; +- ChunkType chunkTypeFromTag = SerializableChunkData.getChunkTypeFromTag(compoundTag); +- return this.markPosition(chunkPos, chunkTypeFromTag) == 1; - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public void setServerViewDistance(int watchDistance) { // Paper - public -- int j = Mth.clamp(watchDistance, 2, 32); -- -- if (j != this.serverViewDistance) { -- this.serverViewDistance = j; + public void setServerViewDistance(int viewDistance) { // Paper - publi +- int i = Mth.clamp(viewDistance, 2, 32); +- if (i != this.serverViewDistance) { +- this.serverViewDistance = i; - this.distanceManager.updatePlayerTickets(this.serverViewDistance); -- Iterator iterator = this.playerMap.getAllPlayers().iterator(); -- -- while (iterator.hasNext()) { -- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); - -- this.updateChunkTracking(entityplayer); +- for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) { +- this.updateChunkTracking(serverPlayer); - } + // Paper start - rewrite chunk system -+ final int clamped = Mth.clamp(watchDistance, 2, ca.spottedleaf.moonrise.common.util.MoonriseConstants.MAX_VIEW_DISTANCE); ++ final int clamped = Mth.clamp(viewDistance, 2, ca.spottedleaf.moonrise.common.util.MoonriseConstants.MAX_VIEW_DISTANCE); + if (clamped == this.serverViewDistance) { + return; } - ++ + this.serverViewDistance = clamped; + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().setLoadDistance(this.serverViewDistance + 1); + // Paper end - rewrite chunk system } - public int getPlayerViewDistance(ServerPlayer player) { // Paper - public + int getPlayerViewDistance(ServerPlayer player) { - return Mth.clamp(player.requestedViewDistance(), 2, this.serverViewDistance); + return ca.spottedleaf.moonrise.common.PlatformHooks.get().getSendViewDistance(player); // Paper - rewrite chunk system } - private void markChunkPendingToSend(ServerPlayer player, ChunkPos pos) { -- LevelChunk chunk = this.getChunkToSend(pos.toLong()); -- -- if (chunk != null) { -- ChunkMap.markChunkPendingToSend(player, chunk); + private void markChunkPendingToSend(ServerPlayer player, ChunkPos chunkPos) { +- LevelChunk chunkToSend = this.getChunkToSend(chunkPos.toLong()); +- if (chunkToSend != null) { +- markChunkPendingToSend(player, chunkToSend); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system - } private static void markChunkPendingToSend(ServerPlayer player, LevelChunk chunk) { @@ -25164,8 +24783,8 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private static void dropChunk(ServerPlayer player, ChunkPos pos) { -- player.connection.chunkSender.dropChunk(player, pos); + private static void dropChunk(ServerPlayer player, ChunkPos chunkPos) { +- player.connection.chunkSender.dropChunk(player, chunkPos); + // Paper - rewrite chunk system + } + @@ -25195,116 +24814,98 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionFileType.CHUNK_DATA + ); + return null; - } - ++ } ++ + @Override + public void flushWorker() { + ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.flush(this.level); -+ } + } + // Paper end - rewrite chunk system -+ + @Nullable - public LevelChunk getChunkToSend(long pos) { - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); -@@ -1059,7 +645,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + public LevelChunk getChunkToSend(long chunkPos) { +@@ -981,7 +649,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } // CraftBukkit start -- private CompoundTag upgradeChunkTag(CompoundTag nbttagcompound, ChunkPos chunkcoordintpair) { -+ public CompoundTag upgradeChunkTag(CompoundTag nbttagcompound, ChunkPos chunkcoordintpair) { // Paper - public - return this.upgradeChunkTag(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, this.generator().getTypeNameForDataFixer(), chunkcoordintpair, this.level); - // CraftBukkit end +- private CompoundTag upgradeChunkTag(CompoundTag tag, ChunkPos pos) { ++ public CompoundTag upgradeChunkTag(CompoundTag tag, ChunkPos pos) { // Paper - public + return this.upgradeChunkTag(this.level.getTypeKey(), this.overworldDataStorage, tag, this.generator().getTypeNameForDataFixer(), pos, this.level); + // CraftBukkit end } -@@ -1069,7 +655,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - while (longiterator.hasNext()) { - long i = longiterator.nextLong(); -- ChunkHolder playerchunk = (ChunkHolder) this.visibleChunkMap.get(i); -+ ChunkHolder playerchunk = (ChunkHolder) this.getVisibleChunkIfPresent(i); // Paper - rewrite chunk system +@@ -991,7 +659,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - if (playerchunk != null && this.anyPlayerCloseEnoughForSpawningInternal(playerchunk.getPos())) { - callback.accept(playerchunk); -@@ -1084,7 +670,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + while (spawnCandidateChunks.hasNext()) { + long l = spawnCandidateChunks.nextLong(); +- ChunkHolder chunkHolder = this.visibleChunkMap.get(l); ++ ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(l); // Paper - rewrite chunk system + if (chunkHolder != null && this.anyPlayerCloseEnoughForSpawningInternal(chunkHolder.getPos())) { + action.accept(chunkHolder); + } +@@ -1004,7 +672,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) { -- return !this.distanceManager.hasPlayersNearby(chunkcoordintpair.toLong()) ? false : this.anyPlayerCloseEnoughForSpawningInternal(chunkcoordintpair, reducedRange); -+ return this.anyPlayerCloseEnoughForSpawningInternal(chunkcoordintpair, reducedRange); // Paper - chunk tick iteration optimisation + boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkPos, boolean reducedRange) { +- return this.distanceManager.hasPlayersNearby(chunkPos.toLong()) && this.anyPlayerCloseEnoughForSpawningInternal(chunkPos, reducedRange); ++ return this.anyPlayerCloseEnoughForSpawningInternal(chunkPos, reducedRange); // Paper - chunk tick iteration optimisation // Spigot end } -@@ -1096,16 +682,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - private boolean anyPlayerCloseEnoughForSpawningInternal(ChunkPos chunkcoordintpair, boolean reducedRange) { +@@ -1016,7 +684,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private boolean anyPlayerCloseEnoughForSpawningInternal(ChunkPos chunkPos, boolean reducedRange) { double blockRange; // Paper - use from event // Spigot end -- Iterator iterator = this.playerMap.getAllPlayers().iterator(); -- -- ServerPlayer entityplayer; +- for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) { + // Paper start - chunk tick iteration optimisation + final ca.spottedleaf.moonrise.common.list.ReferenceList<ServerPlayer> players = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getNearbyPlayers().getPlayers( -+ chunkcoordintpair, ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.SPAWN_RANGE ++ chunkPos, ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.SPAWN_RANGE + ); + if (players == null) { + return false; + } - -- do { -- if (!iterator.hasNext()) { -- return false; -- } ++ + final ServerPlayer[] raw = players.getRawDataUnchecked(); + final int len = players.size(); - -- entityplayer = (ServerPlayer) iterator.next(); ++ + Objects.checkFromIndexSize(0, len, raw.length); + for (int i = 0; i < len; ++i) { -+ final ServerPlayer entityplayer = raw[i]; ++ final ServerPlayer serverPlayer = raw[i]; // Paper start - PlayerNaturallySpawnCreaturesEvent com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event; blockRange = 16384.0D; -@@ -1115,33 +705,47 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4)); - } - // Paper end - PlayerNaturallySpawnCreaturesEvent -- } while (!this.playerIsCloseEnoughForSpawning(entityplayer, chunkcoordintpair, blockRange)); // Spigot -+ if (this.playerIsCloseEnoughForSpawning(entityplayer, chunkcoordintpair, blockRange)) { -+ return true; -+ } -+ } +@@ -1032,26 +713,41 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } -- return true; -+ return false; + return false; + // Paper end - chunk tick iteration optimisation } - public List<ServerPlayer> getPlayersCloseForSpawning(ChunkPos pos) { -- long i = pos.toLong(); + public List<ServerPlayer> getPlayersCloseForSpawning(ChunkPos chunkPos) { +- long packedChunkPos = chunkPos.toLong(); +- if (!this.distanceManager.hasPlayersNearby(packedChunkPos)) { +- return List.of(); +- } else { +- Builder<ServerPlayer> builder = ImmutableList.builder(); + // Paper start - chunk tick iteration optimisation + final ca.spottedleaf.moonrise.common.list.ReferenceList<ServerPlayer> players = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getNearbyPlayers().getPlayers( -+ pos, ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.SPAWN_RANGE ++ chunkPos, ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.SPAWN_RANGE + ); + if (players == null) { + return new ArrayList<>(); + } - -- if (!this.distanceManager.hasPlayersNearby(i)) { -- return List.of(); -- } else { -- Builder<ServerPlayer> builder = ImmutableList.builder(); -- Iterator iterator = this.playerMap.getAllPlayers().iterator(); ++ + List<ServerPlayer> ret = null; - -- while (iterator.hasNext()) { -- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); ++ + final ServerPlayer[] raw = players.getRawDataUnchecked(); + final int len = players.size(); -- if (this.playerIsCloseEnoughForSpawning(entityplayer, pos, 16384.0D)) { // Spigot -- builder.add(entityplayer); +- for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) { +- if (this.playerIsCloseEnoughForSpawning(serverPlayer, chunkPos, 16384.0D)) { // Spigot +- builder.add(serverPlayer); + Objects.checkFromIndexSize(0, len, raw.length); + for (int i = 0; i < len; ++i) { + final ServerPlayer player = raw[i]; -+ if (this.playerIsCloseEnoughForSpawning(player, pos, 16384.0D)) { // Spigot ++ if (this.playerIsCloseEnoughForSpawning(player, chunkPos, 16384.0D)) { // Spigot + if (ret == null) { + ret = new ArrayList<>(len - i); + ret.add(player); @@ -25320,15 +24921,15 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + // Paper end - chunk tick iteration optimisation } -- private boolean playerIsCloseEnoughForSpawning(ServerPlayer entityplayer, ChunkPos chunkcoordintpair, double range) { // Spigot -+ public boolean playerIsCloseEnoughForSpawning(ServerPlayer entityplayer, ChunkPos chunkcoordintpair, double range) { // Spigot // Paper - chunk tick iteration optimisation - public - if (entityplayer.isSpectator()) { +- private boolean playerIsCloseEnoughForSpawning(ServerPlayer player, ChunkPos chunkPos, double range) { // Spigot ++ public boolean playerIsCloseEnoughForSpawning(ServerPlayer player, ChunkPos chunkPos, double range) { // Spigot // Paper - chunk tick iteration optimisation - public + if (player.isSpectator()) { return false; } else { -@@ -1164,19 +768,21 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1072,18 +768,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.updatePlayerPos(player); - if (!flag1) { - this.distanceManager.addPlayer(SectionPos.of((EntityAccess) player), player); + if (!flag) { + this.distanceManager.addPlayer(SectionPos.of(player), player); + ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager)this.distanceManager).moonrise$addPlayer(player, SectionPos.of(player)); // Paper - chunk tick iteration optimisation } @@ -25336,121 +24937,95 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 - this.updateChunkTracking(player); + ca.spottedleaf.moonrise.common.PlatformHooks.get().addPlayerToDistanceMaps(this.level, player); // Paper - rewrite chunk system } else { - SectionPos sectionposition = player.getLastSectionPos(); - + SectionPos lastSectionPos = player.getLastSectionPos(); this.playerMap.removePlayer(player); - if (!flag2) { - this.distanceManager.removePlayer(sectionposition, player); + if (!flag1) { + this.distanceManager.removePlayer(lastSectionPos, player); + ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager)this.distanceManager).moonrise$removePlayer(player, SectionPos.of(player)); // Paper - chunk tick iteration optimisation } - this.applyChunkTrackingView(player, ChunkTrackingView.EMPTY); + ca.spottedleaf.moonrise.common.PlatformHooks.get().removePlayerFromDistanceMaps(this.level, player); // Paper - rewrite chunk system } - } -@@ -1188,17 +794,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + +@@ -1093,13 +791,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public void move(ServerPlayer player) { -- ObjectIterator objectiterator = this.entityMap.values().iterator(); -- -- while (objectiterator.hasNext()) { -- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); -- -- if (playerchunkmap_entitytracker.entity == player) { -- playerchunkmap_entitytracker.updatePlayers(this.level.players()); +- for (ChunkMap.TrackedEntity trackedEntity : this.entityMap.values()) { +- if (trackedEntity.entity == player) { +- trackedEntity.updatePlayers(this.level.players()); - } else { -- playerchunkmap_entitytracker.updatePlayer(player); +- trackedEntity.updatePlayer(player); - } - } + // Paper - optimise entity tracker - SectionPos sectionposition = player.getLastSectionPos(); - SectionPos sectionposition1 = SectionPos.of((EntityAccess) player); -@@ -1208,6 +804,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - + SectionPos lastSectionPos = player.getLastSectionPos(); + SectionPos sectionPos = SectionPos.of(player); +@@ -1108,6 +800,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + boolean flag2 = lastSectionPos.asLong() != sectionPos.asLong(); if (flag2 || flag != flag1) { this.updatePlayerPos(player); + ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager)this.distanceManager).moonrise$updatePlayer(player, sectionposition, sectionposition1, flag, flag1); // Paper - chunk tick iteration optimisation if (!flag) { - this.distanceManager.removePlayer(sectionposition, player); + this.distanceManager.removePlayer(lastSectionPos, player); } -@@ -1224,70 +821,30 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1124,49 +817,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.playerMap.unIgnorePlayer(player); } - this.updateChunkTracking(player); + // Paper - rewrite chunk system } - + ca.spottedleaf.moonrise.common.PlatformHooks.get().updateMaps(this.level, player); // Paper - rewrite chunk system } private void updateChunkTracking(ServerPlayer player) { -- ChunkPos chunkcoordintpair = player.chunkPosition(); -- int i = this.getPlayerViewDistance(player); -- ChunkTrackingView chunktrackingview = player.getChunkTrackingView(); -- -- if (chunktrackingview instanceof ChunkTrackingView.Positioned chunktrackingview_a) { -- if (chunktrackingview_a.center().equals(chunkcoordintpair) && chunktrackingview_a.viewDistance() == i) { -- return; -- } +- ChunkPos chunkPos = player.chunkPosition(); +- int playerViewDistance = this.getPlayerViewDistance(player); +- if (!( +- player.getChunkTrackingView() instanceof ChunkTrackingView.Positioned positioned +- && positioned.center().equals(chunkPos) +- && positioned.viewDistance() == playerViewDistance +- )) { +- this.applyChunkTrackingView(player, ChunkTrackingView.of(chunkPos, playerViewDistance)); - } -- -- this.applyChunkTrackingView(player, ChunkTrackingView.of(chunkcoordintpair, i)); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void applyChunkTrackingView(ServerPlayer player, ChunkTrackingView chunkFilter) { + private void applyChunkTrackingView(ServerPlayer player, ChunkTrackingView chunkTrackingView) { - if (player.level() == this.level) { -- ChunkTrackingView chunktrackingview1 = player.getChunkTrackingView(); -- -- if (chunkFilter instanceof ChunkTrackingView.Positioned) { -- label15: -- { -- ChunkTrackingView.Positioned chunktrackingview_a = (ChunkTrackingView.Positioned) chunkFilter; -- -- if (chunktrackingview1 instanceof ChunkTrackingView.Positioned) { -- ChunkTrackingView.Positioned chunktrackingview_a1 = (ChunkTrackingView.Positioned) chunktrackingview1; -- -- if (chunktrackingview_a1.center().equals(chunktrackingview_a.center())) { -- break label15; -- } -- } -- -- player.connection.send(new ClientboundSetChunkCacheCenterPacket(chunktrackingview_a.center().x, chunktrackingview_a.center().z)); -- } +- ChunkTrackingView chunkTrackingView1 = player.getChunkTrackingView(); +- if (chunkTrackingView instanceof ChunkTrackingView.Positioned positioned +- && !(chunkTrackingView1 instanceof ChunkTrackingView.Positioned positioned1 && positioned1.center().equals(positioned.center()))) { +- player.connection.send(new ClientboundSetChunkCacheCenterPacket(positioned.center().x, positioned.center().z)); - } - -- ChunkTrackingView.difference(chunktrackingview1, chunkFilter, (chunkcoordintpair) -> { -- this.markChunkPendingToSend(player, chunkcoordintpair); -- }, (chunkcoordintpair) -> { -- ChunkMap.dropChunk(player, chunkcoordintpair); -- }); -- player.setChunkTrackingView(chunkFilter); +- ChunkTrackingView.difference( +- chunkTrackingView1, chunkTrackingView, chunkPos -> this.markChunkPendingToSend(player, chunkPos), chunkPos -> dropChunk(player, chunkPos) +- ); +- player.setChunkTrackingView(chunkTrackingView); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @Override - public List<ServerPlayer> getPlayers(ChunkPos chunkPos, boolean onlyOnWatchDistanceEdge) { -- Set<ServerPlayer> set = this.playerMap.getAllPlayers(); + public List<ServerPlayer> getPlayers(ChunkPos pos, boolean boundaryOnly) { +- Set<ServerPlayer> allPlayers = this.playerMap.getAllPlayers(); - Builder<ServerPlayer> builder = ImmutableList.builder(); -- Iterator iterator = set.iterator(); - -- while (iterator.hasNext()) { -- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -- -- if (onlyOnWatchDistanceEdge && this.isChunkOnTrackedBorder(entityplayer, chunkPos.x, chunkPos.z) || !onlyOnWatchDistanceEdge && this.isChunkTracked(entityplayer, chunkPos.x, chunkPos.z)) { -- builder.add(entityplayer); +- for (ServerPlayer serverPlayer : allPlayers) { +- if (boundaryOnly && this.isChunkOnTrackedBorder(serverPlayer, pos.x, pos.z) || !boundaryOnly && this.isChunkTracked(serverPlayer, pos.x, pos.z)) { +- builder.add(serverPlayer); - } + // Paper start - rewrite chunk system -+ final ChunkHolder holder = this.getVisibleChunkIfPresent(chunkPos.toLong()); ++ final ChunkHolder holder = this.getVisibleChunkIfPresent(pos.toLong()); + if (holder == null) { + return new ArrayList<>(); + } else { -+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)holder).moonrise$getPlayers(onlyOnWatchDistanceEdge); ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)holder).moonrise$getPlayers(boundaryOnly); } - - return builder.build(); @@ -25458,34 +25033,30 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 } public void addEntity(Entity entity) { -@@ -1314,6 +871,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - ChunkMap.TrackedEntity playerchunkmap_entitytracker = new ChunkMap.TrackedEntity(entity, i, j, entitytypes.trackDeltas()); - - this.entityMap.put(entity.getId(), playerchunkmap_entitytracker); +@@ -1190,6 +863,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } else { + ChunkMap.TrackedEntity trackedEntity = new ChunkMap.TrackedEntity(entity, i, updateInterval, type.trackDeltas()); + this.entityMap.put(entity.getId(), trackedEntity); + // Paper start - optimise entity tracker + if (((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$getTrackedEntity() != null) { + throw new IllegalStateException("Entity is already tracked"); + } + ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$setTrackedEntity(playerchunkmap_entitytracker); + // Paper end - optimise entity tracker - playerchunkmap_entitytracker.updatePlayers(this.level.players()); - if (entity instanceof ServerPlayer) { - ServerPlayer entityplayer = (ServerPlayer) entity; -@@ -1354,16 +917,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - playerchunkmap_entitytracker1.broadcastRemoved(); + trackedEntity.updatePlayers(this.level.players()); + if (entity instanceof ServerPlayer serverPlayer) { + this.updatePlayerStatus(serverPlayer, true); +@@ -1219,12 +898,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + if (trackedEntity1 != null) { + trackedEntity1.broadcastRemoved(); } - + ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$setTrackedEntity(null); // Paper - optimise entity tracker } -- protected void tick() { -- Iterator iterator = this.playerMap.getAllPlayers().iterator(); + // Paper start - optimise entity tracker + private void newTrackerTick() { + final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup entityLookup = (ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup)((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getEntityLookup();; - -- while (iterator.hasNext()) { -- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); ++ + final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.world.entity.Entity> trackerEntities = entityLookup.trackerEntities; + final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked(); + for (int i = 0, len = trackerEntities.size(); i < len; ++i) { @@ -25502,9 +25073,10 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + } + } + // Paper end - optimise entity tracker - -- this.updateChunkTracking(entityplayer); -+ protected void tick() { ++ + protected void tick() { +- for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) { +- this.updateChunkTracking(serverPlayer); + // Paper start - optimise entity tracker + if (true) { + this.newTrackerTick(); @@ -25515,28 +25087,24 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 List<ServerPlayer> list = Lists.newArrayList(); List<ServerPlayer> list1 = this.level.players(); -@@ -1466,27 +1051,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1302,23 +1007,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - public void waitForLightBeforeSending(ChunkPos centerPos, int radius) { -- int j = radius + 1; -- -- ChunkPos.rangeClosed(centerPos, j).forEach((chunkcoordintpair1) -> { -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(chunkcoordintpair1.toLong()); -- -- if (playerchunk != null) { -- playerchunk.addSendDependency(this.lightEngine.waitForPendingTasks(chunkcoordintpair1.x, chunkcoordintpair1.z)); + public void waitForLightBeforeSending(ChunkPos chunkPos, int range) { +- int i = range + 1; +- ChunkPos.rangeClosed(chunkPos, i).forEach(pos -> { +- ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(pos.toLong()); +- if (visibleChunkIfPresent != null) { +- visibleChunkIfPresent.addSendDependency(this.lightEngine.waitForPendingTasks(pos.x, pos.z)); - } -- - }); + // Paper - rewrite chunk system } -- public class ChunkDistanceManager extends DistanceManager { // Paper - public -+ public class ChunkDistanceManager extends DistanceManager implements ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager { // Paper - public // Paper - rewrite chunk system - - protected ChunkDistanceManager(final Executor workerExecutor, final Executor mainThreadExecutor) { - super(workerExecutor, mainThreadExecutor); +- public class DistanceManager extends net.minecraft.server.level.DistanceManager { // Paper - public ++ public class DistanceManager extends net.minecraft.server.level.DistanceManager implements ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager { // Paper - public // Paper - rewrite chunk system + protected DistanceManager(final Executor dispatcher, final Executor mainThreadExecutor) { + super(dispatcher, mainThreadExecutor); } + // Paper start - rewrite chunk system @@ -25547,22 +25115,21 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + // Paper end - rewrite chunk system + @Override - protected boolean isChunkToRemove(long pos) { -- return ChunkMap.this.toDrop.contains(pos); + protected boolean isChunkToRemove(long chunkPos) { +- return ChunkMap.this.toDrop.contains(chunkPos); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @Nullable -@@ -1502,7 +1085,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1334,13 +1040,96 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } - public class TrackedEntity { + public class TrackedEntity implements ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity { // Paper - optimise entity tracker - public final ServerEntity serverEntity; final Entity entity; -@@ -1510,6 +1093,89 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private final int range; SectionPos lastSectionPos; public final Set<ServerPlayerConnection> seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl @@ -25649,30 +25216,28 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + } + // Paper end - optimise entity tracker + - public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) { - this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit + public TrackedEntity(final Entity entity, final int range, final int updateInterval, final boolean trackDelta) { + this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, updateInterval, trackDelta, this::broadcast, this.seenBy); // CraftBukkit this.entity = entity; -@@ -1612,20 +1278,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1431,17 +1220,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } private int getEffectiveRange() { - int i = this.range; -- Iterator iterator = this.entity.getIndirectPassengers().iterator(); + // Paper start - optimise entity tracker + final Entity entity = this.entity; + int range = this.range; -- while (iterator.hasNext()) { -- Entity entity = (Entity) iterator.next(); -- int j = entity.getType().clientTrackingRange() * 16; -- j = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, j); // Paper +- for (Entity entity : this.entity.getIndirectPassengers()) { +- int i1 = entity.getType().clientTrackingRange() * 16; +- i1 = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, i1); // Paper +- if (i1 > i) { +- i = i1; +- } + if (entity.getPassengers() == ImmutableList.<Entity>of()) { + return this.scaledRange(range); + } - -- if (j > i) { -- i = j; -- } ++ + // note: we change to List + final List<Entity> passengers = (List<Entity>)entity.getIndirectPassengers(); + for (int i = 0, len = passengers.size(); i < len; ++i) { @@ -25686,28 +25251,27 @@ index e9b585387f6cbc454e7b16feb36a256e733c5488..204965b3dfa2ac9f6709e61b847e1152 + // Paper end - optimise entity tracker } - public void updatePlayers(List<ServerPlayer> players) { + public void updatePlayers(List<ServerPlayer> playersList) { diff --git a/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java -index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57fbca45b2 100644 +index e50e96861c0aefdb0a79674b7790798f2571010e..73599e8adbee0957c1318ee6688e49b9873d2411 100644 --- a/net/minecraft/server/level/DistanceManager.java +++ b/net/minecraft/server/level/DistanceManager.java -@@ -34,58 +34,57 @@ import net.minecraft.world.level.ChunkPos; +@@ -34,56 +34,56 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.LevelChunk; import org.slf4j.Logger; -public abstract class DistanceManager { +public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager, ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager { // Paper - rewrite chunk system // Paper - chunk tick iteration optimisation - static final Logger LOGGER = LogUtils.getLogger(); static final int PLAYER_TICKET_LEVEL = ChunkLevel.byStatus(FullChunkStatus.ENTITY_TICKING); private static final int INITIAL_TICKET_LIST_CAPACITY = 4; - final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap(); -- public final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets = new Long2ObjectOpenHashMap(); + final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap<>(); +- public final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets = new Long2ObjectOpenHashMap<>(); - private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker(); - 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<ChunkHolder> chunksToUpdateFutures = new ReferenceOpenHashSet(); +- final Set<ChunkHolder> chunksToUpdateFutures = new ReferenceOpenHashSet<>(); - final ThrottlingChunkTaskDispatcher ticketDispatcher; - final LongSet ticketsToRelease = new LongOpenHashSet(); - final Executor mainThreadExecutor; @@ -25718,25 +25282,30 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 - public int simulationDistance = 10; + // Paper - rewrite chunk system - protected DistanceManager(Executor workerExecutor, Executor mainThreadExecutor) { - TaskScheduler<Runnable> taskscheduler = TaskScheduler.wrapExecutor("player ticket throttler", mainThreadExecutor); - -- this.ticketDispatcher = new ThrottlingChunkTaskDispatcher(taskscheduler, workerExecutor, 4); + protected DistanceManager(Executor dispatcher, Executor mainThreadExecutor) { + TaskScheduler<Runnable> taskScheduler = TaskScheduler.wrapExecutor("player ticket throttler", mainThreadExecutor); +- this.ticketDispatcher = new ThrottlingChunkTaskDispatcher(taskScheduler, dispatcher, 4); - this.mainThreadExecutor = mainThreadExecutor; + // Paper - rewrite chunk system } - protected void purgeStaleTickets() { -- ++this.ticketTickCounter; -- ObjectIterator<Entry<SortedArraySet<Ticket<?>>>> objectiterator = this.tickets.long2ObjectEntrySet().fastIterator(); +- this.ticketTickCounter++; +- ObjectIterator<Entry<SortedArraySet<Ticket<?>>>> objectIterator = this.tickets.long2ObjectEntrySet().fastIterator(); - -- while (objectiterator.hasNext()) { -- Entry<SortedArraySet<Ticket<?>>> entry = (Entry) objectiterator.next(); -- Iterator<Ticket<?>> iterator = ((SortedArraySet) entry.getValue()).iterator(); +- while (objectIterator.hasNext()) { +- Entry<SortedArraySet<Ticket<?>>> entry = objectIterator.next(); +- Iterator<Ticket<?>> iterator = entry.getValue().iterator(); - boolean flag = false; - - while (iterator.hasNext()) { -- Ticket<?> ticket = (Ticket) iterator.next(); +- Ticket<?> ticket = iterator.next(); +- if (ticket.timedOut(this.ticketTickCounter)) { +- iterator.remove(); +- flag = true; +- this.tickingTicketsTracker.removeTicket(entry.getLongKey(), ticket); +- } +- } + // Paper start - rewrite chunk system + @Override + public final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager moonrise$getChunkHolderManager() { @@ -25746,28 +25315,22 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 + // Paper start - chunk tick iteration optimisation + private final ca.spottedleaf.moonrise.common.misc.PositionCountingAreaMap<ServerPlayer> spawnChunkTracker = new ca.spottedleaf.moonrise.common.misc.PositionCountingAreaMap<>(); -- if (ticket.timedOut(this.ticketTickCounter)) { -- iterator.remove(); -- flag = true; -- this.tickingTicketsTracker.removeTicket(entry.getLongKey(), ticket); -- } +- if (flag) { +- this.ticketTracker.update(entry.getLongKey(), getTicketLevelAt(entry.getValue()), false); - } + @Override + public final void moonrise$addPlayer(final ServerPlayer player, final SectionPos pos) { + this.spawnChunkTracker.add(player, pos.x(), pos.z(), ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants.PLAYER_SPAWN_TRACK_RANGE); + } -- if (flag) { -- this.ticketTracker.update(entry.getLongKey(), DistanceManager.getTicketLevelAt((SortedArraySet) entry.getValue()), false); +- if (entry.getValue().isEmpty()) { +- objectIterator.remove(); - } + @Override + public final void moonrise$removePlayer(final ServerPlayer player, final SectionPos pos) { + this.spawnChunkTracker.remove(player); + } - -- if (((SortedArraySet) entry.getValue()).isEmpty()) { -- objectiterator.remove(); -- } ++ + @Override + public final void moonrise$updatePlayer(final ServerPlayer player, + final SectionPos oldPos, final SectionPos newPos, @@ -25777,80 +25340,60 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 + } else { + this.spawnChunkTracker.addOrUpdate(player, newPos.x(), newPos.z(), ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants.PLAYER_SPAWN_TRACK_RANGE); } -+ } + } + // Paper end - chunk tick iteration optimisation + + protected void purgeStaleTickets() { + this.moonrise$getChunkHolderManager().tick(); // Paper - rewrite chunk system ++ } - } - -@@ -102,105 +101,15 @@ public abstract class DistanceManager { - protected abstract ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k); + private static int getTicketLevelAt(SortedArraySet<Ticket<?>> tickets) { + return !tickets.isEmpty() ? tickets.first().getTicketLevel() : ChunkLevel.MAX_LEVEL + 1; +@@ -98,81 +98,15 @@ public abstract class DistanceManager { + protected abstract ChunkHolder updateChunkScheduling(long chunkPos, int i, @Nullable ChunkHolder newLevel, int holder); - public boolean runAllUpdates(ChunkMap chunkLoadingManager) { + public boolean runAllUpdates(ChunkMap chunkMap) { - this.naturalSpawnChunkCounter.runAllUpdates(); - this.tickingTicketsTracker.runAllUpdates(); - this.playerTicketManager.runAllUpdates(); - int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE); - boolean flag = i != 0; -- - if (flag) { -- ; - } - - if (!this.chunksToUpdateFutures.isEmpty()) { -- Iterator iterator = this.chunksToUpdateFutures.iterator(); -- -- ChunkHolder playerchunk; -- - // CraftBukkit start - SPIGOT-7780: Call chunk unload events before updateHighestAllowedStatus -- while (iterator.hasNext()) { -- playerchunk = (ChunkHolder) iterator.next(); -- playerchunk.callEventIfUnloading(chunkLoadingManager); +- for (final ChunkHolder chunkHolder : this.chunksToUpdateFutures) { +- chunkHolder.callEventIfUnloading(chunkMap); - } +- // CraftBukkit end - SPIGOT-7780: Call chunk unload events before updateHighestAllowedStatus - -- iterator = this.chunksToUpdateFutures.iterator(); -- // CraftBukkit end -- -- while (iterator.hasNext()) { -- playerchunk = (ChunkHolder) iterator.next(); -- playerchunk.updateHighestAllowedStatus(chunkLoadingManager); +- for (ChunkHolder chunkHolder : this.chunksToUpdateFutures) { +- chunkHolder.updateHighestAllowedStatus(chunkMap); - } - -- iterator = this.chunksToUpdateFutures.iterator(); -- -- while (iterator.hasNext()) { -- playerchunk = (ChunkHolder) iterator.next(); -- playerchunk.updateFutures(chunkLoadingManager, this.mainThreadExecutor); +- for (ChunkHolder chunkHolder : this.chunksToUpdateFutures) { +- chunkHolder.updateFutures(chunkMap, this.mainThreadExecutor); - } - - this.chunksToUpdateFutures.clear(); - return true; - } else { - if (!this.ticketsToRelease.isEmpty()) { -- LongIterator longiterator = this.ticketsToRelease.iterator(); -- -- while (longiterator.hasNext()) { -- long j = longiterator.nextLong(); +- LongIterator longIterator = this.ticketsToRelease.iterator(); - -- if (this.getTickets(j).stream().anyMatch((ticket) -> { -- return ticket.getType() == TicketType.PLAYER; -- })) { -- ChunkHolder playerchunk1 = chunkLoadingManager.getUpdatingChunkIfPresent(j); -- -- if (playerchunk1 == null) { +- while (longIterator.hasNext()) { +- long l = longIterator.nextLong(); +- if (this.getTickets(l).stream().anyMatch(ticket -> ticket.getType() == TicketType.PLAYER)) { +- ChunkHolder updatingChunkIfPresent = chunkMap.getUpdatingChunkIfPresent(l); +- if (updatingChunkIfPresent == null) { - throw new IllegalStateException(); - } - -- CompletableFuture<ChunkResult<LevelChunk>> completablefuture = playerchunk1.getEntityTickingChunkFuture(); -- -- completablefuture.thenAccept((chunkresult) -> { -- this.mainThreadExecutor.execute(() -> { -- this.ticketDispatcher.release(j, () -> { -- }, false); -- }); -- }); +- CompletableFuture<ChunkResult<LevelChunk>> entityTickingChunkFuture = updatingChunkIfPresent.getEntityTickingChunkFuture(); +- entityTickingChunkFuture.thenAccept( +- chunkResult -> this.mainThreadExecutor.execute(() -> this.ticketDispatcher.release(l, () -> {}, false)) +- ); - } - } - @@ -25862,115 +25405,105 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 + return this.moonrise$getChunkHolderManager().processTicketUpdates(); // Paper - rewrite chunk system } - boolean addTicket(long i, Ticket<?> ticket) { // CraftBukkit - void -> boolean -- SortedArraySet<Ticket<?>> arraysetsorted = this.getTickets(i); -- int j = DistanceManager.getTicketLevelAt(arraysetsorted); -- Ticket<?> ticket1 = (Ticket) arraysetsorted.addOrGet(ticket); -- + boolean addTicket(long chunkPos, Ticket<?> ticket) { // CraftBukkit - void -> boolean +- SortedArraySet<Ticket<?>> tickets = this.getTickets(chunkPos); +- int ticketLevelAt = getTicketLevelAt(tickets); +- Ticket<?> ticket1 = tickets.addOrGet(ticket); - ticket1.setCreatedTick(this.ticketTickCounter); -- if (ticket.getTicketLevel() < j) { -- this.ticketTracker.update(i, ticket.getTicketLevel(), true); +- if (ticket.getTicketLevel() < ticketLevelAt) { +- this.ticketTracker.update(chunkPos, ticket.getTicketLevel(), true); - } -- - return ticket == ticket1; // CraftBukkit -+ return this.moonrise$getChunkHolderManager().addTicketAtLevel((TicketType)ticket.getType(), i, ticket.getTicketLevel(), ticket.key); // Paper - rewrite chunk system ++ return this.moonrise$getChunkHolderManager().addTicketAtLevel((TicketType)ticket.getType(), chunkPos, ticket.getTicketLevel(), ticket.key); // Paper - rewrite chunk system } - boolean removeTicket(long i, Ticket<?> ticket) { // CraftBukkit - void -> boolean -- SortedArraySet<Ticket<?>> arraysetsorted = this.getTickets(i); -- + boolean removeTicket(long chunkPos, Ticket<?> ticket) { // CraftBukkit - void -> boolean +- SortedArraySet<Ticket<?>> tickets = this.getTickets(chunkPos); - boolean removed = false; // CraftBukkit -- if (arraysetsorted.remove(ticket)) { +- if (tickets.remove(ticket)) { - removed = true; // CraftBukkit - } - -- if (arraysetsorted.isEmpty()) { -- this.tickets.remove(i); +- if (tickets.isEmpty()) { +- this.tickets.remove(chunkPos); - } - -- this.ticketTracker.update(i, DistanceManager.getTicketLevelAt(arraysetsorted), false); +- this.ticketTracker.update(chunkPos, getTicketLevelAt(tickets), false); - return removed; // CraftBukkit -+ return this.moonrise$getChunkHolderManager().removeTicketAtLevel((TicketType)ticket.getType(), i, ticket.getTicketLevel(), ticket.key); // Paper - rewrite chunk system ++ return this.moonrise$getChunkHolderManager().removeTicketAtLevel((TicketType)ticket.getType(), chunkPos, ticket.getTicketLevel(), ticket.key); // Paper - rewrite chunk system } - public <T> void addTicket(TicketType<T> type, ChunkPos pos, int level, T argument) { -@@ -219,13 +128,7 @@ public abstract class DistanceManager { + public <T> void addTicket(TicketType<T> type, ChunkPos pos, int level, T value) { +@@ -189,12 +123,7 @@ public abstract class DistanceManager { + this.addRegionTicketAtDistance(type, pos, distance, value); } - - public <T> boolean addRegionTicketAtDistance(TicketType<T> tickettype, ChunkPos chunkcoordintpair, int i, T t0) { + public <T> boolean addRegionTicketAtDistance(TicketType<T> type, ChunkPos pos, int distance, T value) { - // CraftBukkit end -- Ticket<T> ticket = new Ticket<>(tickettype, ChunkLevel.byStatus(FullChunkStatus.FULL) - i, t0); -- long j = chunkcoordintpair.toLong(); -- -- boolean added = this.addTicket(j, ticket); // CraftBukkit -- this.tickingTicketsTracker.addTicket(j, ticket); -- return added; // CraftBukkit -+ return this.moonrise$getChunkHolderManager().addTicketAtLevel(tickettype, chunkcoordintpair, ChunkLevel.byStatus(FullChunkStatus.FULL) - i, t0); // Paper - rewrite chunk system +- Ticket<T> ticket = new Ticket<>(type, ChunkLevel.byStatus(FullChunkStatus.FULL) - distance, value); +- long packedChunkPos = pos.toLong(); +- final boolean addded = this.addTicket(packedChunkPos, ticket); // CraftBukkit +- this.tickingTicketsTracker.addTicket(packedChunkPos, ticket); +- return addded; // CraftBukkit ++ return this.moonrise$getChunkHolderManager().addTicketAtLevel(type, pos, ChunkLevel.byStatus(FullChunkStatus.FULL) - distance, value); // Paper - rewrite chunk system } - public <T> void removeRegionTicket(TicketType<T> type, ChunkPos pos, int radius, T argument) { -@@ -234,32 +137,21 @@ public abstract class DistanceManager { + public <T> void removeRegionTicket(TicketType<T> type, ChunkPos pos, int distance, T value) { +@@ -202,37 +131,29 @@ public abstract class DistanceManager { + removeRegionTicketAtDistance(type, pos, distance, value); } - - public <T> boolean removeRegionTicketAtDistance(TicketType<T> tickettype, ChunkPos chunkcoordintpair, int i, T t0) { + public <T> boolean removeRegionTicketAtDistance(TicketType<T> type, ChunkPos pos, int distance, T value) { - // CraftBukkit end -- Ticket<T> ticket = new Ticket<>(tickettype, ChunkLevel.byStatus(FullChunkStatus.FULL) - i, t0); -- long j = chunkcoordintpair.toLong(); -- -- boolean removed = this.removeTicket(j, ticket); // CraftBukkit -- this.tickingTicketsTracker.removeTicket(j, ticket); +- Ticket<T> ticket = new Ticket<>(type, ChunkLevel.byStatus(FullChunkStatus.FULL) - distance, value); +- long packedChunkPos = pos.toLong(); +- final boolean removed = this.removeTicket(packedChunkPos, ticket); // CraftBukkit +- this.tickingTicketsTracker.removeTicket(packedChunkPos, ticket); - return removed; // CraftBukkit -+ return this.moonrise$getChunkHolderManager().removeTicketAtLevel(tickettype, chunkcoordintpair, ChunkLevel.byStatus(FullChunkStatus.FULL) - i, t0); // Paper - rewrite chunk system ++ return this.moonrise$getChunkHolderManager().removeTicketAtLevel(type, pos, ChunkLevel.byStatus(FullChunkStatus.FULL) - distance, value); // Paper - rewrite chunk system } - private SortedArraySet<Ticket<?>> getTickets(long position) { -- return (SortedArraySet) this.tickets.computeIfAbsent(position, (j) -> { -- return SortedArraySet.create(4); -- }); + private SortedArraySet<Ticket<?>> getTickets(long chunkPos) { +- return this.tickets.computeIfAbsent(chunkPos, l -> SortedArraySet.create(4)); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - protected void updateChunkForced(ChunkPos pos, boolean forced) { + protected void updateChunkForced(ChunkPos pos, boolean add) { - Ticket<ChunkPos> ticket = new Ticket<>(TicketType.FORCED, ChunkMap.FORCED_TICKET_LEVEL, pos); -- long i = pos.toLong(); -- +- long packedChunkPos = pos.toLong(); + // Paper start - rewrite chunk system - if (forced) { -- this.addTicket(i, ticket); -- this.tickingTicketsTracker.addTicket(i, ticket); + if (add) { +- this.addTicket(packedChunkPos, ticket); +- this.tickingTicketsTracker.addTicket(packedChunkPos, ticket); + this.moonrise$getChunkHolderManager().addTicketAtLevel(TicketType.FORCED, pos, ChunkMap.FORCED_TICKET_LEVEL, pos); } else { -- this.removeTicket(i, ticket); -- this.tickingTicketsTracker.removeTicket(i, ticket); +- this.removeTicket(packedChunkPos, ticket); +- this.tickingTicketsTracker.removeTicket(packedChunkPos, ticket); + this.moonrise$getChunkHolderManager().removeTicketAtLevel(TicketType.FORCED, pos, ChunkMap.FORCED_TICKET_LEVEL, pos); } + // Paper end - rewrite chunk system - } -@@ -270,9 +162,8 @@ public abstract class DistanceManager { - ((ObjectSet) this.playersPerChunk.computeIfAbsent(i, (j) -> { - return new ObjectOpenHashSet(); - })).add(player); -- this.naturalSpawnChunkCounter.update(i, 0, true); -- this.playerTicketManager.update(i, 0, true); -- this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); + public void addPlayer(SectionPos sectionPos, ServerPlayer player) { + ChunkPos chunkPos = sectionPos.chunk(); + long packedChunkPos = chunkPos.toLong(); + this.playersPerChunk.computeIfAbsent(packedChunkPos, l -> new ObjectOpenHashSet<>()).add(player); +- this.naturalSpawnChunkCounter.update(packedChunkPos, 0, true); +- this.playerTicketManager.update(packedChunkPos, 0, true); +- this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkPos, this.getPlayerTicketLevel(), chunkPos); + // Paper - chunk tick iteration optimisation + // Paper - rewrite chunk system } - public void removePlayer(SectionPos pos, ServerPlayer player) { -@@ -284,160 +175,93 @@ public abstract class DistanceManager { - if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully - if (objectset == null || objectset.isEmpty()) { // Paper - this.playersPerChunk.remove(i); -- this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); -- this.playerTicketManager.update(i, Integer.MAX_VALUE, false); -- this.tickingTicketsTracker.removeTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); + public void removePlayer(SectionPos sectionPos, ServerPlayer player) { +@@ -246,136 +167,90 @@ public abstract class DistanceManager { + if (set == null || set.isEmpty()) { + // Paper end - some state corruption happens here, don't crash, clean up gracefully + this.playersPerChunk.remove(packedChunkPos); +- this.naturalSpawnChunkCounter.update(packedChunkPos, Integer.MAX_VALUE, false); +- this.playerTicketManager.update(packedChunkPos, Integer.MAX_VALUE, false); +- this.tickingTicketsTracker.removeTicket(TicketType.PLAYER, chunkPos, this.getPlayerTicketLevel(), chunkPos); + // Paper - chunk tick iteration optimisation + // Paper - rewrite chunk system } - } private int getPlayerTicketLevel() { @@ -25994,11 +25527,10 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 + // Paper end - rewrite chunk system } - protected String getTicketDebugString(long pos) { -- SortedArraySet<Ticket<?>> arraysetsorted = (SortedArraySet) this.tickets.get(pos); -- -- return arraysetsorted != null && !arraysetsorted.isEmpty() ? ((Ticket) arraysetsorted.first()).toString() : "no_ticket"; -+ return this.moonrise$getChunkHolderManager().getTicketDebugString(pos); // Paper - rewrite chunk system + protected String getTicketDebugString(long chunkPos) { +- SortedArraySet<Ticket<?>> set = this.tickets.get(chunkPos); +- return set != null && !set.isEmpty() ? set.first().toString() : "no_ticket"; ++ return this.moonrise$getChunkHolderManager().getTicketDebugString(chunkPos); // Paper - rewrite chunk system } protected void updatePlayerTickets(int viewDistance) { @@ -26014,7 +25546,7 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 + // Paper start - rewrite chunk system + // note: vanilla does not clamp to 0, but we do simply because we need a min of 0 + final int clamped = net.minecraft.util.Mth.clamp(simulationDistance, 0, ca.spottedleaf.moonrise.common.util.MoonriseConstants.MAX_VIEW_DISTANCE); - ++ + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getPlayerChunkLoader().setTickDistance(clamped); + // Paper end - rewrite chunk system } @@ -26042,40 +25574,21 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 + return "No DistanceManager stats available"; // Paper - rewrite chunk system } - private void dumpTickets(String path) { -- try { -- FileOutputStream fileoutputstream = new FileOutputStream(new File(path)); -- -- try { -- ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().iterator(); -- -- while (objectiterator.hasNext()) { -- Entry<SortedArraySet<Ticket<?>>> entry = (Entry) objectiterator.next(); -- ChunkPos chunkcoordintpair = new ChunkPos(entry.getLongKey()); -- Iterator iterator = ((SortedArraySet) entry.getValue()).iterator(); -- -- while (iterator.hasNext()) { -- Ticket<?> ticket = (Ticket) iterator.next(); + private void dumpTickets(String filename) { +- try (FileOutputStream fileOutputStream = new FileOutputStream(new File(filename))) { +- for (Entry<SortedArraySet<Ticket<?>>> entry : this.tickets.long2ObjectEntrySet()) { +- ChunkPos chunkPos = new ChunkPos(entry.getLongKey()); - -- fileoutputstream.write((chunkcoordintpair.x + "\t" + chunkcoordintpair.z + "\t" + String.valueOf(ticket.getType()) + "\t" + ticket.getTicketLevel() + "\t\n").getBytes(StandardCharsets.UTF_8)); -- } -- } -- } catch (Throwable throwable) { -- try { -- fileoutputstream.close(); -- } catch (Throwable throwable1) { -- throwable.addSuppressed(throwable1); +- for (Ticket<?> ticket : entry.getValue()) { +- fileOutputStream.write( +- (chunkPos.x + "\t" + chunkPos.z + "\t" + ticket.getType() + "\t" + ticket.getTicketLevel() + "\t\n").getBytes(StandardCharsets.UTF_8) +- ); - } -- -- throw throwable; - } -- -- fileoutputstream.close(); -- } catch (IOException ioexception) { -- DistanceManager.LOGGER.error("Failed to dump tickets to {}", path, ioexception); +- } catch (IOException var10) { +- LOGGER.error("Failed to dump tickets to {}", filename, var10); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system - } @VisibleForTesting @@ -26090,18 +25603,17 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 } public void removeTicketsOnClosing() { -- ImmutableSet<TicketType<?>> immutableset = ImmutableSet.of(TicketType.UNKNOWN, TicketType.POST_TELEPORT, TicketType.FUTURE_AWAIT); // Paper - add additional tickets to preserve -- ObjectIterator<Entry<SortedArraySet<Ticket<?>>>> objectiterator = this.tickets.long2ObjectEntrySet().fastIterator(); +- ImmutableSet<TicketType<?>> set = ImmutableSet.of(TicketType.UNKNOWN, TicketType.POST_TELEPORT, TicketType.FUTURE_AWAIT); // Paper - add additional tickets to preserve +- ObjectIterator<Entry<SortedArraySet<Ticket<?>>>> objectIterator = this.tickets.long2ObjectEntrySet().fastIterator(); - -- while (objectiterator.hasNext()) { -- Entry<SortedArraySet<Ticket<?>>> entry = (Entry) objectiterator.next(); -- Iterator<Ticket<?>> iterator = ((SortedArraySet) entry.getValue()).iterator(); +- while (objectIterator.hasNext()) { +- Entry<SortedArraySet<Ticket<?>>> entry = objectIterator.next(); +- Iterator<Ticket<?>> iterator = entry.getValue().iterator(); - boolean flag = false; - - while (iterator.hasNext()) { -- Ticket<?> ticket = (Ticket) iterator.next(); -- -- if (!immutableset.contains(ticket.getType())) { +- Ticket<?> ticket = iterator.next(); +- if (!set.contains(ticket.getType())) { - iterator.remove(); - flag = true; - this.tickingTicketsTracker.removeTicket(entry.getLongKey(), ticket); @@ -26109,15 +25621,14 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 - } - - if (flag) { -- this.ticketTracker.update(entry.getLongKey(), DistanceManager.getTicketLevelAt((SortedArraySet) entry.getValue()), false); +- this.ticketTracker.update(entry.getLongKey(), getTicketLevelAt(entry.getValue()), false); - } - -- if (((SortedArraySet) entry.getValue()).isEmpty()) { -- objectiterator.remove(); +- if (entry.getValue().isEmpty()) { +- objectIterator.remove(); - } - } + // Paper - rewrite chunk system - } public boolean hasTickets() { @@ -26146,36 +25657,36 @@ index f7c2c03749d6be25bf33afd61e1da120770b3432..746f61661e22d22f2acbbe54a5933e57 } // CraftBukkit end -+ /* // Paper - rewrite chunk system - private class ChunkTicketTracker extends ChunkTracker { - ++/* // Paper - rewrite chunk system + class ChunkTicketTracker extends ChunkTracker { private static final int MAX_LEVEL = ChunkLevel.MAX_LEVEL + 1; -@@ -483,7 +307,7 @@ public abstract class DistanceManager { - public int runDistanceUpdates(int distance) { - return this.runUpdates(distance); + +@@ -420,7 +295,7 @@ public abstract class DistanceManager { + public int runDistanceUpdates(int toUpdateCount) { + return this.runUpdates(toUpdateCount); } - } + }*/ // Paper - rewrite chunk system - private class FixedPlayerDistanceChunkTracker extends ChunkTracker { - -@@ -563,6 +387,7 @@ public abstract class DistanceManager { + class FixedPlayerDistanceChunkTracker extends ChunkTracker { + protected final Long2ByteMap chunks = new Long2ByteOpenHashMap(); +@@ -479,6 +354,7 @@ public abstract class DistanceManager { } } -+ /* // Paper - rewrite chunk system - private class PlayerTicketTracker extends DistanceManager.FixedPlayerDistanceChunkTracker { - - private int viewDistance = 0; -@@ -657,5 +482,5 @@ public abstract class DistanceManager { - private boolean haveTicketFor(int distance) { - return distance <= this.viewDistance; ++/* // Paper - rewrite chunk system + class PlayerTicketTracker extends DistanceManager.FixedPlayerDistanceChunkTracker { + private int viewDistance; + private final Long2IntMap queueLevels = Long2IntMaps.synchronize(new Long2IntOpenHashMap()); +@@ -555,5 +431,5 @@ public abstract class DistanceManager { + private boolean haveTicketFor(int level) { + return level <= this.viewDistance; } - } + }*/ // Paper - rewrite chunk system } diff --git a/net/minecraft/server/level/GenerationChunkHolder.java b/net/minecraft/server/level/GenerationChunkHolder.java -index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a5fd7489a 100644 +index cb66209c64b855dedf2e4e114a7716da13bc4587..da1366fdc4889d6a3befd43d81a19a816ed4cbe9 100644 --- a/net/minecraft/server/level/GenerationChunkHolder.java +++ b/net/minecraft/server/level/GenerationChunkHolder.java @@ -27,13 +27,7 @@ public abstract class GenerationChunkHolder { @@ -26196,52 +25707,52 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a @@ -43,243 +37,96 @@ public abstract class GenerationChunkHolder { } - public CompletableFuture<ChunkResult<ChunkAccess>> scheduleChunkGenerationTask(ChunkStatus requestedStatus, ChunkMap chunkLoadingManager) { -- if (this.isStatusDisallowed(requestedStatus)) { + public CompletableFuture<ChunkResult<ChunkAccess>> scheduleChunkGenerationTask(ChunkStatus targetStatus, ChunkMap chunkMap) { +- if (this.isStatusDisallowed(targetStatus)) { - return UNLOADED_CHUNK_FUTURE; - } else { -- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = this.getOrCreateFuture(requestedStatus); -- if (completableFuture.isDone()) { -- return completableFuture; +- CompletableFuture<ChunkResult<ChunkAccess>> future = this.getOrCreateFuture(targetStatus); +- if (future.isDone()) { +- return future; - } else { - ChunkGenerationTask chunkGenerationTask = this.task.get(); -- if (chunkGenerationTask == null || requestedStatus.isAfter(chunkGenerationTask.targetStatus)) { -- this.rescheduleChunkTask(chunkLoadingManager, requestedStatus); +- if (chunkGenerationTask == null || targetStatus.isAfter(chunkGenerationTask.targetStatus)) { +- this.rescheduleChunkTask(chunkMap, targetStatus); - } - -- return completableFuture; +- return future; - } - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - CompletableFuture<ChunkResult<ChunkAccess>> applyStep(ChunkStep step, GeneratingChunkMap chunkLoadingManager, StaticCache2D<GenerationChunkHolder> chunks) { + CompletableFuture<ChunkResult<ChunkAccess>> applyStep(ChunkStep step, GeneratingChunkMap chunkMap, StaticCache2D<GenerationChunkHolder> cache) { - if (this.isStatusDisallowed(step.targetStatus())) { - return UNLOADED_CHUNK_FUTURE; - } else { -- return this.acquireStatusBump(step.targetStatus()) ? chunkLoadingManager.applyStep(this, step, chunks).handle((chunk, throwable) -> { +- return this.acquireStatusBump(step.targetStatus()) ? chunkMap.applyStep(this, step, cache).handle((chunkAccess, throwable) -> { - if (throwable != null) { - CrashReport crashReport = CrashReport.forThrowable(throwable, "Exception chunk generation/loading"); - MinecraftServer.setFatalException(new ReportedException(crashReport)); - } else { -- this.completeFuture(step.targetStatus(), chunk); +- this.completeFuture(step.targetStatus(), chunkAccess); - } - -- return ChunkResult.of(chunk); +- return ChunkResult.of(chunkAccess); - }) : this.getOrCreateFuture(step.targetStatus()); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - protected void updateHighestAllowedStatus(ChunkMap chunkLoadingManager) { + protected void updateHighestAllowedStatus(ChunkMap chunkMap) { - ChunkStatus chunkStatus = this.highestAllowedStatus; -- ChunkStatus chunkStatus2 = ChunkLevel.generationStatus(this.getTicketLevel()); -- this.highestAllowedStatus = chunkStatus2; -- boolean bl = chunkStatus != null && (chunkStatus2 == null || chunkStatus2.isBefore(chunkStatus)); -- if (bl) { -- this.failAndClearPendingFuturesBetween(chunkStatus2, chunkStatus); +- ChunkStatus chunkStatus1 = ChunkLevel.generationStatus(this.getTicketLevel()); +- this.highestAllowedStatus = chunkStatus1; +- boolean flag = chunkStatus != null && (chunkStatus1 == null || chunkStatus1.isBefore(chunkStatus)); +- if (flag) { +- this.failAndClearPendingFuturesBetween(chunkStatus1, chunkStatus); - if (this.task.get() != null) { -- this.rescheduleChunkTask(chunkLoadingManager, this.findHighestStatusWithPendingFuture(chunkStatus2)); +- this.rescheduleChunkTask(chunkMap, this.findHighestStatusWithPendingFuture(chunkStatus1)); - } - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system @@ -26251,57 +25762,57 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a - CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = CompletableFuture.completedFuture(ChunkResult.of(chunk)); - - for (int i = 0; i < this.futures.length() - 1; i++) { -- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture2 = this.futures.get(i); -- Objects.requireNonNull(completableFuture2); -- ChunkAccess chunkAccess = completableFuture2.getNow(NOT_DONE_YET).orElse(null); +- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture1 = this.futures.get(i); +- Objects.requireNonNull(completableFuture1); +- ChunkAccess chunkAccess = completableFuture1.getNow(NOT_DONE_YET).orElse(null); - if (!(chunkAccess instanceof ProtoChunk)) { - throw new IllegalStateException("Trying to replace a ProtoChunk, but found " + chunkAccess); - } - -- if (!this.futures.compareAndSet(i, completableFuture2, completableFuture)) { +- if (!this.futures.compareAndSet(i, completableFuture1, completableFuture)) { - throw new IllegalStateException("Future changed by other thread while trying to replace it"); - } - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - void removeTask(ChunkGenerationTask loader) { -- this.task.compareAndSet(loader, null); + void removeTask(ChunkGenerationTask task) { +- this.task.compareAndSet(task, null); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void rescheduleChunkTask(ChunkMap chunkLoadingManager, @Nullable ChunkStatus requestedStatus) { + private void rescheduleChunkTask(ChunkMap chunkMap, @Nullable ChunkStatus targetStatus) { - ChunkGenerationTask chunkGenerationTask; -- if (requestedStatus != null) { -- chunkGenerationTask = chunkLoadingManager.scheduleGenerationTask(requestedStatus, this.getPos()); +- if (targetStatus != null) { +- chunkGenerationTask = chunkMap.scheduleGenerationTask(targetStatus, this.getPos()); - } else { - chunkGenerationTask = null; - } - -- ChunkGenerationTask chunkGenerationTask3 = this.task.getAndSet(chunkGenerationTask); -- if (chunkGenerationTask3 != null) { -- chunkGenerationTask3.markForCancellation(); +- ChunkGenerationTask chunkGenerationTask1 = this.task.getAndSet(chunkGenerationTask); +- if (chunkGenerationTask1 != null) { +- chunkGenerationTask1.markForCancellation(); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private CompletableFuture<ChunkResult<ChunkAccess>> getOrCreateFuture(ChunkStatus status) { -- if (this.isStatusDisallowed(status)) { + private CompletableFuture<ChunkResult<ChunkAccess>> getOrCreateFuture(ChunkStatus targetStatus) { +- if (this.isStatusDisallowed(targetStatus)) { - return UNLOADED_CHUNK_FUTURE; - } else { -- int i = status.getIndex(); -- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = this.futures.get(i); +- int index = targetStatus.getIndex(); +- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = this.futures.get(index); - - while (completableFuture == null) { -- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture2 = new CompletableFuture<>(); -- completableFuture = this.futures.compareAndExchange(i, null, completableFuture2); +- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture1 = new CompletableFuture<>(); +- completableFuture = this.futures.compareAndExchange(index, null, completableFuture1); - if (completableFuture == null) { -- if (this.isStatusDisallowed(status)) { -- this.failAndClearPendingFuture(i, completableFuture2); +- if (this.isStatusDisallowed(targetStatus)) { +- this.failAndClearPendingFuture(index, completableFuture1); - return UNLOADED_CHUNK_FUTURE; - } - -- return completableFuture2; +- return completableFuture1; - } - } - @@ -26310,34 +25821,34 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void failAndClearPendingFuturesBetween(@Nullable ChunkStatus from, ChunkStatus to) { -- int i = from == null ? 0 : from.getIndex() + 1; -- int j = to.getIndex(); + private void failAndClearPendingFuturesBetween(@Nullable ChunkStatus highestAllowableStatus, ChunkStatus currentStatus) { +- int i = highestAllowableStatus == null ? 0 : highestAllowableStatus.getIndex() + 1; +- int index = currentStatus.getIndex(); - -- for (int k = i; k <= j; k++) { -- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = this.futures.get(k); +- for (int i1 = i; i1 <= index; i1++) { +- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = this.futures.get(i1); - if (completableFuture != null) { -- this.failAndClearPendingFuture(k, completableFuture); +- this.failAndClearPendingFuture(i1, completableFuture); - } - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void failAndClearPendingFuture(int statusIndex, CompletableFuture<ChunkResult<ChunkAccess>> previousFuture) { -- if (previousFuture.complete(UNLOADED_CHUNK) && !this.futures.compareAndSet(statusIndex, previousFuture, null)) { + private void failAndClearPendingFuture(int status, CompletableFuture<ChunkResult<ChunkAccess>> future) { +- if (future.complete(UNLOADED_CHUNK) && !this.futures.compareAndSet(status, future, null)) { - throw new IllegalStateException("Nothing else should replace the future here"); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void completeFuture(ChunkStatus status, ChunkAccess chunk) { -- ChunkResult<ChunkAccess> chunkResult = ChunkResult.of(chunk); -- int i = status.getIndex(); + private void completeFuture(ChunkStatus targetStatus, ChunkAccess chunkAccess) { +- ChunkResult<ChunkAccess> chunkResult = ChunkResult.of(chunkAccess); +- int index = targetStatus.getIndex(); - - while (true) { -- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = this.futures.get(i); +- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = this.futures.get(index); - if (completableFuture == null) { -- if (this.futures.compareAndSet(i, null, CompletableFuture.completedFuture(chunkResult))) { +- if (this.futures.compareAndSet(index, null, CompletableFuture.completedFuture(chunkResult))) { - return; - } - } else { @@ -26356,14 +25867,14 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a } @Nullable - private ChunkStatus findHighestStatusWithPendingFuture(@Nullable ChunkStatus checkUpperBound) { -- if (checkUpperBound == null) { + private ChunkStatus findHighestStatusWithPendingFuture(@Nullable ChunkStatus generationStatus) { +- if (generationStatus == null) { - return null; - } else { -- ChunkStatus chunkStatus = checkUpperBound; +- ChunkStatus chunkStatus = generationStatus; - -- for (ChunkStatus chunkStatus2 = this.startedWork.get(); -- chunkStatus2 == null || chunkStatus.isAfter(chunkStatus2); +- for (ChunkStatus chunkStatus1 = this.startedWork.get(); +- chunkStatus1 == null || chunkStatus.isAfter(chunkStatus1); - chunkStatus = chunkStatus.getParent() - ) { - if (this.futures.get(chunkStatus.getIndex()) != null) { @@ -26380,15 +25891,15 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private boolean acquireStatusBump(ChunkStatus nextStatus) { -- ChunkStatus chunkStatus = nextStatus == ChunkStatus.EMPTY ? null : nextStatus.getParent(); -- ChunkStatus chunkStatus2 = this.startedWork.compareAndExchange(chunkStatus, nextStatus); -- if (chunkStatus2 == chunkStatus) { + private boolean acquireStatusBump(ChunkStatus status) { +- ChunkStatus chunkStatus = status == ChunkStatus.EMPTY ? null : status.getParent(); +- ChunkStatus chunkStatus1 = this.startedWork.compareAndExchange(chunkStatus, status); +- if (chunkStatus1 == chunkStatus) { - return true; -- } else if (chunkStatus2 != null && !nextStatus.isAfter(chunkStatus2)) { +- } else if (chunkStatus1 != null && !status.isAfter(chunkStatus1)) { - return false; - } else { -- throw new IllegalStateException("Unexpected last startedWork status: " + chunkStatus2 + " while trying to start: " + nextStatus); +- throw new IllegalStateException("Unexpected last startedWork status: " + chunkStatus1 + " while trying to start: " + status); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -26399,7 +25910,7 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - protected abstract void addSaveDependency(CompletableFuture<?> savingFuture); + protected abstract void addSaveDependency(CompletableFuture<?> saveDependency); public void increaseGenerationRefCount() { - if (this.generationRefCount.getAndIncrement() == 0) { @@ -26423,19 +25934,19 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a } @Nullable - public ChunkAccess getChunkIfPresentUnchecked(ChunkStatus requestedStatus) { -- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = this.futures.get(requestedStatus.getIndex()); + public ChunkAccess getChunkIfPresentUnchecked(ChunkStatus status) { +- CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = this.futures.get(status.getIndex()); - return completableFuture == null ? null : completableFuture.getNow(NOT_DONE_YET).orElse(null); + // Paper start - rewrite chunk system -+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)(Object)this).moonrise$getRealChunkHolder().getChunkIfPresentUnchecked(requestedStatus); ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)(Object)this).moonrise$getRealChunkHolder().getChunkIfPresentUnchecked(status); + // Paper end - rewrite chunk system } @Nullable - public ChunkAccess getChunkIfPresent(ChunkStatus requestedStatus) { -- return this.isStatusDisallowed(requestedStatus) ? null : this.getChunkIfPresentUnchecked(requestedStatus); + public ChunkAccess getChunkIfPresent(ChunkStatus status) { +- return this.isStatusDisallowed(status) ? null : this.getChunkIfPresentUnchecked(status); + // Paper start - rewrite chunk system -+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)(Object)this).moonrise$getRealChunkHolder().getChunkIfPresent(requestedStatus); ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)(Object)this).moonrise$getRealChunkHolder().getChunkIfPresent(status); + // Paper end - rewrite chunk system } @@ -26445,8 +25956,8 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a - if (chunkStatus == null) { - return null; - } else { -- ChunkAccess chunkAccess = this.getChunkIfPresentUnchecked(chunkStatus); -- return chunkAccess != null ? chunkAccess : this.getChunkIfPresentUnchecked(chunkStatus.getParent()); +- ChunkAccess chunkIfPresentUnchecked = this.getChunkIfPresentUnchecked(chunkStatus); +- return chunkIfPresentUnchecked != null ? chunkIfPresentUnchecked : this.getChunkIfPresentUnchecked(chunkStatus.getParent()); - } + // Paper start - rewrite chunk system + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder.ChunkCompletion lastCompletion = ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)(Object)this).moonrise$getRealChunkHolder().getLastChunkCompletion(); @@ -26494,8 +26005,8 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a public ChunkStatus getLatestStatus() { - for (int i = CHUNK_STATUSES.size() - 1; i >= 0; i--) { - ChunkStatus chunkStatus = CHUNK_STATUSES.get(i); -- ChunkAccess chunkAccess = this.getChunkIfPresentUnchecked(chunkStatus); -- if (chunkAccess != null) { +- ChunkAccess chunkIfPresentUnchecked = this.getChunkIfPresentUnchecked(chunkStatus); +- if (chunkIfPresentUnchecked != null) { - return chunkStatus; - } - } @@ -26508,7 +26019,7 @@ index 65206fdfa5b94eaca139e433b4865c16b16641f3..bf4463bcb5dc439ac5a3fa08dd60845a } } diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa7130c20f 100644 +index 796b5f8541b0cf84482ab2b5a60adde544d43593..7ce641cc34ef95e248e62ebf0b7fdfb8b2924256 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -52,7 +52,7 @@ import net.minecraft.world.level.storage.DimensionDataStorage; @@ -26517,10 +26028,10 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa -public class ServerChunkCache extends ChunkSource { +public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache { // Paper - rewrite chunk system - private static final Logger LOGGER = LogUtils.getLogger(); private final DistanceManager distanceManager; -@@ -81,6 +81,107 @@ public class ServerChunkCache extends ChunkSource { + private final ServerLevel level; +@@ -80,6 +80,107 @@ public class ServerChunkCache extends ChunkSource { } long chunkFutureAwaitCounter; // Paper end @@ -26626,9 +26137,9 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa + // Paper end - chunk tick iteration optimisations + - public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory) { - this.level = world; -@@ -112,13 +213,7 @@ public class ServerChunkCache extends ChunkSource { + public ServerChunkCache( + ServerLevel level, +@@ -138,13 +239,7 @@ public class ServerChunkCache extends ChunkSource { } // CraftBukkit end // Paper start @@ -26643,61 +26154,54 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa @Nullable public ChunkAccess getChunkAtImmediately(int x, int z) { -@@ -189,59 +284,42 @@ public class ServerChunkCache extends ChunkSource { +@@ -215,51 +310,42 @@ public class ServerChunkCache extends ChunkSource { @Nullable @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus leastStatus, boolean create) { + public ChunkAccess getChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk) { - if (Thread.currentThread() != this.mainThread) { -- return (ChunkAccess) CompletableFuture.supplyAsync(() -> { -- return this.getChunk(x, z, leastStatus, create); -- }, this.mainThreadProcessor).join(); +- return CompletableFuture.<ChunkAccess>supplyAsync(() -> this.getChunk(x, z, chunkStatus, requireChunk), this.mainThreadProcessor).join(); - } else { - // Paper start - Perf: Optimise getChunkAt calls for loaded chunks -- LevelChunk ifLoaded = this.getChunkAtIfLoadedMainThread(x, z); +- LevelChunk ifLoaded = this.getChunkAtIfCachedImmediately(x, z); - if (ifLoaded != null) { - return ifLoaded; - } - // Paper end - Perf: Optimise getChunkAt calls for loaded chunks -- ProfilerFiller gameprofilerfiller = Profiler.get(); +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.incrementCounter("getChunk"); +- long packedChunkPos = ChunkPos.asLong(x, z); +- +- for (int i = 0; i < 4; i++) { +- if (packedChunkPos == this.lastChunkPos[i] && chunkStatus == this.lastChunkStatus[i]) { +- ChunkAccess chunkAccess = this.lastChunk[i]; +- if (chunkAccess != 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 chunkAccess; +- } +- } +- } + // Paper start - rewrite chunk system -+ if (leastStatus == ChunkStatus.FULL) { ++ if (chunkStatus == ChunkStatus.FULL) { + final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z)); -- 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]; -- -- 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; -- } -- } +- profilerFiller.incrementCounter("getChunkCacheMiss"); +- CompletableFuture<ChunkResult<ChunkAccess>> chunkFutureMainThread = this.getChunkFutureMainThread(x, z, chunkStatus, requireChunk); +- this.mainThreadProcessor.managedBlock(chunkFutureMainThread::isDone); +- // com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads +- ChunkResult<ChunkAccess> chunkResult = chunkFutureMainThread.join(); +- ChunkAccess chunkAccess1 = chunkResult.orElse(null); +- if (chunkAccess1 == null && requireChunk) { +- throw (IllegalStateException)Util.pauseInIde(new IllegalStateException("Chunk not there when requested: " + chunkResult.getError())); +- } else { +- this.storeInCache(packedChunkPos, chunkAccess1, chunkStatus); +- return chunkAccess1; + if (ret != null) { + return ret; } - -- gameprofilerfiller.incrementCounter("getChunkCacheMiss"); -- CompletableFuture<ChunkResult<ChunkAccess>> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create); -- ServerChunkCache.MainThreadExecutor chunkproviderserver_b = this.mainThreadProcessor; -- -- Objects.requireNonNull(completablefuture); -- chunkproviderserver_b.managedBlock(completablefuture::isDone); -- // com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads -- ChunkResult<ChunkAccess> chunkresult = (ChunkResult) completablefuture.join(); -- ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error -- -- if (ichunkaccess1 == null && create) { -- throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("Chunk not there when requested: " + chunkresult.getError())); -- } else { -- this.storeInCache(k, ichunkaccess1, leastStatus); -- return ichunkaccess1; -- } -+ return create ? this.getChunkFallback(x, z, leastStatus, create) : null; ++ ++ return requireChunk ? this.getChunkFallback(x, z, chunkStatus, requireChunk) : null; } + -+ return this.getChunkFallback(x, z, leastStatus, create); ++ return this.getChunkFallback(x, z, chunkStatus, requireChunk); + // Paper end - rewrite chunk system } @@ -26707,7 +26211,7 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa - if (Thread.currentThread() != this.mainThread) { - return null; - } else { -- return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks +- return this.getChunkAtIfCachedImmediately(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks + // Paper start - rewrite chunk system + final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); + if (!ca.spottedleaf.moonrise.common.PlatformHooks.get().hasCurrentlyLoadingChunk()) { @@ -26716,64 +26220,64 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa + + if (ret != null || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) { + return ret; -+ } + } + + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler() + .chunkHolderManager.getChunkHolder(chunkX, chunkZ); + if (holder == null) { + return ret; - } ++ } + + return ca.spottedleaf.moonrise.common.PlatformHooks.get().getCurrentlyLoadingChunk(holder.vanillaChunkHolder); + // Paper end - rewrite chunk system } private void clearCache() { -@@ -272,56 +350,59 @@ public class ServerChunkCache extends ChunkSource { +@@ -285,54 +371,59 @@ public class ServerChunkCache extends ChunkSource { } - private CompletableFuture<ChunkResult<ChunkAccess>> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { -- ChunkPos chunkcoordintpair = new ChunkPos(chunkX, chunkZ); -- long k = chunkcoordintpair.toLong(); -- int l = ChunkLevel.byStatus(leastStatus); -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k); -- + private CompletableFuture<ChunkResult<ChunkAccess>> getChunkFutureMainThread(int x, int z, ChunkStatus chunkStatus, boolean requireChunk) { +- ChunkPos chunkPos = new ChunkPos(x, z); +- long packedChunkPos = chunkPos.toLong(); +- int i = ChunkLevel.byStatus(chunkStatus); +- ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(packedChunkPos); - // 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()); +- if (visibleChunkIfPresent != null) { +- FullChunkStatus oldChunkState = ChunkLevel.fullStatus(visibleChunkIfPresent.oldTicketLevel); +- FullChunkStatus currentChunkState = ChunkLevel.fullStatus(visibleChunkIfPresent.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"); +- if (requireChunk && !currentlyUnloading) { +- // CraftBukkit end +- this.distanceManager.addTicket(TicketType.UNKNOWN, chunkPos, i, chunkPos); +- if (this.chunkAbsent(visibleChunkIfPresent, i)) { +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.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")); +- visibleChunkIfPresent = this.getVisibleChunkIfPresent(packedChunkPos); +- profilerFiller.pop(); +- if (this.chunkAbsent(visibleChunkIfPresent, i)) { +- 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"); ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.level, x, z, "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); ++ final int minLevel = ChunkLevel.byStatus(chunkStatus); ++ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(x, z); + -+ final boolean needsFullScheduling = leastStatus == ChunkStatus.FULL && (chunkHolder == null || !chunkHolder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)); ++ final boolean needsFullScheduling = chunkStatus == ChunkStatus.FULL && (chunkHolder == null || !chunkHolder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)); + -+ if ((chunkHolder == null || chunkHolder.getTicketLevel() > minLevel || needsFullScheduling) && !create) { ++ if ((chunkHolder == null || chunkHolder.getTicketLevel() > minLevel || needsFullScheduling) && !requireChunk) { + return ChunkHolder.UNLOADED_CHUNK_FUTURE; } -- return this.chunkAbsent(playerchunk, l) ? GenerationChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.scheduleChunkGenerationTask(leastStatus, this.chunkMap); +- return this.chunkAbsent(visibleChunkIfPresent, i) +- ? GenerationChunkHolder.UNLOADED_CHUNK_FUTURE +- : visibleChunkIfPresent.scheduleChunkGenerationTask(chunkStatus, this.chunkMap); - } -+ final ChunkAccess ifPresent = chunkHolder == null ? null : chunkHolder.getChunkIfPresent(leastStatus); ++ final ChunkAccess ifPresent = chunkHolder == null ? null : chunkHolder.getChunkIfPresent(chunkStatus); + if (needsFullScheduling || ifPresent == null) { + // schedule + final CompletableFuture<ChunkResult<ChunkAccess>> ret = new CompletableFuture<>(); @@ -26785,10 +26289,10 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa + } + }; -- private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) { -- return holder == null || holder.oldTicketLevel > maxLevel; // CraftBukkit using oldTicketLevel for isLoaded checks +- private boolean chunkAbsent(@Nullable ChunkHolder chunkHolder, int status) { +- return chunkHolder == null || chunkHolder.oldTicketLevel > status; // CraftBukkit using oldTicketLevel for isLoaded checks + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().scheduleChunkLoad( -+ chunkX, chunkZ, leastStatus, true, ++ x, z, chunkStatus, true, + ca.spottedleaf.concurrentutil.util.Priority.HIGHER, + complete + ); @@ -26803,20 +26307,18 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa @Override public boolean hasChunk(int x, int z) { -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent((new ChunkPos(x, z)).toLong()); -- int k = ChunkLevel.byStatus(ChunkStatus.FULL); -- -- return !this.chunkAbsent(playerchunk, k); +- ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(new ChunkPos(x, z).toLong()); +- int i = ChunkLevel.byStatus(ChunkStatus.FULL); +- return !this.chunkAbsent(visibleChunkIfPresent, i); + return this.getChunkNow(x, z) != null; // Paper - rewrite chunk system } @Nullable @Override public LightChunk getChunkForLighting(int chunkX, int chunkZ) { -- long k = ChunkPos.asLong(chunkX, chunkZ); -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k); -- -- return playerchunk == null ? null : playerchunk.getChunkIfPresentUnchecked(ChunkStatus.INITIALIZE_LIGHT.getParent()); +- long packedChunkPos = ChunkPos.asLong(chunkX, chunkZ); +- ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(packedChunkPos); +- return visibleChunkIfPresent == null ? null : visibleChunkIfPresent.getChunkIfPresentUnchecked(ChunkStatus.INITIALIZE_LIGHT.getParent()); + // 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(chunkX, chunkZ); + if (newChunkHolder == null) { @@ -26827,13 +26329,12 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa } @Override -@@ -334,30 +415,18 @@ public class ServerChunkCache extends ChunkSource { +@@ -345,28 +436,18 @@ public class ServerChunkCache extends ChunkSource { } public boolean runDistanceManagerUpdates() { // Paper - public - boolean flag = this.distanceManager.runAllUpdates(this.chunkMap); - boolean flag1 = this.chunkMap.promoteChunkMap(); -- - this.chunkMap.runGenerationTasks(); - if (!flag && !flag1) { - return false; @@ -26844,16 +26345,15 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa + return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.processTicketUpdates(); // Paper - rewrite chunk system } - public boolean isPositionTicking(long pos) { -- if (!this.level.shouldTickBlocksAt(pos)) { + public boolean isPositionTicking(long chunkPos) { +- if (!this.level.shouldTickBlocksAt(chunkPos)) { - return false; - } else { -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); -- -- return playerchunk == null ? false : ((ChunkResult) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).isSuccess(); +- ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(chunkPos); +- return visibleChunkIfPresent != null && visibleChunkIfPresent.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); ++ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); + return newChunkHolder != null && newChunkHolder.isTickingReady(); + // Paper end - rewrite chunk system } @@ -26864,7 +26364,7 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa this.chunkMap.saveAllChunks(flush); } -@@ -368,17 +437,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -377,17 +458,15 @@ public class ServerChunkCache extends ChunkSource { } public void close(boolean save) throws IOException { @@ -26885,50 +26385,50 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa ProfilerFiller gameprofilerfiller = Profiler.get(); gameprofilerfiller.push("purge"); -@@ -403,6 +470,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -411,6 +490,7 @@ public class ServerChunkCache extends ChunkSource { this.runDistanceManagerUpdates(); - gameprofilerfiller.popPush("chunks"); + profilerFiller.popPush("chunks"); if (tickChunks) { + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().tick(); // Paper - rewrite chunk system this.tickChunks(); this.chunkMap.tick(); } -@@ -429,7 +497,10 @@ public class ServerChunkCache extends ChunkSource { - gameprofilerfiller.push("filteringTickingChunks"); +@@ -435,7 +515,10 @@ public class ServerChunkCache extends ChunkSource { + profilerFiller.push("filteringTickingChunks"); this.collectTickingChunks(list); - gameprofilerfiller.popPush("shuffleChunks"); + profilerFiller.popPush("shuffleChunks"); - Util.shuffle(list, this.level.random); + // Paper start - chunk tick iteration optimisation + this.shuffleRandom.setSeed(this.level.random.nextLong()); + Util.shuffle(list, this.shuffleRandom); + // Paper end - chunk tick iteration optimisation - this.tickChunks(gameprofilerfiller, j, list); - gameprofilerfiller.pop(); + this.tickChunks(profilerFiller, l, list); + profilerFiller.pop(); } finally { -@@ -448,7 +519,7 @@ public class ServerChunkCache extends ChunkSource { - - while (iterator.hasNext()) { - ChunkHolder playerchunk = (ChunkHolder) iterator.next(); -- LevelChunk chunk = playerchunk.getTickingChunk(); -+ LevelChunk chunk = playerchunk.getChunkToSend(); // Paper - rewrite chunk system - - if (chunk != null) { - playerchunk.broadcastChanges(chunk); -@@ -460,14 +531,26 @@ public class ServerChunkCache extends ChunkSource { +@@ -452,7 +535,7 @@ public class ServerChunkCache extends ChunkSource { + profiler.push("broadcast"); + + for (ChunkHolder chunkHolder : this.chunkHoldersToBroadcast) { +- LevelChunk tickingChunk = chunkHolder.getTickingChunk(); ++ LevelChunk tickingChunk = chunkHolder.getChunkToSend(); // Paper - rewrite chunk system + if (tickingChunk != null) { + chunkHolder.broadcastChanges(tickingChunk); + } +@@ -463,12 +546,26 @@ public class ServerChunkCache extends ChunkSource { } - private void collectTickingChunks(List<LevelChunk> chunks) { -- this.chunkMap.forEachSpawnCandidateChunk((playerchunk) -> { -- LevelChunk chunk = playerchunk.getTickingChunk(); + private void collectTickingChunks(List<LevelChunk> output) { +- this.chunkMap.forEachSpawnCandidateChunk(chunk -> { +- LevelChunk tickingChunk = chunk.getTickingChunk(); +- if (tickingChunk != null && this.level.isNaturalSpawningAllowed(chunk.getPos())) { +- output.add(tickingChunk); + // Paper start - chunk tick iteration optimisation + final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerChunkCache.ChunkAndHolder> tickingChunks = + ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel)this.level).moonrise$getPlayerTickingChunks(); + + final ServerChunkCache.ChunkAndHolder[] raw = tickingChunks.getRawDataUnchecked(); + final int size = tickingChunks.size(); - -- if (chunk != null && this.level.isNaturalSpawningAllowed(playerchunk.getPos())) { -- chunks.add(chunk); ++ + final ChunkMap chunkMap = this.chunkMap; + + for (int i = 0; i < size; ++i) { @@ -26938,43 +26438,42 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa + if (!this.isChunkNearPlayer(chunkMap, levelChunk.getPos(), levelChunk)) { + continue; } - - }); -+ chunks.add(levelChunk); ++ ++ output.add(levelChunk); + } + // Paper end - chunk tick iteration optimisation } - private void tickChunks(ProfilerFiller profiler, long timeDelta, List<LevelChunk> chunks) { -@@ -508,7 +591,7 @@ public class ServerChunkCache extends ChunkSource { - NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, list1); + private void tickChunks(ProfilerFiller profiler, long timeInhabited, List<LevelChunk> chunks) { +@@ -504,7 +601,7 @@ public class ServerChunkCache extends ChunkSource { + NaturalSpawner.spawnForChunk(this.level, levelChunk, spawnState, filteredSpawningCategories); } -- if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { +- if (this.level.shouldTickBlocksAt(pos.toLong())) { + if (true) { // Paper - rewrite chunk system - this.level.tickChunk(chunk, k); + this.level.tickChunk(levelChunk, _int); } } -@@ -521,11 +604,13 @@ public class ServerChunkCache extends ChunkSource { +@@ -516,10 +613,13 @@ public class ServerChunkCache extends ChunkSource { } - private void getFullChunk(long pos, Consumer<LevelChunk> chunkConsumer) { -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); -- -- if (playerchunk != null) { -- ((ChunkResult) playerchunk.getFullChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).ifSuccess(chunkConsumer); + private void getFullChunk(long chunkPos, Consumer<LevelChunk> fullChunkGetter) { +- ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(chunkPos); +- if (visibleChunkIfPresent != null) { +- visibleChunkIfPresent.getFullChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).ifSuccess(fullChunkGetter); + // Paper start - rewrite chunk system + // note: bypass currentlyLoaded from getChunkNow -+ final LevelChunk fullChunk = this.fullChunks.get(pos); ++ final LevelChunk fullChunk = this.fullChunks.get(chunkPos); + if (fullChunk != null) { -+ chunkConsumer.accept(fullChunk); ++ fullChunkGetter.accept(fullChunk); } + // Paper end - rewrite chunk system - } -@@ -619,6 +704,12 @@ public class ServerChunkCache extends ChunkSource { - this.chunkMap.setServerViewDistance(watchDistance); + @Override +@@ -607,6 +707,12 @@ public class ServerChunkCache extends ChunkSource { + this.chunkMap.setServerViewDistance(viewDistance); } + // Paper start - rewrite chunk system @@ -26986,11 +26485,20 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa public void setSimulationDistance(int simulationDistance) { this.distanceManager.updateSimulationDistance(simulationDistance); } -@@ -710,21 +801,19 @@ public class ServerChunkCache extends ChunkSource { +@@ -654,7 +760,7 @@ public class ServerChunkCache extends ChunkSource { + } + } + +- record ChunkAndHolder(LevelChunk chunk, ChunkHolder holder) { ++ public record ChunkAndHolder(LevelChunk chunk, ChunkHolder holder) { // Paper - public + } + + public final class MainThreadExecutor extends BlockableEventLoop<Runnable> { +@@ -695,18 +801,14 @@ public class ServerChunkCache extends ChunkSource { + @Override - // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task public boolean pollTask() { -- try { +- try { // CraftBukkit - process pending Chunk loadCallback() and unloadCallback() after each run task - if (ServerChunkCache.this.runDistanceManagerUpdates()) { + // Paper start - rewrite chunk system + final ServerChunkCache serverChunkCache = ServerChunkCache.this; @@ -26999,26 +26507,22 @@ index 6a2af3cd3aebe525a5ff41a801929547d59b8fec..d7382fc1498a33db909c343d8d07c5aa } else { - ServerChunkCache.this.lightEngine.tryScheduleUpdate(); - return super.pollTask(); +- } +- // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task +- } finally { +- ServerChunkCache.this.chunkMap.callbackExecutor.run(); + return super.pollTask() | ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)serverChunkCache.level).moonrise$getChunkTaskScheduler().executeMainThreadTask(); } -- } finally { -- ServerChunkCache.this.chunkMap.callbackExecutor.run(); -- } +- // CraftBukkit end - process pending Chunk loadCallback() and unloadCallback() after each run task + // Paper end - rewrite chunk system - // CraftBukkit end } } - -- private static record ChunkAndHolder(LevelChunk chunk, ChunkHolder holder) { -+ public static record ChunkAndHolder(LevelChunk chunk, ChunkHolder holder) { // Paper - rewrite chunk system - public - - } } diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java -index d5bc702f2676b1b7a32c8f3a4a349fc2710ee825..301e8d6599d200cb0f1328f0e386af2f9a619939 100644 +index 4c891706c2a3efc8e8c44fc1c031e8a1d21efb60..d38ddfd7afba189a489701e62b5fa6db8df87a9d 100644 --- a/net/minecraft/server/level/ServerEntity.java +++ b/net/minecraft/server/level/ServerEntity.java -@@ -101,6 +101,11 @@ public class ServerEntity { +@@ -91,6 +91,11 @@ public class ServerEntity { } public void sendChanges() { @@ -27027,24 +26531,24 @@ index d5bc702f2676b1b7a32c8f3a4a349fc2710ee825..301e8d6599d200cb0f1328f0e386af2f + this.teleportDelay = 9999; + } + // Paper end - optimise collisions - List<Entity> list = this.entity.getPassengers(); - - if (!list.equals(this.lastPassengers)) { + List<Entity> passengers = this.entity.getPassengers(); + if (!passengers.equals(this.lastPassengers)) { + this.broadcastAndSend(new ClientboundSetPassengersPacket(this.entity)); // CraftBukkit diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905d8325618 100644 +index 08ee3583a07b6e4e877e530d422e386597bce6de..3927f5603d18f1c42eb29d916f287b6ef3f39612 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -186,7 +186,7 @@ import org.bukkit.event.weather.LightningStrikeEvent; - import org.bukkit.event.world.TimeSkipEvent; - // CraftBukkit end +@@ -170,7 +170,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; + import net.minecraft.world.ticks.LevelTicks; + import org.slf4j.Logger; -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, ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel { // Paper - rewrite chunk system // Paper - chunk tick iteration - ++public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLevel, ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel, ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader, ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel { // Paper - rewrite chunk system // Paper - chunk tick iteration public static final BlockPos END_SPAWN_POINT = new BlockPos(100, 50, 0); public static final IntProvider RAIN_DELAY = UniformInt.of(12000, 180000); -@@ -202,7 +202,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - public final PrimaryLevelData serverLevelData; // CraftBukkit - type + public static final IntProvider RAIN_DURATION = UniformInt.of(12000, 24000); +@@ -185,7 +185,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type private int lastSpawnChunkRadius; final EntityTickList entityTickList = new EntityTickList(); - public final PersistentEntitySectionManager<Entity> entityManager; @@ -27052,7 +26556,7 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 private final GameEventDispatcher gameEventDispatcher; public boolean noSave; private final SleepStatus sleepStatus; -@@ -273,12 +273,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -256,12 +256,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public final void loadChunksForMoveAsync(AABB axisalignedbb, ca.spottedleaf.concurrentutil.util.Priority priority, java.util.function.Consumer<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) { @@ -27066,7 +26570,7 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3; int minBlockZ = Mth.floor(axisalignedbb.minZ - 1.0E-7D) - 3; -@@ -297,32 +292,159 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -280,32 +275,159 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public final void loadChunks(int minChunkX, int minChunkZ, int maxChunkX, int maxChunkZ, ca.spottedleaf.concurrentutil.util.Priority priority, java.util.function.Consumer<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) { @@ -27114,9 +26618,7 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder.ChunkCompletion lastCompletion = newChunkHolder.getLastChunkCompletion(); + return lastCompletion == null ? null : lastCompletion.chunk(); + } - -- int requiredChunks = (maxChunkX - minChunkX + 1) * (maxChunkZ - minChunkZ + 1); -- int[] loadedChunks = new int[1]; ++ + @Override + public final ChunkAccess moonrise$getSpecificChunkIfLoaded(final int chunkX, final int chunkZ, final net.minecraft.world.level.chunk.status.ChunkStatus leastStatus) { + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkX, chunkZ); @@ -27135,14 +26637,12 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 + public final ChunkAccess moonrise$syncLoadNonFull(final int chunkX, final int chunkZ, final net.minecraft.world.level.chunk.status.ChunkStatus status) { + return this.moonrise$getChunkTaskScheduler().syncLoadNonFull(chunkX, chunkZ, status); + } - -- Long holderIdentifier = Long.valueOf(chunkProvider.chunkFutureAwaitCounter++); ++ + @Override + public final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler moonrise$getChunkTaskScheduler() { + return this.chunkTaskScheduler; + } - -- java.util.function.Consumer<net.minecraft.world.level.chunk.ChunkAccess> consumer = (net.minecraft.world.level.chunk.ChunkAccess chunk) -> { ++ + @Override + public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController moonrise$getChunkDataController() { + return this.chunkDataController; @@ -27207,14 +26707,18 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 + final java.util.function.Consumer<java.util.List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) { + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler chunkTaskScheduler = this.moonrise$getChunkTaskScheduler(); + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager chunkHolderManager = chunkTaskScheduler.chunkHolderManager; -+ + +- int requiredChunks = (maxChunkX - minChunkX + 1) * (maxChunkZ - minChunkZ + 1); +- int[] loadedChunks = new int[1]; + final int requiredChunks = (maxChunkX - minChunkX + 1) * (maxChunkZ - minChunkZ + 1); + final java.util.concurrent.atomic.AtomicInteger loadedChunks = new java.util.concurrent.atomic.AtomicInteger(); + final Long holderIdentifier = ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.getNextChunkLoadId(); + final int ticketLevel = ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.getTicketLevel(chunkStatus); -+ + +- Long holderIdentifier = Long.valueOf(chunkProvider.chunkFutureAwaitCounter++); + final List<ChunkAccess> ret = new ArrayList<>(requiredChunks); -+ + +- java.util.function.Consumer<net.minecraft.world.level.chunk.ChunkAccess> consumer = (net.minecraft.world.level.chunk.ChunkAccess chunk) -> { + final java.util.function.Consumer<net.minecraft.world.level.chunk.ChunkAccess> consumer = (final ChunkAccess chunk) -> { if (chunk != null) { - int ticketLevel = Math.max(33, chunkProvider.chunkMap.getUpdatingChunkIfPresent(chunk.getPos().toLong()).getTicketLevel()); @@ -27242,14 +26746,7 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 } } } -@@ -330,22 +452,137 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - - for (int cx = minChunkX; cx <= maxChunkX; ++cx) { - for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { -- ca.spottedleaf.moonrise.common.util.ChunkSystem.scheduleChunkLoad( -- this, cx, cz, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, true, priority, consumer -- ); -+ chunkTaskScheduler.scheduleChunkLoad(cx, cz, chunkStatus, true, priority, consumer); +@@ -319,16 +441,133 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } } } @@ -27263,8 +26760,7 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 - return player != null && player.level() == this ? player : null; + public final ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.ViewDistanceHolder moonrise$getViewDistanceHolder() { + return this.viewDistanceHolder; - } -- // Paper end - optimise getPlayerByUUID ++ } + + @Override + public final long moonrise$getLastMidTickFailure() { @@ -27279,7 +26775,8 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 + @Override + public final ca.spottedleaf.moonrise.common.misc.NearbyPlayers moonrise$getNearbyPlayers() { + return this.nearbyPlayers; -+ } + } +- // Paper end - optimise getPlayerByUUID + + @Override + public final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerChunkCache.ChunkAndHolder> moonrise$getLoadedChunks() { @@ -27388,38 +26885,49 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 + } + // Paper end - chunk tick iteration - // Add env and gen to constructor, IWorldDataServer -> WorldDataServer - public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { -@@ -379,14 +616,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - DataFixer datafixer = minecraftserver.getFixerUpper(); - EntityPersistentStorage<Entity> 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); - -- this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage); -+ // Paper - rewrite chunk system - StructureTemplateManager structuretemplatemanager = minecraftserver.getStructureManager(); - int j = this.spigotConfig.viewDistance; // Spigot - int k = this.spigotConfig.simulationDistance; // Spigot -- PersistentEntitySectionManager persistententitysectionmanager = this.entityManager; + public ServerLevel( + MinecraftServer server, +@@ -376,18 +615,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // CraftBukkit end + boolean flag = server.forceSynchronousWrites(); + DataFixer fixerUpper = server.getFixerUpper(); +- EntityPersistentStorage<Entity> entityPersistentStorage = new EntityStorage( +- new SimpleRegionStorage( +- new RegionStorageInfo(levelStorageAccess.getLevelId(), dimension, "entities"), +- levelStorageAccess.getDimensionPath(dimension).resolve("entities"), +- fixerUpper, +- flag, +- DataFixTypes.ENTITY_CHUNK +- ), +- this, +- server +- ); +- this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entityPersistentStorage); + // Paper - rewrite chunk system - -- Objects.requireNonNull(this.entityManager); -- this.chunkSource = new ServerChunkCache(this, convertable_conversionsession, datafixer, structuretemplatemanager, executor, chunkgenerator, j, k, flag2, worldloadlistener, persistententitysectionmanager::updateChunkStatus, () -> { -+ this.chunkSource = new ServerChunkCache(this, convertable_conversionsession, datafixer, structuretemplatemanager, executor, chunkgenerator, j, k, flag2, worldloadlistener, null, () -> { // Paper - rewrite chunk system - return minecraftserver.overworld().getDataStorage(); - }); + this.chunkSource = new ServerChunkCache( + this, + levelStorageAccess, +@@ -399,7 +627,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.spigotConfig.simulationDistance, // Spigot + flag, + progressListener, +- this.entityManager::updateChunkStatus, ++ null, // Paper - rewrite chunk system + () -> server.overworld().getDataStorage() + ); this.chunkSource.getGeneratorState().ensureStructuresGenerated(); -@@ -414,6 +650,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.randomSequences = (RandomSequences) Objects.requireNonNullElseGet(randomsequences, () -> { - return (RandomSequences) this.getDataStorage().computeIfAbsent(RandomSequences.factory(l), "random_sequences"); - }); +@@ -437,6 +665,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.randomSequences = Objects.requireNonNullElseGet( + randomSequences, () -> this.getDataStorage().computeIfAbsent(RandomSequences.factory(seed), "random_sequences") + ); + // Paper start - rewrite chunk system + this.moonrise$setEntityLookup(new ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup((ServerLevel)(Object)this, ((ServerLevel)(Object)this).new EntityCallbacks())); + this.chunkTaskScheduler = new ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler((ServerLevel)(Object)this); + this.entityDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController( + new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController.EntityRegionFileStorage( -+ new RegionStorageInfo(convertable_conversionsession.getLevelId(), resourcekey, "entities"), -+ convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), -+ minecraftserver.forceSynchronousWrites() ++ new RegionStorageInfo(levelStorageAccess.getLevelId(), dimension, "entities"), ++ levelStorageAccess.getDimensionPath(dimension).resolve("entities"), ++ server.forceSynchronousWrites() + ), + this.chunkTaskScheduler + ); @@ -27429,22 +26937,23 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit } -@@ -536,7 +786,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - gameprofilerfiller.push("checkDespawn"); - entity.checkDespawn(); - gameprofilerfiller.pop(); -- 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) { -@@ -559,13 +809,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -560,8 +802,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + profilerFiller.push("checkDespawn"); + entity.checkDespawn(); + profilerFiller.pop(); +- if (entity instanceof ServerPlayer +- || this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { ++ if (true) { // Paper - rewrite chunk system + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + if (!vehicle.isRemoved() && vehicle.hasPassenger(entity)) { +@@ -584,13 +825,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } - gameprofilerfiller.push("entityManagement"); + profilerFiller.push("entityManagement"); - this.entityManager.tick(); + // Paper - rewrite chunk system - gameprofilerfiller.pop(); + profilerFiller.pop(); } @Override @@ -27457,8 +26966,8 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 } protected void tickTime() { -@@ -605,7 +858,60 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - }); +@@ -621,14 +865,67 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList()).forEach(player -> player.stopSleepInBed(false, false)); } + // Paper start - optimise random ticking @@ -27515,128 +27024,125 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 + public void tickChunk(LevelChunk chunk, int randomTickSpeed) { + final ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom simpleRandom = this.simpleRandom; // Paper - optimise random ticking - ChunkPos chunkcoordintpair = chunk.getPos(); - boolean flag = this.isRaining(); - int j = chunkcoordintpair.getMinBlockX(); -@@ -613,7 +919,7 @@ 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 -+ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && simpleRandom.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder // Paper - optimise random ticking - BlockPos blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15)); - - if (this.isRainingAt(blockposition)) { -@@ -645,7 +951,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + ChunkPos pos = chunk.getPos(); + boolean isRaining = this.isRaining(); + int minBlockX = pos.getMinBlockX(); + int minBlockZ = pos.getMinBlockZ(); + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("thunder"); +- if (!this.paperConfig().environment.disableThunder && isRaining && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder ++ if (!this.paperConfig().environment.disableThunder && isRaining && this.isThundering() && this.spigotConfig.thunderChance > 0 && simpleRandom.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder // Paper - optimise random ticking + BlockPos blockPos = this.findLightningTargetAround(this.getBlockRandomPos(minBlockX, 0, minBlockZ, 15)); + if (this.isRainingAt(blockPos)) { + DifficultyInstance currentDifficultyAt = this.getCurrentDifficultyAt(blockPos); +@@ -658,7 +955,7 @@ 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) { + for (int i = 0; i < randomTickSpeed; i++) { - if (this.random.nextInt(48) == 0) { -+ if (simpleRandom.nextInt(48) == 0) { // Paper - optimise random ticking - this.tickPrecipitation(this.getBlockRandomPos(j, 0, k, 15)); ++ if (simpleRandom.nextInt(48) == 0) { // Paper - optimise random ticking + this.tickPrecipitation(this.getBlockRandomPos(minBlockX, 0, minBlockZ, 15)); } } -@@ -653,35 +959,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -666,33 +963,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - gameprofilerfiller.popPush("tickBlocks"); + profilerFiller.popPush("tickBlocks"); if (randomTickSpeed > 0) { -- LevelChunkSection[] achunksection = chunk.getSections(); -- -- for (int i1 = 0; i1 < achunksection.length; ++i1) { -- LevelChunkSection chunksection = achunksection[i1]; -- -- if (chunksection.isRandomlyTicking()) { -- int j1 = chunk.getSectionYFromSectionIndex(i1); -- int k1 = SectionPos.sectionToBlockCoord(j1); -- -- for (int l1 = 0; l1 < randomTickSpeed; ++l1) { -- BlockPos blockposition1 = this.getBlockRandomPos(j, k1, k, 15); -- -- gameprofilerfiller.push("randomTick"); -- BlockState iblockdata = chunksection.getBlockState(blockposition1.getX() - j, blockposition1.getY() - k1, blockposition1.getZ() - k); -- -- if (iblockdata.isRandomlyTicking()) { -- iblockdata.randomTick(this, blockposition1, this.random); +- LevelChunkSection[] sections = chunk.getSections(); +- +- for (int i1 = 0; i1 < sections.length; i1++) { +- LevelChunkSection levelChunkSection = sections[i1]; +- if (levelChunkSection.isRandomlyTicking()) { +- int sectionYFromSectionIndex = chunk.getSectionYFromSectionIndex(i1); +- int blockPosCoord = SectionPos.sectionToBlockCoord(sectionYFromSectionIndex); +- +- for (int i2 = 0; i2 < randomTickSpeed; i2++) { +- BlockPos blockRandomPos = this.getBlockRandomPos(minBlockX, blockPosCoord, minBlockZ, 15); +- profilerFiller.push("randomTick"); +- BlockState blockState = levelChunkSection.getBlockState( +- blockRandomPos.getX() - minBlockX, blockRandomPos.getY() - blockPosCoord, blockRandomPos.getZ() - minBlockZ +- ); +- if (blockState.isRandomlyTicking()) { +- blockState.randomTick(this, blockRandomPos, this.random); - } - -- FluidState fluid = iblockdata.getFluidState(); -- -- if (fluid.isRandomlyTicking()) { -- fluid.randomTick(this, blockposition1, this.random); +- FluidState fluidState = blockState.getFluidState(); +- if (fluidState.isRandomlyTicking()) { +- fluidState.randomTick(this, blockRandomPos, this.random); - } - -- gameprofilerfiller.pop(); +- profilerFiller.pop(); - } - } - } + this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking } - gameprofilerfiller.pop(); -@@ -954,6 +1232,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (fluid1.is(fluid)) { - fluid1.tick(this, pos, iblockdata); + profilerFiller.pop(); +@@ -946,6 +1217,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (fluidState.is(fluid)) { + fluidState.tick(this, pos, blockState); } + // Paper start - rewrite chunk system + if ((++this.tickedBlocksOrFluids & 7L) != 0L) { + ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); + } + // Paper end - rewrite chunk system - ++ } -@@ -963,6 +1246,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (iblockdata.is(block)) { - iblockdata.tick(this, pos, this.random); + private void tickBlock(BlockPos pos, Block block) { +@@ -953,6 +1230,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (blockState.is(block)) { + blockState.tick(this, pos, this.random); } + // Paper start - rewrite chunk system + if ((++this.tickedBlocksOrFluids & 7L) != 0L) { + ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); + } + // Paper end - rewrite chunk system - ++ } -@@ -1041,6 +1329,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + public void tickNonPassenger(Entity entity) { +@@ -1007,6 +1290,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } - public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) { + public void save(@Nullable ProgressListener progress, boolean flush, boolean skipSave) { + // Paper start - add close param -+ this.save(progressListener, flush, savingDisabled, false); ++ this.save(progress, flush, skipSave, false); + } -+ public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled, boolean close) { ++ public void save(@Nullable ProgressListener progress, boolean flush, boolean skipSave, boolean close) { + // Paper end - add close param - ServerChunkCache chunkproviderserver = this.getChunkSource(); - - if (!savingDisabled) { -@@ -1054,14 +1347,19 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - progressListener.progressStage(Component.translatable("menu.savingChunks")); + ServerChunkCache chunkSource = this.getChunkSource(); + if (!skipSave) { + org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld())); // CraftBukkit +@@ -1019,13 +1307,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + progress.progressStage(Component.translatable("menu.savingChunks")); } -- chunkproviderserver.save(flush); +- chunkSource.save(flush); - if (flush) { - this.entityManager.saveAll(); - } else { - this.entityManager.autoSave(); -- } -+ if (!close) { chunkproviderserver.save(flush); } // Paper - add close param ++ if (!close) { chunkSource.save(flush); } // Paper - add close param + // Paper - rewrite chunk system - - } ++ } + // Paper start - add close param + if (close) { + try { -+ chunkproviderserver.close(!savingDisabled); ++ chunkSource.close(!skipSave); + } catch (IOException never) { + throw new RuntimeException(never); -+ } -+ } + } + } + // Paper end - add close param // CraftBukkit start - moved from MinecraftServer.saveChunks ServerLevel worldserver1 = this; -@@ -1201,7 +1499,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.removePlayerImmediately((ServerPlayer) entity, Entity.RemovalReason.DISCARDED); +@@ -1156,7 +1449,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.removePlayerImmediately((ServerPlayer)entity, Entity.RemovalReason.DISCARDED); } - this.entityManager.addNewEntity(player); @@ -27644,7 +27150,7 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 } // CraftBukkit start -@@ -1232,7 +1530,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1187,7 +1480,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } // CraftBukkit end @@ -27653,56 +27159,52 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 } } -@@ -1243,11 +1541,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1198,7 +1491,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public boolean tryAddFreshEntityWithPassengers(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { // CraftBukkit end -- Stream<UUID> stream = entity.getSelfAndPassengers().map(Entity::getUUID); // CraftBukkit - decompile error -- PersistentEntitySectionManager persistententitysectionmanager = this.entityManager; -- -- Objects.requireNonNull(this.entityManager); -- if (stream.anyMatch(persistententitysectionmanager::isLoaded)) { +- if (entity.getSelfAndPassengers().map(Entity::getUUID).anyMatch(this.entityManager::isLoaded)) { + if (entity.getSelfAndPassengers().map(Entity::getUUID).anyMatch(this.moonrise$getEntityLookup()::hasEntity)) { // Paper - rewrite chunk system return false; } else { this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit -@@ -1924,7 +2218,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1933,7 +2226,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } } -- bufferedwriter.write(String.format(Locale.ROOT, "entities: %s\n", this.entityManager.gatherStats())); -+ bufferedwriter.write(String.format(Locale.ROOT, "entities: %s\n", this.moonrise$getEntityLookup().getDebugInfo())); // Paper - rewrite chunk system - 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())); -@@ -1973,7 +2267,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - BufferedWriter bufferedwriter2 = Files.newBufferedWriter(path1); - - try { -- playerchunkmap.dumpChunks(bufferedwriter2); -+ //playerchunkmap.dumpChunks(bufferedwriter2); // Paper - rewrite chunk system - } catch (Throwable throwable4) { - if (bufferedwriter2 != null) { - try { -@@ -1994,7 +2288,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - BufferedWriter bufferedwriter3 = Files.newBufferedWriter(path2); - - try { -- this.entityManager.dumpSections(bufferedwriter3); -+ //this.entityManager.dumpSections(bufferedwriter3); // Paper - rewrite chunk system - } catch (Throwable throwable6) { - if (bufferedwriter3 != null) { - try { -@@ -2136,7 +2430,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +- bufferedWriter.write(String.format(Locale.ROOT, "entities: %s\n", this.entityManager.gatherStats())); ++ bufferedWriter.write(String.format(Locale.ROOT, "entities: %s\n", this.moonrise$getEntityLookup().getDebugInfo())); // Paper - rewrite chunk system + 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())); +@@ -1951,13 +2244,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + Path path1 = path.resolve("chunks.csv"); + + try (Writer bufferedWriter2 = Files.newBufferedWriter(path1)) { +- chunkMap.dumpChunks(bufferedWriter2); ++ //chunkMap.dumpChunks(bufferedWriter2); // Paper - rewrite chunk system + } - @VisibleForTesting - public String getWatchdogStats() { -- return String.format(Locale.ROOT, "players: %s, entities: %s [%s], block_entities: %d [%s], block_ticks: %d, fluid_ticks: %d, chunk_source: %s", this.players.size(), this.entityManager.gatherStats(), ServerLevel.getTypeCount(this.entityManager.getEntityGetter().getAll(), (entity) -> { -+ return String.format(Locale.ROOT, "players: %s, entities: %s [%s], block_entities: %d [%s], block_ticks: %d, fluid_ticks: %d, chunk_source: %s", this.players.size(), this.moonrise$getEntityLookup().getDebugInfo(), ServerLevel.getTypeCount(this.moonrise$getEntityLookup().getAll(), (entity) -> { // Paper - rewrite chunk system - 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()); - } -@@ -2166,15 +2460,25 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + Path path2 = path.resolve("entity_chunks.csv"); + + try (Writer bufferedWriter3 = Files.newBufferedWriter(path2)) { +- this.entityManager.dumpSections(bufferedWriter3); ++ //this.entityManager.dumpSections(bufferedWriter3); // Paper - rewrite chunk system + } + + Path path3 = path.resolve("entities.csv"); +@@ -2066,8 +2359,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + Locale.ROOT, + "players: %s, entities: %s [%s], block_entities: %d [%s], block_ticks: %d, fluid_ticks: %d, chunk_source: %s", + this.players.size(), +- this.entityManager.gatherStats(), +- getTypeCount(this.entityManager.getEntityGetter().getAll(), entity -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()), ++ this.moonrise$getEntityLookup().getDebugInfo(), // Paper - rewrite chunk system ++ getTypeCount(this.moonrise$getEntityLookup().getAll(), entity -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()), // Paper - rewrite chunk system + this.blockEntityTickers.size(), + getTypeCount(this.blockEntityTickers, TickingBlockEntity::getType), + this.getBlockTicks().count(), +@@ -2099,15 +2392,25 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public LevelEntityGetter<Entity> getEntities() { org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot @@ -27731,7 +27233,7 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 } public void startTickingChunk(LevelChunk chunk) { -@@ -2194,34 +2498,47 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2125,32 +2428,45 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public void close() throws IOException { super.close(); @@ -27741,10 +27243,8 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 @Override public String gatherChunkSourceStats() { - String s = this.chunkSource.gatherStats(); - -- return "Chunks[S] W: " + s + " E: " + this.entityManager.gatherStats(); -+ return "Chunks[S] W: " + s + " E: " + this.moonrise$getEntityLookup().getDebugInfo(); // Paper - rewrite chunk system +- return "Chunks[S] W: " + this.chunkSource.gatherStats() + " E: " + this.entityManager.gatherStats(); ++ return "Chunks[S] W: " + this.chunkSource.gatherStats() + " E: " + this.moonrise$getEntityLookup().getDebugInfo(); // Paper - rewrite chunk system } public boolean areEntitiesLoaded(long chunkPos) { @@ -27777,8 +27277,8 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 + // Paper end - rewrite chunk system } - public boolean isNaturalSpawningAllowed(ChunkPos pos) { -- return this.entityManager.canPositionTick(pos); + public boolean isNaturalSpawningAllowed(ChunkPos chunkPos) { +- return this.entityManager.canPositionTick(chunkPos); + // Paper start - rewrite chunk system + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos)); + return chunkHolder != null && chunkHolder.isEntityTickingReady(); @@ -27786,29 +27286,29 @@ index 6c71ef3c7430623900a7021f853d2bb514273e4d..cf692267c6376ed8484478dc90f4f905 } @Override -@@ -2277,7 +2594,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - CrashReportCategory crashreportsystemdetails = super.fillReportDetails(report); - - crashreportsystemdetails.setDetail("Loaded entity count", () -> { -- return String.valueOf(this.entityManager.count()); -+ return String.valueOf(this.moonrise$getEntityLookup().getEntityCount()); // Paper - rewrite chunk system - }); - return crashreportsystemdetails; +@@ -2204,7 +2520,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + @Override + public CrashReportCategory fillReportDetails(CrashReport report) { + CrashReportCategory crashReportCategory = super.fillReportDetails(report); +- crashReportCategory.setDetail("Loaded entity count", () -> String.valueOf(this.entityManager.count())); ++ crashReportCategory.setDetail("Loaded entity count", () -> String.valueOf(this.moonrise$getEntityLookup().getEntityCount())); // Paper - rewrite chunk system + return crashReportCategory; } + diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index f6e3073e1f1ff99f6917d84974a18e3e756fa9ea..ba873bcc183f9b3f64ba39be08cb88a95ff52b0e 100644 +index 940509d1f31aedf20b8f5b9192c34ad004875728..b455e0e0fea949bee1953324ae530c19405c5d3b 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -217,7 +217,7 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - import org.bukkit.inventory.MainHand; - // CraftBukkit end - --public class ServerPlayer extends net.minecraft.world.entity.player.Player { -+public class ServerPlayer extends net.minecraft.world.entity.player.Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system +@@ -178,7 +178,7 @@ import net.minecraft.world.scores.Team; + import net.minecraft.world.scores.criteria.ObjectiveCriteria; + import org.slf4j.Logger; +-public class ServerPlayer extends Player { ++public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system private static final Logger LOGGER = LogUtils.getLogger(); private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32; -@@ -322,6 +322,36 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { + private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10; +@@ -387,6 +387,36 @@ public class ServerPlayer extends Player { public @Nullable String clientBrandName = null; // Paper - Brand support public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event @@ -27842,11 +27342,11 @@ index f6e3073e1f1ff99f6917d84974a18e3e756fa9ea..ba873bcc183f9b3f64ba39be08cb88a9 + } + // Paper end - rewrite chunk system + - public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { - super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); - this.chatVisibility = ChatVisiblity.FULL; + public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) { + super(level, level.getSharedSpawnPos(), level.getSharedSpawnAngle(), gameProfile); + this.textFilter = server.createTextFilterForPlayer(this); diff --git a/net/minecraft/server/level/ThreadedLevelLightEngine.java b/net/minecraft/server/level/ThreadedLevelLightEngine.java -index 39d34f3728ae8d845d1bffc09f3ab8b64eb4d48b..3e82adf061bd0ec0100ca4d16ec9b157bddf99a7 100644 +index 11a264ef2f43c2b00741397c9c9ea5393afad6ab..5c9ac44a3b4bc8e047feaf61a94eb163761498a2 100644 --- a/net/minecraft/server/level/ThreadedLevelLightEngine.java +++ b/net/minecraft/server/level/ThreadedLevelLightEngine.java @@ -22,23 +22,134 @@ import net.minecraft.world.level.chunk.LightChunkGetter; @@ -27981,17 +27481,17 @@ index 39d34f3728ae8d845d1bffc09f3ab8b64eb4d48b..3e82adf061bd0ec0100ca4d16ec9b157 + // Paper end - rewrite chunk system public ThreadedLevelLightEngine( - LightChunkGetter chunkProvider, ChunkMap chunkLoadingManager, boolean hasBlockLight, ConsecutiveExecutor processor, ChunkTaskDispatcher executor + LightChunkGetter lightChunkGetter, ChunkMap chunkMap, boolean skyLight, ConsecutiveExecutor consecutiveExecutor, ChunkTaskDispatcher taskDispatcher ) { - super(chunkProvider, true, hasBlockLight); - this.chunkMap = chunkLoadingManager; -- this.taskDispatcher = executor; -- this.consecutiveExecutor = processor; -+ // Paper - rewrite chunk sytem + super(lightChunkGetter, true, skyLight); + this.chunkMap = chunkMap; +- this.taskDispatcher = taskDispatcher; +- this.consecutiveExecutor = consecutiveExecutor; ++ // Paper - rewrite chunk system } @Override -@@ -52,164 +163,73 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl +@@ -52,163 +163,73 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl @Override public void checkBlock(BlockPos pos) { @@ -28010,35 +27510,35 @@ index 39d34f3728ae8d845d1bffc09f3ab8b64eb4d48b..3e82adf061bd0ec0100ca4d16ec9b157 + // Paper end - rewrite chunk system } - protected void updateChunkStatus(ChunkPos pos) { -- this.addTask(pos.x, pos.z, () -> 0, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { -- super.retainData(pos, false); -- super.setLightEnabled(pos, false); + protected void updateChunkStatus(ChunkPos chunkPos) { +- this.addTask(chunkPos.x, chunkPos.z, () -> 0, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { +- super.retainData(chunkPos, false); +- super.setLightEnabled(chunkPos, false); - -- for (int i = this.getMinLightSection(); i < this.getMaxLightSection(); i++) { -- super.queueSectionData(LightLayer.BLOCK, SectionPos.of(pos, i), null); -- super.queueSectionData(LightLayer.SKY, SectionPos.of(pos, i), null); +- for (int lightSection = this.getMinLightSection(); lightSection < this.getMaxLightSection(); lightSection++) { +- super.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, lightSection), null); +- super.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, lightSection), null); - } - -- for (int j = this.levelHeightAccessor.getMinSectionY(); j <= this.levelHeightAccessor.getMaxSectionY(); j++) { -- super.updateSectionStatus(SectionPos.of(pos, j), true); +- for (int lightSection = this.levelHeightAccessor.getMinSectionY(); lightSection <= this.levelHeightAccessor.getMaxSectionY(); lightSection++) { +- super.updateSectionStatus(SectionPos.of(chunkPos, lightSection), true); - } -- }, () -> "updateChunkStatus " + pos + " true")); +- }, () -> "updateChunkStatus " + chunkPos + " true")); + // Paper - rewrite chunk system } @Override - public void updateSectionStatus(SectionPos pos, boolean notReady) { + public void updateSectionStatus(SectionPos pos, boolean isEmpty) { - this.addTask( - pos.x(), - pos.z(), - () -> 0, - ThreadedLevelLightEngine.TaskType.PRE_UPDATE, -- Util.name(() -> super.updateSectionStatus(pos, notReady), () -> "updateSectionStatus " + pos + " " + notReady) +- Util.name(() -> super.updateSectionStatus(pos, isEmpty), () -> "updateSectionStatus " + pos + " " + isEmpty) - ); + // Paper start - rewrite chunk system + this.queueTaskForSection(pos.getX(), pos.getY(), pos.getZ(), () -> { -+ return ThreadedLevelLightEngine.this.starlight$getLightEngine().sectionChange(pos, notReady); ++ return ThreadedLevelLightEngine.this.starlight$getLightEngine().sectionChange(pos, isEmpty); + }); + // Paper end - rewrite chunk system } @@ -28055,84 +27555,84 @@ index 39d34f3728ae8d845d1bffc09f3ab8b64eb4d48b..3e82adf061bd0ec0100ca4d16ec9b157 } @Override - public void setLightEnabled(ChunkPos pos, boolean retainData) { + public void setLightEnabled(ChunkPos chunkPos, boolean lightEnabled) { - this.addTask( -- pos.x, -- pos.z, +- chunkPos.x, +- chunkPos.z, - ThreadedLevelLightEngine.TaskType.PRE_UPDATE, -- Util.name(() -> super.setLightEnabled(pos, retainData), () -> "enableLight " + pos + " " + retainData) +- Util.name(() -> super.setLightEnabled(chunkPos, lightEnabled), () -> "enableLight " + chunkPos + " " + lightEnabled) - ); + // Paper start - rewrite chunk system } @Override - public void queueSectionData(LightLayer lightType, SectionPos pos, @Nullable DataLayer nibbles) { + public void queueSectionData(LightLayer lightLayer, SectionPos sectionPos, @Nullable DataLayer dataLayer) { - this.addTask( -- pos.x(), -- pos.z(), +- sectionPos.x(), +- sectionPos.z(), - () -> 0, - ThreadedLevelLightEngine.TaskType.PRE_UPDATE, -- Util.name(() -> super.queueSectionData(lightType, pos, nibbles), () -> "queueData " + pos) +- Util.name(() -> super.queueSectionData(lightLayer, sectionPos, dataLayer), () -> "queueData " + sectionPos) - ); + // Paper start - rewrite chunk system } - private void addTask(int x, int z, ThreadedLevelLightEngine.TaskType stage, Runnable task) { -- this.addTask(x, z, this.chunkMap.getChunkQueueLevel(ChunkPos.asLong(x, z)), stage, task); + private void addTask(int chunkX, int chunkZ, ThreadedLevelLightEngine.TaskType type, Runnable task) { +- this.addTask(chunkX, chunkZ, this.chunkMap.getChunkQueueLevel(ChunkPos.asLong(chunkX, chunkZ)), type, task); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private void addTask(int x, int z, IntSupplier completedLevelSupplier, ThreadedLevelLightEngine.TaskType stage, Runnable task) { + private void addTask(int chunkX, int chunkZ, IntSupplier queueLevelSupplier, ThreadedLevelLightEngine.TaskType type, Runnable task) { - this.taskDispatcher.submit(() -> { -- this.lightTasks.add(Pair.of(stage, task)); +- this.lightTasks.add(Pair.of(type, task)); - if (this.lightTasks.size() >= 1000) { - this.runUpdate(); - } -- }, ChunkPos.asLong(x, z), completedLevelSupplier); +- }, ChunkPos.asLong(chunkX, chunkZ), queueLevelSupplier); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @Override - public void retainData(ChunkPos pos, boolean retainData) { + public void retainData(ChunkPos pos, boolean retain) { - this.addTask( -- pos.x, pos.z, () -> 0, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> super.retainData(pos, retainData), () -> "retainData " + pos) +- pos.x, pos.z, () -> 0, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> super.retainData(pos, retain), () -> "retainData " + pos) - ); + // Paper start - rewrite chunk system } - public CompletableFuture<ChunkAccess> initializeLight(ChunkAccess chunk, boolean bl) { -- ChunkPos chunkPos = chunk.getPos(); -- this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { -- LevelChunkSection[] levelChunkSections = chunk.getSections(); + public CompletableFuture<ChunkAccess> initializeLight(ChunkAccess chunk, boolean lightEnabled) { +- ChunkPos pos = chunk.getPos(); +- this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { +- LevelChunkSection[] sections = chunk.getSections(); - - for (int i = 0; i < chunk.getSectionsCount(); i++) { -- LevelChunkSection levelChunkSection = levelChunkSections[i]; +- LevelChunkSection levelChunkSection = sections[i]; - if (!levelChunkSection.hasOnlyAir()) { -- int j = this.levelHeightAccessor.getSectionYFromSectionIndex(i); -- super.updateSectionStatus(SectionPos.of(chunkPos, j), false); +- int sectionYFromSectionIndex = this.levelHeightAccessor.getSectionYFromSectionIndex(i); +- super.updateSectionStatus(SectionPos.of(pos, sectionYFromSectionIndex), false); - } - } -- }, () -> "initializeLight: " + chunkPos)); +- }, () -> "initializeLight: " + pos)); - return CompletableFuture.supplyAsync(() -> { -- super.setLightEnabled(chunkPos, bl); -- super.retainData(chunkPos, false); +- super.setLightEnabled(pos, lightEnabled); +- super.retainData(pos, false); - return chunk; -- }, task -> this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, task)); +- }, task -> this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, task)); + return CompletableFuture.completedFuture(chunk); // Paper start - rewrite chunk system } - public CompletableFuture<ChunkAccess> lightChunk(ChunkAccess chunk, boolean excludeBlocks) { -- ChunkPos chunkPos = chunk.getPos(); + public CompletableFuture<ChunkAccess> lightChunk(ChunkAccess chunk, boolean isLighted) { +- ChunkPos pos = chunk.getPos(); - chunk.setLightCorrect(false); -- this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { -- if (!excludeBlocks) { -- super.propagateLightSources(chunkPos); +- this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> { +- if (!isLighted) { +- super.propagateLightSources(pos); - } -- }, () -> "lightChunk " + chunkPos + " " + excludeBlocks)); +- }, () -> "lightChunk " + pos + " " + isLighted)); - return CompletableFuture.supplyAsync(() -> { - chunk.setLightCorrect(true); - return chunk; -- }, task -> this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, task)); +- }, task -> this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, task)); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -28147,24 +27647,24 @@ index 39d34f3728ae8d845d1bffc09f3ab8b64eb4d48b..3e82adf061bd0ec0100ca4d16ec9b157 } private void runUpdate() { -- int i = Math.min(this.lightTasks.size(), 1000); +- int min = Math.min(this.lightTasks.size(), 1000); - ObjectListIterator<Pair<ThreadedLevelLightEngine.TaskType, Runnable>> objectListIterator = this.lightTasks.iterator(); - -- int j; -- for (j = 0; objectListIterator.hasNext() && j < i; j++) { +- int i; +- for (i = 0; objectListIterator.hasNext() && i < min; i++) { - Pair<ThreadedLevelLightEngine.TaskType, Runnable> pair = objectListIterator.next(); - if (pair.getFirst() == ThreadedLevelLightEngine.TaskType.PRE_UPDATE) { - pair.getSecond().run(); - } - } - -- objectListIterator.back(j); +- objectListIterator.back(i); - super.runLightUpdates(); - -- for (int var5 = 0; objectListIterator.hasNext() && var5 < i; var5++) { -- Pair<ThreadedLevelLightEngine.TaskType, Runnable> pair2 = objectListIterator.next(); -- if (pair2.getFirst() == ThreadedLevelLightEngine.TaskType.POST_UPDATE) { -- pair2.getSecond().run(); +- for (int var5 = 0; objectListIterator.hasNext() && var5 < min; var5++) { +- Pair<ThreadedLevelLightEngine.TaskType, Runnable> pair = objectListIterator.next(); +- if (pair.getFirst() == ThreadedLevelLightEngine.TaskType.POST_UPDATE) { +- pair.getSecond().run(); - } - - objectListIterator.remove(); @@ -28173,14 +27673,13 @@ index 39d34f3728ae8d845d1bffc09f3ab8b64eb4d48b..3e82adf061bd0ec0100ca4d16ec9b157 } public CompletableFuture<?> waitForPendingTasks(int x, int z) { -- return CompletableFuture.runAsync(() -> { -- }, callback -> this.addTask(x, z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, callback)); +- return CompletableFuture.runAsync(() -> {}, task -> this.addTask(x, z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, task)); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } static enum TaskType { diff --git a/net/minecraft/server/level/Ticket.java b/net/minecraft/server/level/Ticket.java -index eba83b085435150e5954fd5d41dda9ce1d0601ad..daf543b51d8875b374688957ae4bc466f5512bcd 100644 +index e574f217386d677400b4c093d50261045df06d5c..ed8a3d5bd25909ee4648b1ec2ee66878198a1d8a 100644 --- a/net/minecraft/server/level/Ticket.java +++ b/net/minecraft/server/level/Ticket.java @@ -2,13 +2,25 @@ package net.minecraft.server.level; @@ -28196,7 +27695,7 @@ index eba83b085435150e5954fd5d41dda9ce1d0601ad..daf543b51d8875b374688957ae4bc466 + // Paper start - rewrite chunk system + private long removeDelay; -- protected Ticket(TicketType<T> type, int level, T argument) { +- protected Ticket(TicketType<T> type, int ticketLevel, T key) { + @Override + public final long moonrise$getRemoveDelay() { + return this.removeDelay; @@ -28206,12 +27705,12 @@ index eba83b085435150e5954fd5d41dda9ce1d0601ad..daf543b51d8875b374688957ae4bc466 + public final void moonrise$setRemoveDelay(final long removeDelay) { + this.removeDelay = removeDelay; + } -+ // Paper end - rewerite chunk system ++ // Paper end - rewrite chunk system + -+ public Ticket(TicketType<T> type, int level, T argument) { // Paper - public ++ public Ticket(TicketType<T> type, int ticketLevel, T key) { // Paper - public this.type = type; - this.ticketLevel = level; - this.key = argument; + this.ticketLevel = ticketLevel; + this.key = key; @@ -41,7 +53,7 @@ public final class Ticket<T> implements Comparable<Ticket<?>> { @Override @@ -28224,22 +27723,22 @@ index eba83b085435150e5954fd5d41dda9ce1d0601ad..daf543b51d8875b374688957ae4bc466 @@ -53,11 +65,10 @@ public final class Ticket<T> implements Comparable<Ticket<?>> { } - protected void setCreatedTick(long tickCreated) { -- this.createdTick = tickCreated; + protected void setCreatedTick(long timestamp) { +- this.createdTick = timestamp; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - protected boolean timedOut(long currentTick) { -- long l = this.type.timeout(); -- return l != 0L && currentTick - this.createdTick > l; + protected boolean timedOut(long currentTime) { +- long timeout = this.type.timeout(); +- return timeout != 0L && currentTime - this.createdTick > timeout; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } } diff --git a/net/minecraft/server/level/WorldGenRegion.java b/net/minecraft/server/level/WorldGenRegion.java -index b7d29389a357f142237cecd75f8ca91cf1eb6b5b..e4b0dc3121101d54394a0c3a413dabf8103b2ea6 100644 +index 4eb040006f5d41b47e5ac9df5d9f19c4315d6343..7fa41dea184b01891f45d8e404bc1cba19cf1bcf 100644 --- a/net/minecraft/server/level/WorldGenRegion.java +++ b/net/minecraft/server/level/WorldGenRegion.java -@@ -85,6 +85,36 @@ public class WorldGenRegion implements WorldGenLevel { +@@ -78,6 +78,36 @@ public class WorldGenRegion implements WorldGenLevel { private final AtomicLong subTickCount = new AtomicLong(); private static final ResourceLocation WORLDGEN_REGION_RANDOM = ResourceLocation.withDefaultNamespace("worldgen_region_random"); @@ -28273,33 +27772,33 @@ index b7d29389a357f142237cecd75f8ca91cf1eb6b5b..e4b0dc3121101d54394a0c3a413dabf8 + } + // Paper end - rewrite chunk system + - public WorldGenRegion(ServerLevel world, StaticCache2D<GenerationChunkHolder> chunks, ChunkStep generationStep, ChunkAccess centerPos) { - this.generatingStep = generationStep; - this.cache = chunks; + public WorldGenRegion(ServerLevel level, StaticCache2D<GenerationChunkHolder> cache, ChunkStep generatingStep, ChunkAccess center) { + this.generatingStep = generatingStep; + this.cache = cache; diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index c68040a59fa8aa9b8b9f1e0b4fdded565ea592d9..7913c41aac1f9dd53a2b49da2a17fd894bcb6b3a 100644 +index d227714de0fe13544779fae6cf0e9ff6af5469c7..4722230e74e0778ebdb2cfd383764b34004e9568 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -1426,7 +1426,7 @@ public abstract class PlayerList { +@@ -1318,7 +1318,7 @@ public abstract class PlayerList { public void setViewDistance(int viewDistance) { this.viewDistance = viewDistance; - this.broadcastAll(new ClientboundSetChunkCacheRadiusPacket(viewDistance)); + //this.broadcastAll(new ClientboundSetChunkCacheRadiusPacket(viewDistance)); // Paper - rewrite chunk system - Iterator iterator = this.server.getAllLevels().iterator(); - while (iterator.hasNext()) { -@@ -1441,7 +1441,7 @@ public abstract class PlayerList { + for (ServerLevel serverLevel : this.server.getAllLevels()) { + if (serverLevel != null) { +@@ -1329,7 +1329,7 @@ public abstract class PlayerList { public void setSimulationDistance(int simulationDistance) { this.simulationDistance = simulationDistance; - this.broadcastAll(new ClientboundSetSimulationDistancePacket(simulationDistance)); -+ //this.broadcastAll(new ClientboundSetSimulationDistancePacket(simulationDistance)); // Paper - rewrite chunk system - Iterator iterator = this.server.getAllLevels().iterator(); ++ //this.broadcastAll(new ClientboundSetSimulationDistancePacket(simulationDistance)); // Paper - rewrite chunk system - while (iterator.hasNext()) { + for (ServerLevel serverLevel : this.server.getAllLevels()) { + if (serverLevel != null) { diff --git a/net/minecraft/util/BitStorage.java b/net/minecraft/util/BitStorage.java -index 68648c5a5e3ff079f832092af0f2f801c42d1ede..e4e153cb8899e70273aa150b8ea26907cf68b15c 100644 +index 32fe9b22e1d3a422dd80c64d61156dbc7241ba20..02502d50f0255f5bbcc0ecb965abb48cc1a112da 100644 --- a/net/minecraft/util/BitStorage.java +++ b/net/minecraft/util/BitStorage.java @@ -2,7 +2,7 @@ package net.minecraft.util; @@ -28312,7 +27811,7 @@ index 68648c5a5e3ff079f832092af0f2f801c42d1ede..e4e153cb8899e70273aa150b8ea26907 void set(int index, int value); @@ -20,4 +20,22 @@ public interface BitStorage { - void unpack(int[] out); + void unpack(int[] array); BitStorage copy(); + @@ -28335,7 +27834,7 @@ index 68648c5a5e3ff079f832092af0f2f801c42d1ede..e4e153cb8899e70273aa150b8ea26907 + // Paper end - block counting } diff --git a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java -index 61dee55417bc802e25b9ba2f271d32d8c12844a9..a8a260a3caaa8e5004069b833ecc8b17b2fc8db5 100644 +index 4a7c83c56dfbff59af71c3cd2fa4205c9a22bdc7..f28fbf81a417a678726d3f77b3999054676d522e 100644 --- a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java +++ b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java @@ -7,7 +7,7 @@ import java.util.Iterator; @@ -28376,9 +27875,9 @@ index 61dee55417bc802e25b9ba2f271d32d8c12844a9..a8a260a3caaa8e5004069b833ecc8b17 + // Paper end - optimise palette reads } - public void addMapping(K value, int id) { + public void addMapping(K object, int intKey) { diff --git a/net/minecraft/util/SimpleBitStorage.java b/net/minecraft/util/SimpleBitStorage.java -index 9f438d9c6eb05e43d24e4af68188a3d4c46a938c..d99ec470b4653beab630999a5b2c1a6428b20c38 100644 +index 6fb3a3f167d8cbaa78135af0c180b592661e2c1d..e6306a68c8652d4c5d22d5ecb1416f5f931f76ee 100644 --- a/net/minecraft/util/SimpleBitStorage.java +++ b/net/minecraft/util/SimpleBitStorage.java @@ -208,6 +208,20 @@ public class SimpleBitStorage implements BitStorage { @@ -28399,12 +27898,12 @@ index 9f438d9c6eb05e43d24e4af68188a3d4c46a938c..d99ec470b4653beab630999a5b2c1a64 + private final int mulBits; + // Paper end - optimise bitstorage read/write operations + - public SimpleBitStorage(int elementBits, int size, int[] data) { - this(elementBits, size); + public SimpleBitStorage(int bits, int size, int[] data) { + this(bits, size); int i = 0; @@ -261,6 +275,13 @@ public class SimpleBitStorage implements BitStorage { } else { - this.data = new long[j]; + this.data = new long[i1]; } + // Paper start - optimise bitstorage read/write operations + this.magic = BETTER_MAGIC[this.bits]; @@ -28416,16 +27915,16 @@ index 9f438d9c6eb05e43d24e4af68188a3d4c46a938c..d99ec470b4653beab630999a5b2c1a64 } private int cellIndex(int index) { -@@ -273,31 +294,54 @@ public class SimpleBitStorage implements BitStorage { +@@ -269,28 +290,51 @@ public class SimpleBitStorage implements BitStorage { + + @Override public final int getAndSet(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage - //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage - //Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper - Perf: Optimize SimpleBitStorage - int i = this.cellIndex(index); - long l = this.data[i]; -- int j = (index - i * this.valuesPerLong) * this.bits; -- int k = (int)(l >> j & this.mask); -- this.data[i] = l & ~(this.mask << j) | ((long)value & this.mask) << j; -- return k; +- int i1 = (index - i * this.valuesPerLong) * this.bits; +- int i2 = (int)(l >> i1 & this.mask); +- this.data[i] = l & ~(this.mask << i1) | (value & this.mask) << i1; +- return i2; + // Paper start - optimise bitstorage read/write operations + final int full = this.magic * index; // 20 bits of magic + 12 bits of index = barely int + final int divQ = full >>> 20; @@ -28446,12 +27945,10 @@ index 9f438d9c6eb05e43d24e4af68188a3d4c46a938c..d99ec470b4653beab630999a5b2c1a64 @Override public final void set(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage - //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage - //Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper - Perf: Optimize SimpleBitStorage - int i = this.cellIndex(index); - long l = this.data[i]; -- int j = (index - i * this.valuesPerLong) * this.bits; -- this.data[i] = l & ~(this.mask << j) | ((long)value & this.mask) << j; +- int i1 = (index - i * this.valuesPerLong) * this.bits; +- this.data[i] = l & ~(this.mask << i1) | (value & this.mask) << i1; + // Paper start - optimise bitstorage read/write operations + final int full = this.magic * index; // 20 bits of magic + 12 bits of index = barely int + final int divQ = full >>> 20; @@ -28470,11 +27967,10 @@ index 9f438d9c6eb05e43d24e4af68188a3d4c46a938c..d99ec470b4653beab630999a5b2c1a64 @Override public final int get(int index) { // Paper - Perf: Optimize SimpleBitStorage - //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage - int i = this.cellIndex(index); - long l = this.data[i]; -- int j = (index - i * this.valuesPerLong) * this.bits; -- return (int)(l >> j & this.mask); +- int i1 = (index - i * this.valuesPerLong) * this.bits; +- return (int)(l >> i1 & this.mask); + // Paper start - optimise bitstorage read/write operations + final int full = this.magic * index; // 20 bits of magic + 12 bits of index = barely int + final int divQ = full >>> 20; @@ -28485,7 +27981,7 @@ index 9f438d9c6eb05e43d24e4af68188a3d4c46a938c..d99ec470b4653beab630999a5b2c1a64 } @Override -@@ -362,6 +406,67 @@ public class SimpleBitStorage implements BitStorage { +@@ -355,6 +399,67 @@ public class SimpleBitStorage implements BitStorage { return new SimpleBitStorage(this.bits, this.size, (long[])this.data.clone()); } @@ -28554,7 +28050,7 @@ index 9f438d9c6eb05e43d24e4af68188a3d4c46a938c..d99ec470b4653beab630999a5b2c1a64 InitializationException(String message) { super(message); diff --git a/net/minecraft/util/SortedArraySet.java b/net/minecraft/util/SortedArraySet.java -index ea72dcb064a35bc6245bc5c94d592efedd8faf41..87ee8e51dfa7657ed7d83fcbceef48bf857043e1 100644 +index 2c6b35b86eed9002016b8228c3195f8033d219ca..339b19e88567be382e550ed54477fabd58d51faa 100644 --- a/net/minecraft/util/SortedArraySet.java +++ b/net/minecraft/util/SortedArraySet.java @@ -8,12 +8,89 @@ import java.util.Iterator; @@ -28649,7 +28145,7 @@ index ea72dcb064a35bc6245bc5c94d592efedd8faf41..87ee8e51dfa7657ed7d83fcbceef48bf this.comparator = comparator; if (initialCapacity < 0) { diff --git a/net/minecraft/util/ZeroBitStorage.java b/net/minecraft/util/ZeroBitStorage.java -index 50040c497a819cd1229042ab3cb057d34a32cacc..1f9c436a632e4f110be61cf76fcfc3b7eb80334e 100644 +index 8cc5c0716392ba06501542ff5cbe71ee43979e5d..09fd99c9cbd23b5f3c899bfb00c9b89651948ed8 100644 --- a/net/minecraft/util/ZeroBitStorage.java +++ b/net/minecraft/util/ZeroBitStorage.java @@ -62,4 +62,22 @@ public class ZeroBitStorage implements BitStorage { @@ -28676,19 +28172,19 @@ index 50040c497a819cd1229042ab3cb057d34a32cacc..1f9c436a632e4f110be61cf76fcfc3b7 + // Paper end - block counting } diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3b5d9b6ce 100644 +index 5a67aa9f1fe103e5622ed6fa93bc4bc25ddbb688..77d2c86c8bb20e96e0eed32c430ef0c1d122428b 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -176,7 +176,7 @@ import org.bukkit.event.player.PlayerTeleportEvent; - import org.bukkit.plugin.PluginManager; - // CraftBukkit end +@@ -135,7 +135,7 @@ import net.minecraft.world.scores.ScoreHolder; + import net.minecraft.world.scores.Team; + import org.slf4j.Logger; -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; -@@ -187,7 +187,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -146,7 +146,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess // Paper start - Share random for entities to make them more random public static RandomSource SHARED_RANDOM = new RandomRandomSource(); @@ -28707,7 +28203,7 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 private boolean locked = false; @Override -@@ -200,61 +210,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -159,61 +169,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } @@ -28770,7 +28266,7 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 } // Paper end - Share random for entities to make them more random public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason -@@ -462,6 +418,156 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -425,6 +381,156 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return this.dimensions.makeBoundingBox(x, y, z); } // Paper end @@ -28925,26 +28421,24 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 + } + // Paper end - optimise entity tracker - public Entity(EntityType<?> type, Level world) { - this.id = Entity.ENTITY_COUNTER.incrementAndGet(); -@@ -1387,41 +1493,76 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public Entity(EntityType<?> entityType, Level level) { + this.type = entityType; +@@ -1286,34 +1392,76 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } - private Vec3 collide(Vec3 movement) { -- AABB axisalignedbb = this.getBoundingBox(); -- List<VoxelShape> list = this.level().getEntityCollisions(this, axisalignedbb.expandTowards(movement)); -- Vec3 vec3d1 = movement.lengthSqr() == 0.0D ? movement : Entity.collideBoundingBox(this, movement, axisalignedbb, this.level(), list); -- boolean flag = movement.x != vec3d1.x; -- boolean flag1 = movement.y != vec3d1.y; -- boolean flag2 = movement.z != vec3d1.z; -- boolean flag3 = flag1 && movement.y < 0.0D; -- + private Vec3 collide(Vec3 vec) { +- AABB boundingBox = this.getBoundingBox(); +- List<VoxelShape> entityCollisions = this.level().getEntityCollisions(this, boundingBox.expandTowards(vec)); +- Vec3 vec3 = vec.lengthSqr() == 0.0 ? vec : collideBoundingBox(this, vec, boundingBox, this.level(), entityCollisions); +- boolean flag = vec.x != vec3.x; +- boolean flag1 = vec.y != vec3.y; +- boolean flag2 = vec.z != vec3.z; +- boolean flag3 = flag1 && vec.y < 0.0; - if (this.maxUpStep() > 0.0F && (flag3 || this.onGround()) && (flag || flag2)) { -- AABB axisalignedbb1 = flag3 ? axisalignedbb.move(0.0D, vec3d1.y, 0.0D) : axisalignedbb; -- AABB axisalignedbb2 = axisalignedbb1.expandTowards(movement.x, (double) this.maxUpStep(), movement.z); -- +- AABB aabb = flag3 ? boundingBox.move(0.0, vec3.y, 0.0) : boundingBox; +- AABB aabb1 = aabb.expandTowards(vec.x, this.maxUpStep(), vec.z); - if (!flag3) { -- axisalignedbb2 = axisalignedbb2.expandTowards(0.0D, -9.999999747378752E-6D, 0.0D); +- aabb1 = aabb1.expandTowards(0.0, -1.0E-5F, 0.0); - } + // Paper start - optimise collisions + final boolean xZero = movement.x == 0.0; @@ -28953,17 +28447,21 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 + if (xZero & yZero & zZero) { + return movement; + } -+ + +- List<VoxelShape> list = collectColliders(this, this.level, entityCollisions, aabb1); +- float f = (float)vec3.y; +- float[] floats = collectCandidateStepUpHeights(aabb, list, this.maxUpStep(), f); + final AABB currentBox = this.getBoundingBox(); -+ + +- for (float f1 : floats) { +- Vec3 vec31 = collideWithShapes(new Vec3(vec.x, f1, vec.z), aabb, list); +- if (vec31.horizontalDistanceSqr() > vec3.horizontalDistanceSqr()) { +- double d = boundingBox.minY - aabb.minY; +- return vec31.add(0.0, -d, 0.0); +- } + final List<VoxelShape> potentialCollisionsVoxel = new ArrayList<>(); + final List<AABB> potentialCollisionsBB = new ArrayList<>(); - -- List<VoxelShape> list1 = Entity.collectColliders(this, this.level, list, axisalignedbb2); -- float f = (float) vec3d1.y; -- float[] afloat = Entity.collectCandidateStepUpHeights(axisalignedbb1, list1, this.maxUpStep(), f); -- float[] afloat1 = afloat; -- int i = afloat.length; ++ + final AABB initialCollisionBox; + if (xZero & zZero) { + // note: xZero & zZero -> collision on x/z == 0 -> no step height calculation @@ -28973,26 +28471,19 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 + } else { + initialCollisionBox = currentBox.expandTowards(movement); + } - -- for (int j = 0; j < i; ++j) { -- float f1 = afloat1[j]; -- Vec3 vec3d2 = Entity.collideWithShapes(new Vec3(movement.x, (double) f1, movement.z), axisalignedbb1, list1); ++ + final List<AABB> entityAABBs = new ArrayList<>(); + ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getEntityHardCollisions( + this.level, (Entity)(Object)this, initialCollisionBox, entityAABBs, 0, null + ); - -- if (vec3d2.horizontalDistanceSqr() > vec3d1.horizontalDistanceSqr()) { -- double d0 = axisalignedbb.minY - axisalignedbb1.minY; ++ + ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisionsForBlocksOrWorldBorder( + this.level, (Entity)(Object)this, initialCollisionBox, potentialCollisionsVoxel, potentialCollisionsBB, + ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER, null + ); + potentialCollisionsBB.addAll(entityAABBs); + final Vec3 collided = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currentBox, potentialCollisionsVoxel, potentialCollisionsBB); - -- return vec3d2.add(0.0D, -d0, 0.0D); -- } ++ + final boolean collidedX = collided.x != movement.x; + final boolean collidedY = collided.y != movement.y; + final boolean collidedZ = collided.z != movement.z; @@ -29026,13 +28517,13 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 } } -- return vec3d1; +- return vec3; + return collided; + // Paper end - optimise collisions } - private static float[] collectCandidateStepUpHeights(AABB collisionBox, List<VoxelShape> collisions, float f, float stepHeight) { -@@ -2821,18 +2962,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + private static float[] collectCandidateStepUpHeights(AABB box, List<VoxelShape> colliders, float deltaY, float maxUpStep) { +@@ -2622,23 +2770,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public boolean isInWall() { @@ -29041,20 +28532,25 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 return false; - } else { - float f = this.dimensions.width() * 0.8F; -- AABB axisalignedbb = AABB.ofSize(this.getEyePosition(), (double) f, 1.0E-6D, (double) f); +- AABB aabb = AABB.ofSize(this.getEyePosition(), f, 1.0E-6, f); +- return BlockPos.betweenClosedStream(aabb) +- .anyMatch( +- pos -> { +- BlockState blockState = this.level().getBlockState(pos); +- return !blockState.isAir() +- && blockState.isSuffocating(this.level(), pos) +- && Shapes.joinIsNotEmpty( +- blockState.getCollisionShape(this.level(), pos).move(pos.getX(), pos.getY(), pos.getZ()), Shapes.create(aabb), BooleanOp.AND +- ); + } - -- return BlockPos.betweenClosedStream(axisalignedbb).anyMatch((blockposition) -> { -- BlockState iblockdata = this.level().getBlockState(blockposition); ++ + final double reducedWith = (double)(this.dimensions.width() * 0.8F); + final AABB boundingBox = AABB.ofSize(this.getEyePosition(), reducedWith, 1.0E-6D, reducedWith); + final Level world = this.level; - -- 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(boundingBox)) { + return false; - } ++ } + + final int minBlockX = Mth.floor(boundingBox.minX); + final int minBlockY = Mth.floor(boundingBox.minY); @@ -29084,7 +28580,8 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 + final int sectionIdx = currChunkY - minSection; + if (sectionIdx < 0 || sectionIdx >= sections.length) { + continue; -+ } + } +- ); + final net.minecraft.world.level.chunk.LevelChunkSection section = sections[sectionIdx]; + if (section.hasOnlyAir()) { + // empty @@ -29143,14 +28640,14 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 + } + } + } -+ } + } + + return false; + // Paper end - optimise collisions } public InteractionResult interact(Player player, InteractionHand hand) { -@@ -4310,14 +4543,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4063,15 +4298,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public Iterable<Entity> getIndirectPassengers() { @@ -29167,55 +28664,53 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 + return ret; } - return indirectPassengers.build(); +- // Paper end - Optimize indirect passenger iteration + + collectIndirectPassengers(ret, this.passengers); + + return ret; + // Paper end - optimise entity tracker } - private Iterable<Entity> getIndirectPassengers_old() { - // Paper end - Optimize indirect passenger iteration -@@ -4475,82 +4711,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return Mth.lerp(delta, this.yRotO, this.yRot); + + public int countPlayerPassengers() { +@@ -4209,77 +4446,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return Mth.lerp(partialTick, this.yRotO, this.yRot); } -- public boolean updateFluidHeightAndDoFluidPushing(TagKey<Fluid> tag, double speed) { +- public boolean updateFluidHeightAndDoFluidPushing(TagKey<Fluid> fluidTag, double motionScale) { + // Paper start - optimise collisions + public boolean updateFluidHeightAndDoFluidPushing(final TagKey<Fluid> fluid, final double flowScale) { if (this.touchingUnloadedChunk()) { return false; - } else { -- AABB axisalignedbb = this.getBoundingBox().deflate(0.001D); -- int i = Mth.floor(axisalignedbb.minX); -- int j = Mth.ceil(axisalignedbb.maxX); -- int k = Mth.floor(axisalignedbb.minY); -- int l = Mth.ceil(axisalignedbb.maxY); -- int i1 = Mth.floor(axisalignedbb.minZ); -- int j1 = Mth.ceil(axisalignedbb.maxZ); -- double d1 = 0.0D; -- boolean flag = this.isPushedByFluid(); -- boolean flag1 = false; -- 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); -- -- if (fluid.is(tag)) { -- double d2 = (double) ((float) i2 + fluid.getHeight(this.level(), blockposition_mutableblockposition)); -- -- if (d2 >= axisalignedbb.minY) { -- flag1 = true; -- d1 = Math.max(d2 - axisalignedbb.minY, d1); -- if (flag) { -- Vec3 vec3d1 = fluid.getFlow(this.level(), blockposition_mutableblockposition); -- -- if (d1 < 0.4D) { -- vec3d1 = vec3d1.scale(d1); +- AABB aabb = this.getBoundingBox().deflate(0.001); +- int floor = Mth.floor(aabb.minX); +- int ceil = Mth.ceil(aabb.maxX); +- int floor1 = Mth.floor(aabb.minY); +- int ceil1 = Mth.ceil(aabb.maxY); +- int floor2 = Mth.floor(aabb.minZ); +- int ceil2 = Mth.ceil(aabb.maxZ); +- double d = 0.0; +- boolean isPushedByFluid = this.isPushedByFluid(); +- boolean flag = false; +- Vec3 vec3 = Vec3.ZERO; +- int i = 0; +- BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); +- +- for (int i1 = floor; i1 < ceil; i1++) { +- for (int i2 = floor1; i2 < ceil1; i2++) { +- for (int i3 = floor2; i3 < ceil2; i3++) { +- mutableBlockPos.set(i1, i2, i3); +- FluidState fluidState = this.level().getFluidState(mutableBlockPos); +- if (fluidState.is(fluidTag)) { +- double d1 = i2 + fluidState.getHeight(this.level(), mutableBlockPos); +- if (d1 >= aabb.minY) { +- flag = true; +- d = Math.max(d1 - aabb.minY, d); +- if (isPushedByFluid) { +- Vec3 flow = fluidState.getFlow(this.level(), mutableBlockPos); +- if (d < 0.4) { +- flow = flow.scale(d); - } + } + @@ -29277,8 +28772,8 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 + final int minYIterate = currChunkY == minChunkY ? (minBlockY & 15) : 0; + final int maxYIterate = currChunkY == maxChunkY ? (maxBlockY & 15) : 15; -- vec3d = vec3d.add(vec3d1); -- ++k1; +- vec3 = vec3.add(flow); +- i++; + for (int currY = minYIterate; currY <= maxYIterate; ++currY) { + for (int currZ = minZIterate; currZ <= maxZIterate; ++currZ) { + for (int currX = minXIterate; currX <= maxXIterate; ++currX) { @@ -29288,8 +28783,8 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 + continue; } - // CraftBukkit start - store last lava contact location -- if (tag == FluidTags.LAVA) { -- this.lastLavaContact = blockposition_mutableblockposition.immutable(); +- if (fluidTag == FluidTags.LAVA) { +- this.lastLavaContact = mutableBlockPos.immutable(); + + mutablePos.set(currX | (currChunkX << 4), currY | (currChunkY << 4), currZ | (currChunkZ << 4)); + @@ -29324,53 +28819,52 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 } + } -- if (vec3d.length() > 0.0D) { -- if (k1 > 0) { -- vec3d = vec3d.scale(1.0D / (double) k1); +- if (vec3.length() > 0.0) { +- if (i > 0) { +- vec3 = vec3.scale(1.0 / i); - } + this.fluidHeight.put(fluid, maxHeightDiff); - if (!(this instanceof Player)) { -- vec3d = vec3d.normalize(); +- vec3 = vec3.normalize(); - } + if (pushVector.lengthSqr() == 0.0) { + return inFluid; + } -- Vec3 vec3d2 = this.getDeltaMovement(); +- Vec3 deltaMovement = this.getDeltaMovement(); +- vec3 = vec3.scale(motionScale); +- double d2 = 0.003; +- if (Math.abs(deltaMovement.x) < 0.003 && Math.abs(deltaMovement.z) < 0.003 && vec3.length() < 0.0045000000000000005) { +- vec3 = vec3.normalize().scale(0.0045000000000000005); +- } + // note: totalPushes != 0 as pushVector != 0 + pushVector = pushVector.scale(1.0 / totalPushes); + final Vec3 currMovement = this.getDeltaMovement(); -- vec3d = vec3d.scale(speed); -- double d3 = 0.003D; +- this.setDeltaMovement(this.getDeltaMovement().add(vec3)); +- } + if (!((Entity)(Object)this instanceof Player)) { + pushVector = pushVector.normalize(); + } -- if (Math.abs(vec3d2.x) < 0.003D && Math.abs(vec3d2.z) < 0.003D && vec3d.length() < 0.0045000000000000005D) { -- vec3d = vec3d.normalize().scale(0.0045000000000000005D); -- } +- this.fluidHeight.put(fluidTag, d); +- return flag; + pushVector = pushVector.scale(flowScale); + if (Math.abs(currMovement.x) < 0.003 && Math.abs(currMovement.z) < 0.003 && pushVector.length() < 0.0045000000000000005) { + pushVector = pushVector.normalize().scale(0.0045000000000000005); -+ } - -- this.setDeltaMovement(this.getDeltaMovement().add(vec3d)); -- } + } ++ + this.setDeltaMovement(currMovement.add(pushVector)); - -- this.fluidHeight.put(tag, d1); -- return flag1; -- } ++ + // note: inFluid = true here as pushVector != 0 + return true; } + // Paper end - optimise collisions public boolean touchingUnloadedChunk() { - AABB axisalignedbb = this.getBoundingBox().inflate(1.0D); -@@ -4702,6 +4992,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + AABB aabb = this.getBoundingBox().inflate(1.0); +@@ -4430,6 +4726,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.setPosRaw(x, y, z, false); } public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) { @@ -29386,39 +28880,39 @@ index 766031d1482b0f49b196326b820d5ce9ae1c7c06..1f54752a4ea0788e73279cd99c7c35e3 if (!checkPosition(this, x, y, z)) { return; } -@@ -4831,6 +5130,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4558,6 +4863,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @Override - public final void setRemoved(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { + public final void setRemoved(Entity.RemovalReason removalReason, org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { + // Paper start - rewrite chunk system + if (!((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this.level).moonrise$getEntityLookup().canRemoveEntity((Entity)(Object)this)) { + LOGGER.warn("Entity " + this + " is currently prevented from being removed from the world since it is processing section status updates", new Throwable()); + return; + } + // Paper end - rewrite chunk system - CraftEventFactory.callEntityRemoveEvent(this, cause); + org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit end final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers -@@ -4842,7 +5147,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4569,7 +4880,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.stopRiding(); } - 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); - this.onRemoval(entity_removalreason); + this.levelCallback.onRemove(removalReason); + this.onRemoval(removalReason); // Paper start - Folia schedulers -@@ -4874,7 +5179,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - - @Override +@@ -4603,7 +4914,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public boolean shouldBeSaved() { -- return this.removalReason != null && !this.removalReason.shouldSave() ? false : (this.isPassenger() ? false : !this.isVehicle() || !this.hasExactlyOnePlayerPassenger()); -+ return this.removalReason != null && !this.removalReason.shouldSave() ? false : (this.isPassenger() ? false : !this.isVehicle() || !((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)this).moonrise$hasAnyPlayerPassengers()); // Paper - rewrite chunk system + return (this.removalReason == null || this.removalReason.shouldSave()) + && !this.isPassenger() +- && (!this.isVehicle() || !this.hasExactlyOnePlayerPassenger()); ++ && (!this.isVehicle() || !((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)this).moonrise$hasAnyPlayerPassengers()); // Paper - rewrite chunk system } @Override diff --git a/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/net/minecraft/world/entity/ai/village/poi/PoiManager.java -index 96bc0ba60195e5e666d47b3a0b943b733986d96a..5930a430983061afddf20e3208ff2462ca1b78cd 100644 +index 7d590dd06cc69c0925d22708425520c38e3cda25..c8590e0175dacd6d7efdb1830bd60c92325083f9 100644 --- a/net/minecraft/world/entity/ai/village/poi/PoiManager.java +++ b/net/minecraft/world/entity/ai/village/poi/PoiManager.java @@ -38,12 +38,137 @@ import net.minecraft.world.level.chunk.storage.RegionStorageInfo; @@ -29558,10 +29052,10 @@ index 96bc0ba60195e5e666d47b3a0b943b733986d96a..5930a430983061afddf20e3208ff2462 + // Paper end - rewrite chunk system + public PoiManager( - RegionStorageInfo storageKey, - Path directory, + RegionStorageInfo info, + Path folder, @@ -64,6 +189,7 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> { - world + levelHeightAccessor ); this.distanceTracker = new PoiManager.DistanceTracker(); + this.world = (net.minecraft.server.level.ServerLevel)world; // Paper - rewrite chunk system @@ -29571,30 +29065,29 @@ index 96bc0ba60195e5e666d47b3a0b943b733986d96a..5930a430983061afddf20e3208ff2462 @@ -197,8 +323,10 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> { } - public int sectionsToVillage(SectionPos pos) { + public int sectionsToVillage(SectionPos sectionPos) { - this.distanceTracker.runAllUpdates(); -- return this.distanceTracker.getLevel(pos.asLong()); +- return this.distanceTracker.getLevel(sectionPos.asLong()); + // Paper start - rewrite chunk system + this.villageDistanceTracker.propagateUpdates(); -+ return convertBetweenLevels(this.villageDistanceTracker.getLevel(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkSectionKey(pos))); ++ return convertBetweenLevels(this.villageDistanceTracker.getLevel(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkSectionKey(sectionPos))); + // Paper end - rewrite chunk system } - boolean isVillageCenter(long pos) { + boolean isVillageCenter(long chunkPos) { @@ -212,19 +340,26 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> { @Override - public void tick(BooleanSupplier shouldKeepTicking) { -- super.tick(shouldKeepTicking); + public void tick(BooleanSupplier aheadOfTime) { +- super.tick(aheadOfTime); - this.distanceTracker.runAllUpdates(); + this.villageDistanceTracker.propagateUpdates(); // Paper - rewrite chunk system } @Override -- protected void setDirty(long pos) { -- super.setDirty(pos); -- this.distanceTracker.update(pos, this.distanceTracker.getLevelFromSource(pos), false); -+ public void setDirty(long pos) { // Paper - public + protected void setDirty(long sectionPos) { +- super.setDirty(sectionPos); +- this.distanceTracker.update(sectionPos, this.distanceTracker.getLevelFromSource(sectionPos), false); + // Paper start - rewrite chunk system + final int chunkX = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkSectionX(pos); + final int chunkZ = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkSectionZ(pos); @@ -29608,23 +29101,23 @@ index 96bc0ba60195e5e666d47b3a0b943b733986d96a..5930a430983061afddf20e3208ff2462 } @Override - protected void onSectionLoad(long pos) { -- this.distanceTracker.update(pos, this.distanceTracker.getLevelFromSource(pos), false); -+ this.updateDistanceTracking(pos); // Paper - rewrite chunk system + protected void onSectionLoad(long sectionKey) { +- this.distanceTracker.update(sectionKey, this.distanceTracker.getLevelFromSource(sectionKey), false); ++ this.updateDistanceTracking(sectionKey); // Paper - rewrite chunk system } - public void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection chunkSection) { + public void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection levelChunkSection) { @@ -263,7 +398,7 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> { .map(sectionPos -> Pair.of(sectionPos, this.getOrLoad(sectionPos.asLong()))) .filter(pair -> !pair.getSecond().map(PoiSection::isValid).orElse(false)) .map(pair -> pair.getFirst().chunk()) - .filter(chunkPos -> this.loadedChunks.add(chunkPos.toLong())) + // Paper - rewrite chunk system - .forEach(chunkPos -> world.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY)); + .forEach(chunkPos -> levelReader.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY)); } diff --git a/net/minecraft/world/entity/ai/village/poi/PoiSection.java b/net/minecraft/world/entity/ai/village/poi/PoiSection.java -index b9e0bc8f1e948614d986335de1f3d2df199eea81..712cbfc100e8aaf612d1d651dae64f57f892a768 100644 +index 324cc0686f0f5b1371b2bbea5b8c8fdb1f363006..39cd1e3d8192d7077d6b7864d33933097cc6b986 100644 --- a/net/minecraft/world/entity/ai/village/poi/PoiSection.java +++ b/net/minecraft/world/entity/ai/village/poi/PoiSection.java @@ -23,13 +23,27 @@ import net.minecraft.core.SectionPos; @@ -29653,27 +29146,27 @@ index b9e0bc8f1e948614d986335de1f3d2df199eea81..712cbfc100e8aaf612d1d651dae64f57 + } + // Paper end - rewrite chunk system + - public PoiSection(Runnable updateListener) { - this(updateListener, true, ImmutableList.of()); + public PoiSection(Runnable setDirty) { + this(setDirty, true, ImmutableList.of()); } diff --git a/net/minecraft/world/entity/decoration/ArmorStand.java b/net/minecraft/world/entity/decoration/ArmorStand.java -index 63f02cdc67d9e88cc6998d0ae9d139c83e85b447..70b8023c3badc745f342d5b0ab54699e3923826a 100644 +index 613675c86787dd1147e140f1ef4d17b09ab9a74b..5cc19a67c7a29f1bda8cdd6921201f47fe6bf91f 100644 --- a/net/minecraft/world/entity/decoration/ArmorStand.java +++ b/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -364,7 +364,7 @@ public class ArmorStand extends LivingEntity { +@@ -316,7 +316,7 @@ public class ArmorStand extends LivingEntity { @Override protected void pushEntities() { if (!this.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return; // Paper - Option to prevent armor stands from doing entity lookups -- List<Entity> list = this.level().getEntities((Entity) this, this.getBoundingBox(), ArmorStand.RIDABLE_MINECARTS); -+ List<AbstractMinecart> list = this.level().getEntitiesOfClass(AbstractMinecart.class, this.getBoundingBox(), RIDABLE_MINECARTS); // Paper - optimise collisions - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { +- for (Entity entity : this.level().getEntities(this, this.getBoundingBox(), RIDABLE_MINECARTS)) { ++ for (Entity entity : this.level().getEntitiesOfClass(AbstractMinecart.class, this.getBoundingBox(), RIDABLE_MINECARTS)) { // Paper - optimise collisions + if (this.distanceToSqr(entity) <= 0.2) { + entity.push(this); + } diff --git a/net/minecraft/world/level/ClipContext.java b/net/minecraft/world/level/ClipContext.java -index 3fa2964b979053ecbefc946c7fe76828de86d8f1..28bf0518f7d17099d7e4990defbeda6757b4477c 100644 +index 9f34fc4278860dd7bcfa1fd79b15e588b0cc3973..a7ebd624652cb6f0edc735bf6b9760e7b443594f 100644 --- a/net/minecraft/world/level/ClipContext.java +++ b/net/minecraft/world/level/ClipContext.java -@@ -18,7 +18,7 @@ public class ClipContext { +@@ -17,7 +17,7 @@ public class ClipContext { private final Vec3 from; private final Vec3 to; private final ClipContext.Block block; @@ -29681,9 +29174,9 @@ index 3fa2964b979053ecbefc946c7fe76828de86d8f1..28bf0518f7d17099d7e4990defbeda67 + public final ClipContext.Fluid fluid; // Paper - optimise collisions - public private final CollisionContext collisionContext; - public ClipContext(Vec3 start, Vec3 end, ClipContext.Block shapeType, ClipContext.Fluid fluidHandling, Entity entity) { + public ClipContext(Vec3 from, Vec3 to, ClipContext.Block block, ClipContext.Fluid fluid, Entity entity) { diff --git a/net/minecraft/world/level/EntityGetter.java b/net/minecraft/world/level/EntityGetter.java -index e185a33b5b1f8e8e0a0e666b24ba3e9186a8a7ff..5d7a6e4b73f032db356e7ec369b150013e940ee6 100644 +index 300f3ed58109219d97846082941b860585f66fed..e81195df621159da67136f020fa7a6d39d1ee5ed 100644 --- a/net/minecraft/world/level/EntityGetter.java +++ b/net/minecraft/world/level/EntityGetter.java @@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.BooleanOp; @@ -29692,22 +29185,22 @@ index e185a33b5b1f8e8e0a0e666b24ba3e9186a8a7ff..5d7a6e4b73f032db356e7ec369b15001 -public interface EntityGetter { +public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter { // Paper - rewrite chunk system - List<Entity> getEntities(@Nullable Entity except, AABB box, Predicate<? super Entity> predicate); + List<Entity> getEntities(@Nullable Entity entity, AABB area, Predicate<? super Entity> predicate); - <T extends Entity> List<T> getEntities(EntityTypeTest<Entity, T> filter, AABB box, Predicate<? super T> predicate); + <T extends Entity> List<T> getEntities(EntityTypeTest<Entity, T> entityTypeTest, AABB bounds, Predicate<? super T> predicate); @@ -30,21 +30,44 @@ public interface EntityGetter { - return this.getEntities(except, box, EntitySelector.NO_SPECTATORS); + return this.getEntities(entity, area, EntitySelector.NO_SPECTATORS); } -- default boolean isUnobstructed(@Nullable Entity except, VoxelShape shape) { +- default boolean isUnobstructed(@Nullable Entity entity, VoxelShape shape) { - if (shape.isEmpty()) { - return true; - } else { -- for (Entity entity : this.getEntities(except, shape.bounds())) { -- if (!entity.isRemoved() -- && entity.blocksBuilding -- && (except == null || !entity.isPassengerOfSameVehicle(except)) -- && Shapes.joinIsNotEmpty(shape, Shapes.create(entity.getBoundingBox()), BooleanOp.AND)) { +- for (Entity entity1 : this.getEntities(entity, shape.bounds())) { +- if (!entity1.isRemoved() +- && entity1.blocksBuilding +- && (entity == null || !entity1.isPassengerOfSameVehicle(entity)) +- && Shapes.joinIsNotEmpty(shape, Shapes.create(entity1.getBoundingBox()), BooleanOp.AND)) { - return false; + // Paper start - rewrite chunk system + @Override @@ -29750,16 +29243,16 @@ index e185a33b5b1f8e8e0a0e666b24ba3e9186a8a7ff..5d7a6e4b73f032db356e7ec369b15001 + // Paper end - optimise collisions } - default <T extends Entity> List<T> getEntitiesOfClass(Class<T> entityClass, AABB box) { + default <T extends Entity> List<T> getEntitiesOfClass(Class<T> entityClass, AABB area) { @@ -52,23 +75,41 @@ public interface EntityGetter { } - default List<VoxelShape> getEntityCollisions(@Nullable Entity entity, AABB box) { -- if (box.getSize() < 1.0E-7) { + default List<VoxelShape> getEntityCollisions(@Nullable Entity entity, AABB collisionBox) { +- if (collisionBox.getSize() < 1.0E-7) { - return List.of(); + // Paper start - optimise collisions + // first behavior change is to correctly check for empty AABB -+ if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isEmpty(box)) { ++ if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isEmpty(collisionBox)) { + // reduce indirection by always returning type with same class + return new java.util.ArrayList<>(); + } @@ -29767,23 +29260,23 @@ index e185a33b5b1f8e8e0a0e666b24ba3e9186a8a7ff..5d7a6e4b73f032db356e7ec369b15001 + // to comply with vanilla intersection rules, expand by -epsilon so that we only get stuff we definitely collide with. + // Vanilla for hard collisions has this backwards, and they expand by +epsilon but this causes terrible problems + // specifically with boat collisions. -+ box = box.inflate(-ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON, -ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON, -ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON); ++ collisionBox = collisionBox.inflate(-ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON, -ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON, -ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON); + + final List<Entity> entities; -+ if (entity != null && ((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)entity).moonrise$isHardColliding()) { -+ entities = this.getEntities(entity, box, null); ++ if (entity != null && ((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity) entity).moonrise$isHardColliding()) { ++ entities = this.getEntities(entity, collisionBox, null); } else { - Predicate<Entity> predicate = entity == null ? EntitySelector.CAN_BE_COLLIDED_WITH : EntitySelector.NO_SPECTATORS.and(entity::canCollideWith); -- List<Entity> list = this.getEntities(entity, box.inflate(1.0E-7), predicate); -- if (list.isEmpty()) { +- List<Entity> entities = this.getEntities(entity, collisionBox.inflate(1.0E-7), predicate); +- if (entities.isEmpty()) { - return List.of(); - } else { -- Builder<VoxelShape> builder = ImmutableList.builderWithExpectedSize(list.size()); +- Builder<VoxelShape> builder = ImmutableList.builderWithExpectedSize(entities.size()); - -- for (Entity entity2 : list) { -- builder.add(Shapes.create(entity2.getBoundingBox())); +- for (Entity entity1 : entities) { +- builder.add(Shapes.create(entity1.getBoundingBox())); - } -+ entities = ((ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter)this).moonrise$getHardCollidingEntities(entity, box, null); ++ entities = ((ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter) this).moonrise$getHardCollidingEntities(entity, collisionBox, null); + } - return builder.build(); @@ -29807,10 +29300,10 @@ index e185a33b5b1f8e8e0a0e666b24ba3e9186a8a7ff..5d7a6e4b73f032db356e7ec369b15001 // Paper start - Affects Spawning API diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b827401434bcfff1 100644 +index 872c3b8826f436b15f6ab0a3619692c5202eadc3..b5efce6faf35dbfee9aa6c17f2e7e9befe6a2040 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -84,6 +84,7 @@ import net.minecraft.world.level.storage.LevelData; +@@ -79,6 +79,7 @@ import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.level.storage.WritableLevelData; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; @@ -29818,25 +29311,25 @@ index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b8274014 import net.minecraft.world.scores.Scoreboard; // CraftBukkit start -@@ -105,7 +106,7 @@ import org.bukkit.entity.SpawnCategory; +@@ -102,7 +103,7 @@ import org.bukkit.entity.SpawnCategory; import org.bukkit.event.block.BlockPhysicsEvent; // CraftBukkit end -public abstract class Level implements LevelAccessor, AutoCloseable { +public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel, ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter { // Paper - rewrite chunk system // Paper - optimise collisions - public static final Codec<ResourceKey<Level>> RESOURCE_KEY_CODEC = ResourceKey.codec(Registries.DIMENSION); public static final ResourceKey<Level> OVERWORLD = ResourceKey.create(Registries.DIMENSION, ResourceLocation.withDefaultNamespace("overworld")); -@@ -131,7 +132,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + public static final ResourceKey<Level> NETHER = ResourceKey.create(Registries.DIMENSION, ResourceLocation.withDefaultNamespace("the_nether")); +@@ -127,7 +128,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public float rainLevel; protected float oThunderLevel; public float thunderLevel; - public final RandomSource random = RandomSource.create(); + public final RandomSource random = new ca.spottedleaf.moonrise.common.util.ThreadUnsafeRandom(net.minecraft.world.level.levelgen.RandomSupport.generateUniqueSeed()); // Paper - replace random - /** @deprecated */ @Deprecated private final RandomSource threadSafeRandom = RandomSource.createThreadSafe(); -@@ -207,7 +208,639 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + private final Holder<DimensionType> dimensionTypeRegistration; +@@ -202,6 +203,629 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public abstract ResourceKey<LevelStem> getTypeKey(); @@ -30463,9 +29956,15 @@ index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b8274014 + } + // Paper end - optimise random ticking + - protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> 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<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config & Anti-Xray + protected Level( + WritableLevelData levelData, + ResourceKey<Level> dimension, +@@ -218,6 +842,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, // Paper - create paper world config + java.util.concurrent.Executor executor // Paper - Anti-Xray + ) { + // Paper start - getblock optimisations - cache world height/sections -+ final DimensionType dimType = holder.value(); ++ final DimensionType dimType = dimensionTypeRegistration.value(); + this.minY = dimType.minY(); + this.height = dimType.height(); + this.maxY = this.minY + this.height - 1; @@ -30473,18 +29972,18 @@ index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b8274014 + this.maxSectionY = this.maxY >> 4; + this.sectionsCount = this.maxSectionY - this.minSectionY + 1; + // Paper end - getblock optimisations - cache world height/sections - this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config this.generator = gen; -@@ -288,6 +921,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -298,6 +931,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime); this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime); - this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray + this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new io.papermc.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : io.papermc.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray + this.entityLookup = new ca.spottedleaf.moonrise.patches.chunk_system.level.entity.dfl.DefaultEntityLookup(this); // Paper - rewrite chunk system } // Paper start - Cancel hit for vanished players -@@ -557,7 +1191,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -567,7 +1201,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { this.setBlocksDirty(blockposition, iblockdata1, iblockdata2); } @@ -30493,19 +29992,19 @@ index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b8274014 this.sendBlockUpdated(blockposition, iblockdata1, iblockdata, i); } -@@ -820,6 +1454,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -836,6 +1470,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // Iterator<TickingBlockEntity> iterator = this.blockEntityTickers.iterator(); - boolean flag = this.tickRateManager().runsNormally(); + boolean runsNormally = this.tickRateManager().runsNormally(); + int tickedEntities = 0; // Paper - rewrite chunk system + int tilesThisCycle = 0; var toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<TickingBlockEntity>(); // Paper - Fix MC-117075; use removeAll toRemove.add(null); // Paper - Fix MC-117075 -@@ -835,6 +1471,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -850,6 +1486,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // Spigot end - } else if (flag && this.shouldTickBlocksAt(tickingblockentity.getPos())) { - tickingblockentity.tick(); + } else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) { + tickingBlockEntity.tick(); + // Paper start - rewrite chunk system + if ((++tickedEntities & 7) == 0) { + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks(); @@ -30514,16 +30013,18 @@ index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b8274014 } } this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 -@@ -855,12 +1496,20 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -870,6 +1511,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Paper end - Prevent block entity and entity crashes } + this.moonrise$midTickTasks(); // Paper - rewrite chunk system } + // Paper start - Option to prevent armor stands from doing entity lookups - @Override +@@ -877,7 +1519,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public boolean noCollision(@Nullable Entity entity, AABB box) { - if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return false; + if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups) + return false; - return LevelAccessor.super.noCollision(entity, box); + // Paper start - optimise collisions + final int flags = entity == null ? (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER | ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_ONLY) : ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_ONLY; @@ -30536,59 +30037,62 @@ index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b8274014 } // Paper end - Option to prevent armor stands from doing entity lookups -@@ -912,7 +1561,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1015,7 +1664,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + if (this.isOutsideBuildHeight(pos)) { + return null; + } else { +- return !this.isClientSide && Thread.currentThread() != this.thread ++ return !this.isClientSide && !ca.spottedleaf.moonrise.common.util.TickThread.isTickThread() // Paper - rewrite chunk system + ? null + : this.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE); } - // Paper end - Perf: Optimize capturedTileEntities lookup - // CraftBukkit end -- return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); -+ return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !ca.spottedleaf.moonrise.common.util.TickThread.isTickThread() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system - } - - public void setBlockEntity(BlockEntity blockEntity) { -@@ -1004,23 +1653,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1108,22 +1757,16 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + public List<Entity> getEntities(@Nullable Entity entity, AABB boundingBox, Predicate<? super Entity> predicate) { Profiler.get().incrementCounter("getEntities"); List<Entity> list = Lists.newArrayList(); - -- this.getEntities().get(box, (entity1) -> { -- if (entity1 != except && predicate.test(entity1)) { +- this.getEntities().get(boundingBox, entity1 -> { +- if (entity1 != entity && predicate.test(entity1)) { - list.add(entity1); - } -- - }); -- Iterator iterator = this.dragonParts().iterator(); -+ // Paper start - rewrite chunk system -+ final List<Entity> ret = new java.util.ArrayList<>(); -- while (iterator.hasNext()) { -- EnderDragonPart entitycomplexpart = (EnderDragonPart) iterator.next(); -+ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(except, box, ret, predicate); - -- if (entitycomplexpart != except && entitycomplexpart.parentMob != except && predicate.test(entitycomplexpart) && box.intersects(entitycomplexpart.getBoundingBox())) { -- list.add(entitycomplexpart); +- for (EnderDragonPart enderDragonPart : this.dragonParts()) { +- if (enderDragonPart != entity +- && enderDragonPart.parentMob != entity +- && predicate.test(enderDragonPart) +- && boundingBox.intersects(enderDragonPart.getBoundingBox())) { +- list.add(enderDragonPart); - } - } -+ ca.spottedleaf.moonrise.common.PlatformHooks.get().addToGetEntities((Level)(Object)this, except, box, predicate, ret); ++ // Paper start - rewrite chunk system ++ final List<Entity> ret = new java.util.ArrayList<>(); - return list; ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entity, boundingBox, ret, predicate); ++ ++ ca.spottedleaf.moonrise.common.PlatformHooks.get().addToGetEntities((Level)(Object)this, entity, boundingBox, predicate, ret); ++ + return ret; + // Paper end - rewrite chunk system } @Override -@@ -1035,36 +1676,94 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - this.getEntities(filter, box, predicate, result, Integer.MAX_VALUE); +@@ -1137,33 +1780,94 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + this.getEntities(entityTypeTest, bounds, predicate, output, Integer.MAX_VALUE); } -- public <T extends Entity> void getEntities(EntityTypeTest<Entity, T> filter, AABB box, Predicate<? super T> predicate, List<? super T> result, int limit) { +- public <T extends Entity> void getEntities( +- EntityTypeTest<Entity, T> entityTypeTest, AABB bounds, Predicate<? super T> predicate, List<? super T> output, int maxResults +- ) { + // Paper start - rewrite chunk system + public <T extends Entity> void getEntities(final EntityTypeTest<Entity, T> entityTypeTest, + final AABB boundingBox, final Predicate<? super T> predicate, + final List<? super T> into, final int maxCount) { Profiler.get().incrementCounter("getEntities"); -- this.getEntities().get(filter, box, (entity) -> { +- this.getEntities().get(entityTypeTest, bounds, entity -> { - if (predicate.test(entity)) { -- result.add(entity); -- if (result.size() >= limit) { +- output.add(entity); +- if (output.size() >= maxResults) { - return AbortableIterationConsumer.Continuation.ABORT; - } + @@ -30604,9 +30108,15 @@ index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b8274014 } + } -- if (entity instanceof EnderDragon entityenderdragon) { -- EnderDragonPart[] aentitycomplexpart = entityenderdragon.getSubEntities(); -- int j = aentitycomplexpart.length; +- if (entity instanceof EnderDragon enderDragon) { +- for (EnderDragonPart enderDragonPart : enderDragon.getSubEntities()) { +- T entity1 = entityTypeTest.tryCast(enderDragonPart); +- if (entity1 != null && predicate.test(entity1)) { +- output.add(entity1); +- if (output.size() >= maxResults) { +- return AbortableIterationConsumer.Continuation.ABORT; +- } +- } + if (entityTypeTest == null) { + if (maxCount != Integer.MAX_VALUE) { + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities((Entity)null, boundingBox, (List)into, (Predicate)predicate, maxCount); @@ -30618,18 +30128,9 @@ index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b8274014 + return; + } + } - -- for (int k = 0; k < j; ++k) { -- EnderDragonPart entitycomplexpart = aentitycomplexpart[k]; -- T t0 = filter.tryCast(entitycomplexpart); // CraftBukkit - decompile error ++ + final Class<? extends Entity> base = entityTypeTest.getBaseClass(); - -- if (t0 != null && predicate.test(t0)) { -- result.add(t0); -- if (result.size() >= limit) { -- return AbortableIterationConsumer.Continuation.ABORT; -- } -- } ++ + final Predicate<? super T> modifiedPredicate; + if (predicate == null) { + modifiedPredicate = (final T obj) -> { @@ -30692,7 +30193,7 @@ index 2a078293332efe4369f314ab021dfa16f63f7f3f..f477c5817f022ce7c4ad25e9b8274014 @Nullable public abstract Entity getEntity(int id); diff --git a/net/minecraft/world/level/LevelReader.java b/net/minecraft/world/level/LevelReader.java -index 5eb8982678110fabb82a93c5ec67c666b7fde017..ade435de0af4ee3566fa4a490df53cddd2f6531c 100644 +index 2709803b9266ff4a2034d83321cd0ba4e30fc0aa..26c8c1e5598daf3550aef05b12218c47bda6618b 100644 --- a/net/minecraft/world/level/LevelReader.java +++ b/net/minecraft/world/level/LevelReader.java @@ -22,7 +22,18 @@ import net.minecraft.world.level.dimension.DimensionType; @@ -30713,10 +30214,10 @@ index 5eb8982678110fabb82a93c5ec67c666b7fde017..ade435de0af4ee3566fa4a490df53cdd + // Paper end - rewrite chunk system + @Nullable - ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create); + ChunkAccess getChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk); diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index b8ffe547ad29645b65c3df8bd6ccb7c20985711d..685ccfb73bf7125585ef90b6a0f51b2f81daa428 100644 +index 8b91574d4679f4e5a01b4bc3651069cd489b0336..fc08543bf5c8cbe338991795a9da28e997a5d9d1 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java @@ -64,6 +64,249 @@ public class ServerExplosion implements Explosion { @@ -30967,61 +30468,60 @@ index b8ffe547ad29645b65c3df8bd6ccb7c20985711d..685ccfb73bf7125585ef90b6a0f51b2f + } + // Paper end - collisions optimisations - public ServerExplosion(ServerLevel world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 pos, float power, boolean createFire, Explosion.BlockInteraction destructionType) { - this.level = world; -@@ -127,65 +370,101 @@ public class ServerExplosion implements Explosion { + public ServerExplosion( + ServerLevel level, +@@ -135,63 +378,102 @@ public class ServerExplosion implements Explosion { } private List<BlockPos> calculateExplodedPositions() { -- Set<BlockPos> set = new HashSet(); -- boolean flag = true; -- -- for (int i = 0; i < 16; ++i) { -- for (int j = 0; j < 16; ++j) { -- for (int k = 0; k < 16; ++k) { -- if (i == 0 || i == 15 || j == 0 || j == 15 || k == 0 || k == 15) { -- double d0 = (double) ((float) i / 15.0F * 2.0F - 1.0F); -- double d1 = (double) ((float) j / 15.0F * 2.0F - 1.0F); -- double d2 = (double) ((float) k / 15.0F * 2.0F - 1.0F); -- double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2); -- -- d0 /= d3; -- d1 /= d3; -- d2 /= d3; +- Set<BlockPos> set = new HashSet<>(); +- int i = 16; +- +- for (int i1 = 0; i1 < 16; i1++) { +- for (int i2 = 0; i2 < 16; i2++) { +- for (int i3 = 0; i3 < 16; i3++) { +- if (i1 == 0 || i1 == 15 || i2 == 0 || i2 == 15 || i3 == 0 || i3 == 15) { +- double d = i1 / 15.0F * 2.0F - 1.0F; +- double d1 = i2 / 15.0F * 2.0F - 1.0F; +- double d2 = i3 / 15.0F * 2.0F - 1.0F; +- double squareRoot = Math.sqrt(d * d + d1 * d1 + d2 * d2); +- d /= squareRoot; +- d1 /= squareRoot; +- d2 /= squareRoot; - float f = this.radius * (0.7F + this.level.random.nextFloat() * 0.6F); -- double d4 = this.center.x; -- double d5 = this.center.y; -- double d6 = this.center.z; +- double d3 = this.center.x; +- double d4 = this.center.y; +- double d5 = this.center.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)) { +- BlockPos blockPos = BlockPos.containing(d3, d4, d5); +- BlockState blockState = this.level.getBlockState(blockPos); +- if (!blockState.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed +- FluidState fluidState = blockState.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions +- if (!this.level.isInWorldBounds(blockPos)) { - break; - } + // Paper start - collision optimisations + final ObjectArrayList<BlockPos> ret = new ObjectArrayList<>(); -- Optional<Float> optional = this.damageCalculator.getBlockExplosionResistance(this, this.level, blockposition, iblockdata, fluid); -+ final Vec3 center = this.center; - -- if (optional.isPresent()) { -- f -= ((Float) optional.get() + 0.3F) * 0.3F; +- Optional<Float> blockExplosionResistance = this.damageCalculator +- .getBlockExplosionResistance(this, this.level, blockPos, blockState, fluidState); +- if (blockExplosionResistance.isPresent()) { +- f -= (blockExplosionResistance.get() + 0.3F) * 0.3F; - } -+ final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[] blockCache = this.directMappedBlockCache; ++ final Vec3 center = this.center; -- if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockposition, iblockdata, f)) { -- set.add(blockposition); +- if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockPos, blockState, f)) { +- set.add(blockPos); - // 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 (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && blockState.getBlock() == Blocks.MOVING_PISTON) { +- net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(blockPos); - 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())); +- net.minecraft.core.Direction direction = blockState.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING); +- set.add(blockPos.relative(direction.getOpposite())); - } ++ final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[] blockCache = this.directMappedBlockCache; ++ + // use initial cache value that is most likely to be used: the source position + final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache initialCache; + { @@ -31097,10 +30597,10 @@ index b8ffe547ad29645b65c3df8bd6ccb7c20985711d..685ccfb73bf7125585ef90b6a0f51b2f } - // Paper end - prevent headless pistons from forming } -- -- d4 += d0 * 0.30000001192092896D; -- d5 += d1 * 0.30000001192092896D; -- d6 += d2 * 0.30000001192092896D; + +- d3 += d * 0.3F; +- d4 += d1 * 0.3F; +- d5 += d2 * 0.3F; + // Paper end - prevent headless pistons from forming } } @@ -31114,13 +30614,13 @@ index b8ffe547ad29645b65c3df8bd6ccb7c20985711d..685ccfb73bf7125585ef90b6a0f51b2f + } while (power > 0.0f); } -- return new ObjectArrayList(set); +- return new ObjectArrayList<>(set); + return ret; + // Paper end - collision optimisations } private void hurtEntities() { -@@ -391,6 +670,14 @@ public class ServerExplosion implements Explosion { +@@ -372,6 +654,14 @@ public class ServerExplosion implements Explosion { return; } // CraftBukkit end @@ -31132,10 +30632,10 @@ index b8ffe547ad29645b65c3df8bd6ccb7c20985711d..685ccfb73bf7125585ef90b6a0f51b2f + this.directMappedBlockCache = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH]; + this.mutablePos = new BlockPos.MutableBlockPos(); + // Paper end - collision optimisations - this.level.gameEvent(this.source, (Holder) GameEvent.EXPLODE, this.center); + this.level.gameEvent(this.source, GameEvent.EXPLODE, this.center); List<BlockPos> list = this.calculateExplodedPositions(); - -@@ -406,6 +693,13 @@ public class ServerExplosion implements Explosion { + this.hurtEntities(); +@@ -385,6 +675,13 @@ public class ServerExplosion implements Explosion { if (this.fire) { this.createFire(list); } @@ -31146,10 +30646,10 @@ index b8ffe547ad29645b65c3df8bd6ccb7c20985711d..685ccfb73bf7125585ef90b6a0f51b2f + this.directMappedBlockCache = null; + this.mutablePos = null; + // Paper end - collision optimisations - } -@@ -499,12 +793,12 @@ public class ServerExplosion implements Explosion { + private static void addOrAppendStack(List<ServerExplosion.StackCollector> stackCollectors, ItemStack stack, BlockPos pos) { +@@ -475,12 +772,12 @@ public class ServerExplosion implements Explosion { // Paper start - Optimize explosions private float getBlockDensity(Vec3 vec3d, Entity entity) { if (!this.level.paperConfig().environment.optimizeExplosions) { @@ -31165,72 +30665,72 @@ index b8ffe547ad29645b65c3df8bd6ccb7c20985711d..685ccfb73bf7125585ef90b6a0f51b2f } diff --git a/net/minecraft/world/level/biome/Biome.java b/net/minecraft/world/level/biome/Biome.java -index 9f86b69d8c93a63e0b408ea52519f1fc2e798226..78afd8e51e03cd53c12b64db8a817da457f81bef 100644 +index ea521e1d636b8ffdeb22882dfc8875b2ddbd8da1..7b666bbeefe296e7fdbadcc72dbf9e602f73e925 100644 --- a/net/minecraft/world/level/biome/Biome.java +++ b/net/minecraft/world/level/biome/Biome.java -@@ -113,20 +113,7 @@ public final class Biome { +@@ -117,20 +117,7 @@ public final class Biome { @Deprecated - public float getTemperature(BlockPos blockPos, int seaLevel) { -- long l = blockPos.asLong(); -- Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = this.temperatureCache.get(); -- float f = long2FloatLinkedOpenHashMap.get(l); + public float getTemperature(BlockPos pos, int seaLevel) { +- long packedBlockPos = pos.asLong(); +- Long2FloatLinkedOpenHashMap map = this.temperatureCache.get(); +- float f = map.get(packedBlockPos); - if (!Float.isNaN(f)) { - return f; - } else { -- float g = this.getHeightAdjustedTemperature(blockPos, seaLevel); -- if (long2FloatLinkedOpenHashMap.size() == 1024) { -- long2FloatLinkedOpenHashMap.removeFirstFloat(); +- float heightAdjustedTemperature = this.getHeightAdjustedTemperature(pos, seaLevel); +- if (map.size() == 1024) { +- map.removeFirstFloat(); - } - -- long2FloatLinkedOpenHashMap.put(l, g); -- return g; +- map.put(packedBlockPos, heightAdjustedTemperature); +- return heightAdjustedTemperature; - } -+ return this.getHeightAdjustedTemperature(blockPos, seaLevel); // Paper - optimise random ticking ++ return this.getHeightAdjustedTemperature(pos, seaLevel); // Paper - optimise random ticking } - public boolean shouldFreeze(LevelReader world, BlockPos blockPos) { + public boolean shouldFreeze(LevelReader level, BlockPos pos) { diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java -index 01352cc83b25eb0e30b7e0ff521fc7c1b3d5155b..90f8360f547ce709fd13ee34f8e67d8bfa94b498 100644 +index 8d98cba3830dc5dfb5cae9a6f5fedfffee0d2cd8..73962e79a0f3d892e3155443a1b84508b0f4042e 100644 --- a/net/minecraft/world/level/biome/BiomeManager.java +++ b/net/minecraft/world/level/biome/BiomeManager.java @@ -98,8 +98,7 @@ public class BiomeManager { } - private static double getFiddle(long l) { -- double d = (double)Math.floorMod(l >> 24, 1024) / 1024.0; + private static double getFiddle(long seed) { +- double d = Math.floorMod(seed >> 24, 1024) / 1024.0; - return (d - 0.5) * 0.9; -+ return (double)(((l >> 24) & (1024 - 1)) - (1024/2)) * (0.9 / 1024.0); // Paper - avoid floorMod, fp division, and fp subtraction ++ return (double)(((seed >> 24) & (1024 - 1)) - (1024/2)) * (0.9 / 1024.0); // Paper - avoid floorMod, fp division, and fp subtraction } public interface NoiseBiomeSource { diff --git a/net/minecraft/world/level/block/Block.java b/net/minecraft/world/level/block/Block.java -index 1aa69f4a7005242925124c74b8229e6fa7362717..c0b1f903962b25d8ff6c2b4fcd2be0e45de09b35 100644 +index 3eedc6c2a1325a0fd1baa14e246aeda27de4117d..34177f27680612055526553c849777067882ad74 100644 --- a/net/minecraft/world/level/block/Block.java +++ b/net/minecraft/world/level/block/Block.java -@@ -271,7 +271,7 @@ public class Block extends BlockBehaviour implements ItemLike { +@@ -259,7 +259,7 @@ public class Block extends BlockBehaviour implements ItemLike { } public static boolean isShapeFullBlock(VoxelShape shape) { -- return (Boolean) Block.SHAPE_FULL_BLOCK_CACHE.getUnchecked(shape); +- return SHAPE_FULL_BLOCK_CACHE.getUnchecked(shape); + return ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)shape).moonrise$isFullBlock(); // Paper - optimise collisions } - public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource random) {} + public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) { diff --git a/net/minecraft/world/level/block/state/BlockBehaviour.java b/net/minecraft/world/level/block/state/BlockBehaviour.java -index b1101156b281d800f18b25208018722bbecded9f..8c0f332a1a0918f60226d969918ae7fe4fe74166 100644 +index e0c3d8923f56c059b5d6111ab2ff01be3566f6d9..73b913da595e7ad2de8f363f342de98f6c647b71 100644 --- a/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/net/minecraft/world/level/block/state/BlockBehaviour.java -@@ -797,7 +797,7 @@ public abstract class BlockBehaviour implements FeatureElement { - boolean test(BlockState state, BlockGetter world, BlockPos pos); +@@ -417,7 +417,7 @@ public abstract class BlockBehaviour implements FeatureElement { + return this.properties.destroyTime; } - public abstract static class BlockStateBase extends StateHolder<Block, BlockState> { + public abstract static class BlockStateBase extends StateHolder<Block, BlockState> implements ca.spottedleaf.moonrise.patches.starlight.blockstate.StarlightAbstractBlockState, ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState { // Paper - rewrite chunk system // Paper - optimise collisions - private static final Direction[] DIRECTIONS = Direction.values(); - private static final VoxelShape[] EMPTY_OCCLUSION_SHAPES = (VoxelShape[]) Util.make(new VoxelShape[BlockBehaviour.BlockStateBase.DIRECTIONS.length], (avoxelshape) -> { -@@ -841,6 +841,76 @@ public abstract class BlockBehaviour implements FeatureElement { + private static final VoxelShape[] EMPTY_OCCLUSION_SHAPES = Util.make(new VoxelShape[DIRECTIONS.length], shape -> Arrays.fill(shape, Shapes.empty())); + private static final VoxelShape[] FULL_BLOCK_OCCLUSION_SHAPES = Util.make( +@@ -456,6 +456,76 @@ public abstract class BlockBehaviour implements FeatureElement { private boolean propagatesSkylightDown; private int lightBlock; @@ -31304,13 +30804,13 @@ index b1101156b281d800f18b25208018722bbecded9f..8c0f332a1a0918f60226d969918ae7fe + } + // Paper end - optimise collisions + - protected BlockStateBase(Block block, Reference2ObjectArrayMap<Property<?>, Comparable<?>> propertyMap, MapCodec<BlockState> codec) { - super(block, propertyMap, codec); - this.fluidState = Fluids.EMPTY.defaultFluidState(); -@@ -925,6 +995,41 @@ public abstract class BlockBehaviour implements FeatureElement { + protected BlockStateBase(Block owner, Reference2ObjectArrayMap<Property<?>, Comparable<?>> values, MapCodec<BlockState> propertiesCodec) { + super(owner, values, propertiesCodec); + BlockBehaviour.Properties properties = owner.properties; +@@ -534,6 +604,41 @@ public abstract class BlockBehaviour implements FeatureElement { - this.propagatesSkylightDown = ((Block) this.owner).propagatesSkylightDown(this.asState()); - this.lightBlock = ((Block) this.owner).getLightBlock(this.asState()); + this.propagatesSkylightDown = this.owner.propagatesSkylightDown(this.asState()); + this.lightBlock = this.owner.getLightBlock(this.asState()); + // Paper start - rewrite chunk system + this.isConditionallyFullOpaque = this.canOcclude & this.useShapeForLightOcclusion; + // Paper end - rewrite chunk system @@ -31350,7 +30850,7 @@ index b1101156b281d800f18b25208018722bbecded9f..8c0f332a1a0918f60226d969918ae7fe public Block getBlock() { diff --git a/net/minecraft/world/level/block/state/StateHolder.java b/net/minecraft/world/level/block/state/StateHolder.java -index 422b364764e0df16ca250b4939d7b226e69c0840..815ee11aa5ed3448ff255e9c36d769478de477bd 100644 +index 2f2dbf02a9732a7e640a6c730d4fc1443e723933..098518383d2c07491e047749ce3a834e98b85b1d 100644 --- a/net/minecraft/world/level/block/state/StateHolder.java +++ b/net/minecraft/world/level/block/state/StateHolder.java @@ -15,7 +15,7 @@ import java.util.stream.Collectors; @@ -31381,10 +30881,10 @@ index 422b364764e0df16ca250b4939d7b226e69c0840..815ee11aa5ed3448ff255e9c36d76947 + } + // Paper end - optimise blockstate property access + - protected StateHolder(O owner, Reference2ObjectArrayMap<Property<?>, Comparable<?>> propertyMap, MapCodec<S> codec) { + protected StateHolder(O owner, Reference2ObjectArrayMap<Property<?>, Comparable<?>> values, MapCodec<S> propertiesCodec) { this.owner = owner; - this.values = propertyMap; - this.propertiesCodec = codec; + this.values = values; + this.propertiesCodec = propertiesCodec; + // Paper start - optimise blockstate property access + this.optimisedTable = new ca.spottedleaf.moonrise.patches.blockstate_propertyaccess.util.ZeroCollidingReferenceStateTable<>(this.values.keySet()); + this.tableIndex = this.optimisedTable.getIndex((StateHolder<O, S>)(Object)this); @@ -31460,45 +30960,49 @@ index 422b364764e0df16ca250b4939d7b226e69c0840..815ee11aa5ed3448ff255e9c36d76947 + // Paper end - optimise blockstate property access } - private <T extends Comparable<T>, V extends T> S setValueInternal(Property<T> property, V newValue, Comparable<?> oldValue) { -@@ -125,18 +148,27 @@ public abstract class StateHolder<O, S> { + private <T extends Comparable<T>, V extends T> S setValueInternal(Property<T> property, V value, Comparable<?> comparable) { +@@ -125,21 +148,27 @@ public abstract class StateHolder<O, S> { } - public void populateNeighbours(Map<Map<Property<?>, Comparable<?>>, S> states) { + public void populateNeighbours(Map<Map<Property<?>, Comparable<?>>, S> possibleStateMap) { - if (this.neighbours != null) { - throw new IllegalStateException(); - } else { - Map<Property<?>, S[]> map = new Reference2ObjectArrayMap<>(this.values.size()); +- +- for (Entry<Property<?>, Comparable<?>> entry : this.values.entrySet()) { +- Property<?> property = entry.getKey(); +- map.put( +- property, +- (S[]) property.getPossibleValues().stream().map(comparable -> possibleStateMap.get(this.makeNeighbourValues(property, comparable))).toArray() +- ); +- } + // Paper start - optimise blockstate property access -+ final Map<Map<Property<?>, Comparable<?>>, S> map = states; ++ final Map<Map<Property<?>, Comparable<?>>, S> map = possibleStateMap; + if (this.optimisedTable.isLoaded()) { + return; + } + this.optimisedTable.loadInTable(map); -- for (Entry<Property<?>, Comparable<?>> entry : this.values.entrySet()) { -- Property<?> property = entry.getKey(); -- map.put(property, property.getPossibleValues().stream().map(value -> states.get(this.makeNeighbourValues(property, value))).toArray()); -- } +- this.neighbours = map; + // de-duplicate the tables + for (final Map.Entry<Map<Property<?>, Comparable<?>>, S> entry : map.entrySet()) { + final S value = entry.getValue(); + ((StateHolder<O, S>)value).optimisedTable = this.optimisedTable; -+ } - -- this.neighbours = map; + } ++ + // remove values arrays + for (final Map.Entry<Map<Property<?>, Comparable<?>>, S> entry : map.entrySet()) { + final S value = entry.getValue(); + ((StateHolder<O, S>)value).values = null; - } ++ } + + return; + // Paper end optimise blockstate property access } private Map<Property<?>, Comparable<?>> makeNeighbourValues(Property<?> property, Comparable<?> value) { -@@ -146,7 +178,11 @@ public abstract class StateHolder<O, S> { +@@ -149,7 +178,11 @@ public abstract class StateHolder<O, S> { } public Map<Property<?>, Comparable<?>> getValues() { @@ -31510,9 +31014,9 @@ index 422b364764e0df16ca250b4939d7b226e69c0840..815ee11aa5ed3448ff255e9c36d76947 + // Paper end - optimise blockstate property access } - protected static <O, S extends StateHolder<O, S>> Codec<S> codec(Codec<O> codec, Function<O, S> ownerToStateFunction) { + protected static <O, S extends StateHolder<O, S>> Codec<S> codec(Codec<O> propertyMap, Function<O, S> holderFunction) { diff --git a/net/minecraft/world/level/block/state/properties/BooleanProperty.java b/net/minecraft/world/level/block/state/properties/BooleanProperty.java -index ea76aa490358e9e1d13350ba0ea246ec2c423894..98058505d36baf74008da08339afc196713b14a7 100644 +index 40c83ff614169be8ab988f3ab476eca93acee28d..654f14e0fd1920ec94300649719c2460918899e2 100644 --- a/net/minecraft/world/level/block/state/properties/BooleanProperty.java +++ b/net/minecraft/world/level/block/state/properties/BooleanProperty.java @@ -3,13 +3,23 @@ package net.minecraft.world.level.block.state.properties; @@ -31541,7 +31045,7 @@ index ea76aa490358e9e1d13350ba0ea246ec2c423894..98058505d36baf74008da08339afc196 @Override diff --git a/net/minecraft/world/level/block/state/properties/EnumProperty.java b/net/minecraft/world/level/block/state/properties/EnumProperty.java -index 85a197232be9377c0313ec00e8f935551e2c60e0..30b2fce9e47ffcc3de1542b1d0f073f5640127a7 100644 +index c56728863a084a5e1f6e6d9489d00bb0c83af168..1d785b7bb046ef291342efa3ede6cdeb460f12fb 100644 --- a/net/minecraft/world/level/block/state/properties/EnumProperty.java +++ b/net/minecraft/world/level/block/state/properties/EnumProperty.java @@ -10,11 +10,39 @@ import java.util.function.Predicate; @@ -31582,8 +31086,8 @@ index 85a197232be9377c0313ec00e8f935551e2c60e0..30b2fce9e47ffcc3de1542b1d0f073f5 + } + // Paper end - optimise blockstate property access + - private EnumProperty(String name, Class<T> type, List<T> values) { - super(name, type); + private EnumProperty(String name, Class<T> clazz, List<T> values) { + super(name, clazz); if (values.isEmpty()) { @@ -37,6 +65,7 @@ public final class EnumProperty<T extends Enum<T> & StringRepresentable> extends @@ -31594,7 +31098,7 @@ index 85a197232be9377c0313ec00e8f935551e2c60e0..30b2fce9e47ffcc3de1542b1d0f073f5 @Override diff --git a/net/minecraft/world/level/block/state/properties/IntegerProperty.java b/net/minecraft/world/level/block/state/properties/IntegerProperty.java -index 55a87592a99105dbf57b26fb6ccba695295fce24..986365acc9983331a7982ea2e1eac2b0efe1506d 100644 +index 28a15908420cb239c317d58f7e3a1df3c6278b33..b7543eb5a8f87bc7bd275ed9d46a68072c1e57b5 100644 --- a/net/minecraft/world/level/block/state/properties/IntegerProperty.java +++ b/net/minecraft/world/level/block/state/properties/IntegerProperty.java @@ -5,11 +5,33 @@ import java.util.List; @@ -31641,7 +31145,7 @@ index 55a87592a99105dbf57b26fb6ccba695295fce24..986365acc9983331a7982ea2e1eac2b0 @Override diff --git a/net/minecraft/world/level/block/state/properties/Property.java b/net/minecraft/world/level/block/state/properties/Property.java -index fcf04c5c58ff35d38c5bf0df562ae2f8dc98a0ee..0b116160924300a9d62ad5948bfaf276f0386e4d 100644 +index 92350434746f06bbf4a161c6bc42602de7b45220..1c24f38d21da1be9740512981f219924c5d3cf76 100644 --- a/net/minecraft/world/level/block/state/properties/Property.java +++ b/net/minecraft/world/level/block/state/properties/Property.java @@ -10,7 +10,7 @@ import java.util.stream.Stream; @@ -31685,15 +31189,15 @@ index fcf04c5c58ff35d38c5bf0df562ae2f8dc98a0ee..0b116160924300a9d62ad5948bfaf276 + public abstract int moonrise$getIdFor(final T value); + // Paper end - optimise blockstate property access + - protected Property(String name, Class<T> type) { - this.clazz = type; + protected Property(String name, Class<T> clazz) { + this.clazz = clazz; this.name = name; + this.id = ID_GENERATOR.getAndIncrement(); // Paper - optimise blockstate property access } public Property.Value<T> value(T value) { diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java -index 9d240aa87101662480cdd510839e017aa9c58fcd..f87abb22dd161b2b74401086de80dc95c9ac2dbb 100644 +index bc688ad1097ef4159dfc5f96d963a9fa63262e20..6e0210f32c679e3a33256cb05dc282f2e8b7d856 100644 --- a/net/minecraft/world/level/chunk/ChunkAccess.java +++ b/net/minecraft/world/level/chunk/ChunkAccess.java @@ -57,7 +57,7 @@ import net.minecraft.world.ticks.SavedTick; @@ -31702,10 +31206,10 @@ index 9d240aa87101662480cdd510839e017aa9c58fcd..f87abb22dd161b2b74401086de80dc95 -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(); -@@ -77,7 +77,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh + private static final LongSet EMPTY_REFERENCE_SET = new LongOpenHashSet(); +@@ -75,7 +75,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh @Nullable protected BlendingData blendingData; public final Map<Heightmap.Types, Heightmap> heightmaps = Maps.newEnumMap(Heightmap.Types.class); @@ -31714,9 +31218,9 @@ index 9d240aa87101662480cdd510839e017aa9c58fcd..f87abb22dd161b2b74401086de80dc95 private final Map<Structure, StructureStart> structureStarts = Maps.newHashMap(); private final Map<Structure, LongSet> structuresRefences = Maps.newHashMap(); protected final Map<BlockPos, CompoundTag> pendingBlockEntities = Maps.newHashMap(); -@@ -90,6 +90,57 @@ 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); +@@ -88,6 +88,57 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh // CraftBukkit end + public final Registry<Biome> biomeRegistry; // CraftBukkit + // Paper start - rewrite chunk system + private volatile ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] blockNibbles; @@ -31769,22 +31273,22 @@ index 9d240aa87101662480cdd510839e017aa9c58fcd..f87abb22dd161b2b74401086de80dc95 + private final int maxSection; + // Paper end - get block chunk optimisation + - public ChunkAccess(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor heightLimitView, Registry<Biome> 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 -@@ -99,7 +150,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh + public ChunkAccess( + ChunkPos chunkPos, + UpgradeData upgradeData, +@@ -105,7 +156,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh this.inhabitedTime = inhabitedTime; - this.postProcessing = new ShortList[heightLimitView.getSectionsCount()]; + this.postProcessing = new ShortList[levelHeightAccessor.getSectionsCount()]; this.blendingData = blendingData; -- this.skyLightSources = new ChunkSkyLightSources(heightLimitView); +- this.skyLightSources = new ChunkSkyLightSources(levelHeightAccessor); + // Paper - rewrite chunk system - if (sectionArray != null) { - if (this.sections.length == sectionArray.length) { - System.arraycopy(sectionArray, 0, this.sections, 0, this.sections.length); -@@ -111,6 +162,16 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh + if (sections != null) { + if (this.sections.length == sections.length) { + System.arraycopy(sections, 0, this.sections, 0, this.sections.length); +@@ -116,6 +167,16 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh + this.replaceMissingSections(biomeRegistry, this.sections); // Paper - Anti-Xray - make it a non-static method - // CraftBukkit start - this.biomeRegistry = biomeRegistry; + this.biomeRegistry = biomeRegistry; // Craftbukkit + // Paper start - rewrite chunk system + if (!((Object)this instanceof ImposterProtoChunk)) { + this.starlight$setBlockNibbles(ca.spottedleaf.moonrise.patches.starlight.light.StarLightEngine.getFilledEmptyLight(heightLimitView)); @@ -31796,30 +31300,26 @@ index 9d240aa87101662480cdd510839e017aa9c58fcd..f87abb22dd161b2b74401086de80dc95 + this.maxSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxSection(levelHeightAccessor); + // Paper end - get block chunk optimisation } - public final Registry<Biome> biomeRegistry; - // CraftBukkit end -@@ -457,22 +518,22 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh + + private void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sections) { // Paper - Anti-Xray - make it a non-static method +@@ -442,18 +503,22 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh @Override - public Holder<Biome> getNoiseBiome(int biomeX, int biomeY, int biomeZ) { + public Holder<Biome> getNoiseBiome(int x, int y, int z) { - try { -- 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)); -- -- return this.sections[k1].getNoiseBiome(biomeX & 3, j1 & 3, biomeZ & 3); -- } catch (Throwable throwable) { -- CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting biome"); -- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Biome being got"); -- -- crashreportsystemdetails.setDetail("Location", () -> { -- return CrashReportCategory.formatLocation(this, biomeX, biomeY, biomeZ); -- }); -- throw new ReportedException(crashreport); +- int quartPosMinY = QuartPos.fromBlock(this.getMinY()); +- int i = quartPosMinY + QuartPos.fromBlock(this.getHeight()) - 1; +- int i1 = Mth.clamp(y, quartPosMinY, i); +- int sectionIndex = this.getSectionIndex(QuartPos.toBlock(i1)); +- return this.sections[sectionIndex].getNoiseBiome(x & 3, i1 & 3, z & 3); +- } catch (Throwable var8) { +- CrashReport crashReport = CrashReport.forThrowable(var8, "Getting biome"); +- CrashReportCategory crashReportCategory = crashReport.addCategory("Biome being got"); +- crashReportCategory.setDetail("Location", () -> CrashReportCategory.formatLocation(this, x, y, z)); +- throw new ReportedException(crashReport); + // Paper start - get block chunk optimisation -+ int sectionY = (biomeY >> 2) - this.minSection; -+ int rel = biomeY & 3; ++ int sectionY = (y >> 2) - this.minSection; ++ int rel = y & 3; + + final LevelChunkSection[] sections = this.sections; + @@ -31831,12 +31331,12 @@ index 9d240aa87101662480cdd510839e017aa9c58fcd..f87abb22dd161b2b74401086de80dc95 + rel = 3; } + -+ return sections[sectionY].getNoiseBiome(biomeX & 3, rel, biomeZ & 3); ++ return sections[sectionY].getNoiseBiome(x & 3, rel, z & 3); + // Paper end - get block chunk optimisation } - // CraftBukkit start -@@ -529,12 +590,12 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh + public void setBiome(int i, int j, int k, Holder<Biome> biome) { +@@ -507,12 +572,12 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh } public void initializeLightSources() { @@ -31850,31 +31350,31 @@ index 9d240aa87101662480cdd510839e017aa9c58fcd..f87abb22dd161b2b74401086de80dc95 + return null; // Paper - rewrite chunk system } - public static record PackedTicks(List<SavedTick<Block>> blocks, List<SavedTick<Fluid>> fluids) { + public record PackedTicks(List<SavedTick<Block>> blocks, List<SavedTick<Fluid>> fluids) { diff --git a/net/minecraft/world/level/chunk/ChunkGenerator.java b/net/minecraft/world/level/chunk/ChunkGenerator.java -index ca6928f959eb63ac9183ba6c95738609839a7d32..e0cb360ece042c4fc6aa0d10106923fe25288f5c 100644 +index 89f027f0edf2ca59966efe209e567108665cbe0c..7944c2bb854ee52a55d7c54e5f814e87d709e70e 100644 --- a/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -120,7 +120,7 @@ public abstract class ChunkGenerator { +@@ -116,7 +116,7 @@ public abstract class ChunkGenerator { return CompletableFuture.supplyAsync(() -> { - chunk.fillBiomesFromNoise(this.biomeSource, noiseConfig.sampler()); + chunk.fillBiomesFromNoise(this.biomeSource, randomState.sampler()); return chunk; - }, 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); + public abstract void applyCarvers( @@ -315,7 +315,7 @@ public abstract class ChunkGenerator { - return Pair.of(placement.getLocatePos(pos), holder); - } - -- ChunkAccess ichunkaccess = world.getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_STARTS); -+ ChunkAccess ichunkaccess = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader)world).moonrise$syncLoadNonFull(pos.x, pos.z, ChunkStatus.STRUCTURE_STARTS); // Paper - rewrite chunk system + return Pair.of(placement.getLocatePos(chunkPos), holder); + } - structurestart = structureAccessor.getStartForStructure(SectionPos.bottomOf(ichunkaccess), (Structure) holder.value(), ichunkaccess); - } while (structurestart == null); +- ChunkAccess chunk = level.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_STARTS); ++ ChunkAccess chunk = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader)level).moonrise$syncLoadNonFull(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_STARTS); // Paper - rewrite chunk system + StructureStart startForStructure = structureManager.getStartForStructure(SectionPos.bottomOf(chunk), holder.value(), chunk); + if (startForStructure != null && startForStructure.isValid() && (!skipKnownStructures || tryAddReference(structureManager, startForStructure))) { + return Pair.of(placement.getLocatePos(startForStructure.getChunkPos()), holder); diff --git a/net/minecraft/world/level/chunk/EmptyLevelChunk.java b/net/minecraft/world/level/chunk/EmptyLevelChunk.java -index dcc0acd259920463a4464213b9a5e793603852f9..ef4161884574d3d137e12591d983dc95a960cb19 100644 +index ec128412e4a0d3d21e3b6abea8cd06c03656f00c..07b7e82c7d24f52c0251e09195451841d47883c9 100644 --- a/net/minecraft/world/level/chunk/EmptyLevelChunk.java +++ b/net/minecraft/world/level/chunk/EmptyLevelChunk.java @@ -13,7 +13,7 @@ import net.minecraft.world.level.block.state.BlockState; @@ -31885,9 +31385,9 @@ index dcc0acd259920463a4464213b9a5e793603852f9..ef4161884574d3d137e12591d983dc95 +public class EmptyLevelChunk extends LevelChunk implements ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk { // Paper - rewrite chunk system private final Holder<Biome> biome; - public EmptyLevelChunk(Level world, ChunkPos pos, Holder<Biome> biomeEntry) { + public EmptyLevelChunk(Level level, ChunkPos pos, Holder<Biome> biome) { @@ -21,6 +21,40 @@ public class EmptyLevelChunk extends LevelChunk { - this.biome = biomeEntry; + this.biome = biome; } + // Paper start - rewrite chunk system @@ -31928,7 +31428,7 @@ index dcc0acd259920463a4464213b9a5e793603852f9..ef4161884574d3d137e12591d983dc95 public BlockState getBlockState(BlockPos pos) { return Blocks.VOID_AIR.defaultBlockState(); diff --git a/net/minecraft/world/level/chunk/HashMapPalette.java b/net/minecraft/world/level/chunk/HashMapPalette.java -index 98dbeaf8bde15940e5b5d5d1f13fd4bb32f0a10d..7beea075b5a7ef738a4ac0558b99f4c5708f2c4a 100644 +index 7cd5d42e0c28033ee80f18bd0031ed1241fb7aae..718d00a386f32423db9f6d6c95b4a20698b976f5 100644 --- a/net/minecraft/world/level/chunk/HashMapPalette.java +++ b/net/minecraft/world/level/chunk/HashMapPalette.java @@ -8,12 +8,19 @@ import net.minecraft.network.FriendlyByteBuf; @@ -31949,11 +31449,11 @@ index 98dbeaf8bde15940e5b5d5d1f13fd4bb32f0a10d..7beea075b5a7ef738a4ac0558b99f4c5 + } + // Paper end - optimise palette reads + - public HashMapPalette(IdMap<T> idList, int bits, PaletteResize<T> listener, List<T> entries) { - this(idList, bits, listener); - entries.forEach(this.values::add); + public HashMapPalette(IdMap<T> registry, int bits, PaletteResize<T> resizeHandler, List<T> values) { + this(registry, bits, resizeHandler); + values.forEach(this.values::add); diff --git a/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/net/minecraft/world/level/chunk/ImposterProtoChunk.java -index f38700e5fbeeb8a913272d4464b8aa325d511dac..1eb8022f3e31603322e6c56516304afc9a11bbec 100644 +index e7c0f4da8508fbca467326f475668d66454d7b77..41856c98d97e7eb0782f8e441b9a269a47ed1914 100644 --- a/net/minecraft/world/level/chunk/ImposterProtoChunk.java +++ b/net/minecraft/world/level/chunk/ImposterProtoChunk.java @@ -30,7 +30,7 @@ import net.minecraft.world.level.material.FluidState; @@ -31966,7 +31466,7 @@ index f38700e5fbeeb8a913272d4464b8aa325d511dac..1eb8022f3e31603322e6c56516304afc private final boolean allowWrites; @@ -46,6 +46,48 @@ public class ImposterProtoChunk extends ProtoChunk { - this.allowWrites = propagateToWrapped; + this.allowWrites = allowWrites; } + // Paper start - rewrite chunk system @@ -32015,34 +31515,19 @@ index f38700e5fbeeb8a913272d4464b8aa325d511dac..1eb8022f3e31603322e6c56516304afc @Override public BlockEntity getBlockEntity(BlockPos pos) { diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index 0ade64bbdec563e555c981cee2208e6c72afe249..134d63076f231791988e67a5bdf191005112080b 100644 +index d1d0dc13eecb0e0eb3a7839b570a5fe7f62f3fba..72c0e031443ca42c2cfafddea9e04cfa4f93a0eb 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -55,7 +55,7 @@ import net.minecraft.world.ticks.LevelChunkTicks; +@@ -52,7 +52,7 @@ import net.minecraft.world.ticks.LevelChunkTicks; import net.minecraft.world.ticks.TickContainerAccess; import org.slf4j.Logger; -public class LevelChunk extends ChunkAccess { +public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk, ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk, ca.spottedleaf.moonrise.patches.getblock.GetBlockChunk { // Paper - rewrite chunk system // Paper - get block chunk optimisation - static final Logger LOGGER = LogUtils.getLogger(); private static final TickingBlockEntity NULL_TICKER = new TickingBlockEntity() { -@@ -114,6 +114,14 @@ public class LevelChunk extends ChunkAccess { - this.postLoad = entityLoader; - this.blockTicks = blockTickScheduler; - this.fluidTicks = fluidTickScheduler; -+ // Paper start - get block chunk optimisation -+ this.minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(level); -+ this.maxSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxSection(level); -+ -+ final boolean empty = ((Object)this instanceof EmptyLevelChunk); -+ this.debug = !empty && this.level.isDebug(); -+ this.defaultBlockState = empty ? VOID_AIR_BLOCKSTATE : AIR_BLOCKSTATE; -+ // Paper end - get block chunk optimisation - } - - // CraftBukkit start -@@ -124,6 +132,39 @@ public class LevelChunk extends ChunkAccess { + @Override +@@ -93,6 +93,39 @@ public class LevelChunk extends ChunkAccess { // Paper start boolean loadedTicketLevel; // Paper end @@ -32080,19 +31565,34 @@ index 0ade64bbdec563e555c981cee2208e6c72afe249..134d63076f231791988e67a5bdf19100 + } + // Paper end - get block chunk optimisation - public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor entityLoader) { - this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), entityLoader, protoChunk.getBlendingData()); -@@ -157,13 +198,19 @@ public class LevelChunk extends ChunkAccess { + public LevelChunk(Level level, ChunkPos pos) { + this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null); +@@ -122,6 +155,14 @@ public class LevelChunk extends ChunkAccess { + this.postLoad = postLoad; + this.blockTicks = blockTicks; + this.fluidTicks = fluidTicks; ++ // Paper start - get block chunk optimisation ++ this.minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(level); ++ this.maxSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxSection(level); ++ ++ final boolean empty = ((Object)this instanceof EmptyLevelChunk); ++ this.debug = !empty && this.level.isDebug(); ++ this.defaultBlockState = empty ? VOID_AIR_BLOCKSTATE : AIR_BLOCKSTATE; ++ // Paper end - get block chunk optimisation + } + + public LevelChunk(ServerLevel level, ProtoChunk chunk, @Nullable LevelChunk.PostLoadProcessor postLoad) { +@@ -159,13 +200,19 @@ public class LevelChunk extends ChunkAccess { } } -- this.skyLightSources = protoChunk.skyLightSources; +- this.skyLightSources = chunk.skyLightSources; + // Paper - rewrite chunk system - this.setLightCorrect(protoChunk.isLightCorrect()); + this.setLightCorrect(chunk.isLightCorrect()); 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. + this.persistentDataContainer = chunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading. // CraftBukkit end + // Paper start - rewrite chunk system + this.starlight$setBlockNibbles(((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)protoChunk).starlight$getBlockNibbles()); @@ -32103,16 +31603,16 @@ index 0ade64bbdec563e555c981cee2208e6c72afe249..134d63076f231791988e67a5bdf19100 } public void setUnsavedListener(LevelChunk.UnsavedListener unsavedListener) { -@@ -366,7 +413,7 @@ public class LevelChunk extends ChunkAccess { - ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.push("updateSkyLightSources"); -- this.skyLightSources.update(this, j, i, l); +@@ -341,7 +388,7 @@ public class LevelChunk extends ChunkAccess { + if (LightEngine.hasDifferentLightProperties(blockState, state)) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("updateSkyLightSources"); +- this.skyLightSources.update(this, i, y, i2); + // Paper - rewrite chunk system - gameprofilerfiller.popPush("queueCheckLight"); - this.level.getChunkSource().getLightEngine().checkBlock(blockposition); - gameprofilerfiller.pop(); -@@ -632,11 +679,12 @@ public class LevelChunk extends ChunkAccess { + profilerFiller.popPush("queueCheckLight"); + this.level.getChunkSource().getLightEngine().checkBlock(pos); + profilerFiller.pop(); +@@ -573,11 +620,12 @@ public class LevelChunk extends ChunkAccess { // CraftBukkit start public void loadCallback() { @@ -32126,7 +31626,7 @@ index 0ade64bbdec563e555c981cee2208e6c72afe249..134d63076f231791988e67a5bdf19100 if (server != null) { /* * If it's a new world, the first few chunks are generated inside -@@ -645,6 +693,7 @@ public class LevelChunk extends ChunkAccess { +@@ -586,6 +634,7 @@ public class LevelChunk extends ChunkAccess { */ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration)); @@ -32134,7 +31634,7 @@ index 0ade64bbdec563e555c981cee2208e6c72afe249..134d63076f231791988e67a5bdf19100 if (this.needsDecoration) { this.needsDecoration = false; -@@ -671,13 +720,15 @@ public class LevelChunk extends ChunkAccess { +@@ -612,13 +661,15 @@ public class LevelChunk extends ChunkAccess { } public void unloadCallback() { @@ -32152,7 +31652,7 @@ index 0ade64bbdec563e555c981cee2208e6c72afe249..134d63076f231791988e67a5bdf19100 // Paper start this.loadedTicketLevel = false; // Paper end -@@ -685,8 +736,31 @@ public class LevelChunk extends ChunkAccess { +@@ -626,8 +677,31 @@ public class LevelChunk extends ChunkAccess { @Override public boolean isUnsaved() { @@ -32185,7 +31685,7 @@ index 0ade64bbdec563e555c981cee2208e6c72afe249..134d63076f231791988e67a5bdf19100 // CraftBukkit end public boolean isEmpty() { -@@ -794,6 +868,7 @@ public class LevelChunk extends ChunkAccess { +@@ -706,6 +780,7 @@ public class LevelChunk extends ChunkAccess { this.pendingBlockEntities.clear(); this.upgradeData.upgrade(this); @@ -32194,7 +31694,7 @@ index 0ade64bbdec563e555c981cee2208e6c72afe249..134d63076f231791988e67a5bdf19100 @Nullable diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java -index 3dab36d00ea48101807ba40c7a7358b7eed12747..e4ae25c83ab9dd1aaa530a5456275ef63cdb8511 100644 +index fc21c3268c4b4fda2933d71f0913db28e3796653..2ff691bcd32f587e8add2d8eda7e7339ccbde6e8 100644 --- a/net/minecraft/world/level/chunk/LevelChunkSection.java +++ b/net/minecraft/world/level/chunk/LevelChunkSection.java @@ -13,7 +13,7 @@ import net.minecraft.world.level.block.Blocks; @@ -32203,10 +31703,10 @@ index 3dab36d00ea48101807ba40c7a7358b7eed12747..e4ae25c83ab9dd1aaa530a5456275ef6 -public class LevelChunkSection { +public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection { // Paper - block counting - public static final int SECTION_WIDTH = 16; public static final int SECTION_HEIGHT = 16; -@@ -25,6 +25,30 @@ public class LevelChunkSection { + public static final int SECTION_SIZE = 4096; +@@ -24,6 +24,30 @@ public class LevelChunkSection { public final PalettedContainer<BlockState> states; private PalettedContainer<Holder<Biome>> biomes; // CraftBukkit - read/write @@ -32237,7 +31737,7 @@ index 3dab36d00ea48101807ba40c7a7358b7eed12747..e4ae25c83ab9dd1aaa530a5456275ef6 private LevelChunkSection(LevelChunkSection section) { this.nonEmptyBlockCount = section.nonEmptyBlockCount; this.tickingBlockCount = section.tickingBlockCount; -@@ -67,6 +91,45 @@ public class LevelChunkSection { +@@ -69,6 +93,45 @@ public class LevelChunkSection { return this.setBlockState(x, y, z, state, true); } @@ -32280,37 +31780,48 @@ index 3dab36d00ea48101807ba40c7a7358b7eed12747..e4ae25c83ab9dd1aaa530a5456275ef6 + } + // Paper end - block counting + - public BlockState setBlockState(int x, int y, int z, BlockState state, boolean lock) { - BlockState iblockdata1; - + public BlockState setBlockState(int x, int y, int z, BlockState state, boolean useLocks) { + BlockState blockState; + if (useLocks) { @@ -86,7 +149,7 @@ public class LevelChunkSection { } } -- if (!fluid.isEmpty()) { -+ if (!!fluid.isRandomlyTicking()) { // Paper - block counting - --this.tickingFluidCount; +- if (!fluidState.isEmpty()) { ++ if (!!fluidState.isRandomlyTicking()) { // Paper - block counting + this.tickingFluidCount--; } @@ -97,10 +160,12 @@ public class LevelChunkSection { } } -- if (!fluid1.isEmpty()) { -+ if (!!fluid1.isRandomlyTicking()) { // Paper - block counting - ++this.tickingFluidCount; +- if (!fluidState1.isEmpty()) { ++ if (!!fluidState1.isRandomlyTicking()) { // Paper - block counting + this.tickingFluidCount++; } -+ this.updateBlockCallback(x, y, z, state, iblockdata1); // Paper - block counting ++ this.updateBlockCallback(x, y, z, state, blockState); // Paper - block counting + - return iblockdata1; + return blockState; } -@@ -121,40 +186,70 @@ public class LevelChunkSection { +@@ -121,35 +186,70 @@ public class LevelChunkSection { } public void recalcBlockCounts() { -- class a implements PalettedContainer.CountConsumer<BlockState> { +- class BlockCounter implements PalettedContainer.CountConsumer<BlockState> { +- public int nonEmptyBlockCount; +- public int tickingBlockCount; +- public int tickingFluidCount; +- +- @Override +- public void accept(BlockState state, int count) { +- FluidState fluidState = state.getFluidState(); +- if (!state.isAir()) { +- this.nonEmptyBlockCount += count; +- if (state.isRandomlyTicking()) { +- this.tickingBlockCount += count; + // Paper start - block counting + // reset, then recalculate + this.nonEmptyBlockCount = (short)0; @@ -32338,13 +31849,9 @@ index 3dab36d00ea48101807ba40c7a7358b7eed12747..e4ae25c83ab9dd1aaa530a5456275ef6 + final int paletteIdx = entry.getIntKey(); + final it.unimi.dsi.fastutil.shorts.ShortArrayList coordinates = entry.getValue(); + final int paletteCount = coordinates.size(); - -- public int nonEmptyBlockCount; -- public int tickingBlockCount; -- public int tickingFluidCount; ++ + final BlockState state = palette.valueFor(paletteIdx); - -- a(final LevelChunkSection chunksection) {} ++ + if (state.isAir()) { + continue; + } @@ -32359,49 +31866,43 @@ index 3dab36d00ea48101807ba40c7a7358b7eed12747..e4ae25c83ab9dd1aaa530a5456275ef6 + final int rawLen = raw.length; + + final ca.spottedleaf.moonrise.common.list.ShortList tickingBlocks = this.tickingBlocks; - -- public void accept(BlockState iblockdata, int i) { -- FluidState fluid = iblockdata.getFluidState(); ++ + tickingBlocks.setMinCapacity(Math.min((rawLen + tickingBlocks.size()) * 3 / 2, 16*16*16)); - -- if (!iblockdata.isAir()) { -- this.nonEmptyBlockCount += i; -- if (iblockdata.isRandomlyTicking()) { -- this.tickingBlockCount += i; ++ + java.util.Objects.checkFromToIndex(0, paletteCount, raw.length); + for (int i = 0; i < paletteCount; ++i) { + tickingBlocks.add(raw[i]); } } +- if (!fluidState.isEmpty()) { +- this.nonEmptyBlockCount += count; +- if (fluidState.isRandomlyTicking()) { +- this.tickingFluidCount += count; + final FluidState fluid = state.getFluidState(); + - if (!fluid.isEmpty()) { -- this.nonEmptyBlockCount += i; ++ if (!fluid.isEmpty()) { + //this.nonEmptyBlockCount += count; // fix vanilla bug: make non-empty block count correct - if (fluid.isRandomlyTicking()) { -- this.tickingFluidCount += i; ++ if (fluid.isRandomlyTicking()) { + this.tickingFluidCount += (short)paletteCount; } } -- } } - -- a a0 = new a(this); -- -- this.states.count(a0); -- this.nonEmptyBlockCount = (short) a0.nonEmptyBlockCount; -- this.tickingBlockCount = (short) a0.tickingBlockCount; -- this.tickingFluidCount = (short) a0.tickingFluidCount; +- BlockCounter blockCounter = new BlockCounter(); +- this.states.count(blockCounter); +- this.nonEmptyBlockCount = (short)blockCounter.nonEmptyBlockCount; +- this.tickingBlockCount = (short)blockCounter.tickingBlockCount; +- this.tickingFluidCount = (short)blockCounter.tickingFluidCount; + // Paper end - block counting } public PalettedContainer<BlockState> getStates() { -@@ -172,6 +267,11 @@ public class LevelChunkSection { - - datapaletteblock.read(buf); - this.biomes = datapaletteblock; +@@ -166,6 +266,11 @@ public class LevelChunkSection { + PalettedContainer<Holder<Biome>> palettedContainer = this.biomes.recreate(); + palettedContainer.read(buffer); + this.biomes = palettedContainer; + // Paper start - block counting + this.isClient = true; + // force has special colliding blocks to be true @@ -32409,9 +31910,9 @@ index 3dab36d00ea48101807ba40c7a7358b7eed12747..e4ae25c83ab9dd1aaa530a5456275ef6 + // Paper end - block counting } - public void readBiomes(FriendlyByteBuf buf) { + public void readBiomes(FriendlyByteBuf buffer) { diff --git a/net/minecraft/world/level/chunk/LinearPalette.java b/net/minecraft/world/level/chunk/LinearPalette.java -index bc4d9452bbeb05a691fd285603e49491f41d3ad2..f8d9892970c9092f7cc84434d4fbf34354ce1195 100644 +index 5ae2f38dc613ac6129af49084980d064f14ff153..2073f6ff41aa570102621d183ee890b076267d54 100644 --- a/net/minecraft/world/level/chunk/LinearPalette.java +++ b/net/minecraft/world/level/chunk/LinearPalette.java @@ -7,13 +7,20 @@ import net.minecraft.network.FriendlyByteBuf; @@ -32433,11 +31934,11 @@ index bc4d9452bbeb05a691fd285603e49491f41d3ad2..f8d9892970c9092f7cc84434d4fbf343 + } + // Paper end - optimise palette reads + - private LinearPalette(IdMap<T> idList, int bits, PaletteResize<T> listener, List<T> list) { - this.registry = idList; + private LinearPalette(IdMap<T> registry, int bits, PaletteResize<T> resizeHandler, List<T> values) { + this.registry = registry; this.values = (T[])(new Object[1 << bits]); diff --git a/net/minecraft/world/level/chunk/Palette.java b/net/minecraft/world/level/chunk/Palette.java -index b8922e4a13df535cdc5701e893a6e460b33ff90d..100807f8b8337f56f49cdb818ccc75be2f08ecd1 100644 +index b4b973e453a093dcc04a6b7257883aa0065e2a89..a80b2e9dceea423180a9c390d1970317dff4f1b0 100644 --- a/net/minecraft/world/level/chunk/Palette.java +++ b/net/minecraft/world/level/chunk/Palette.java @@ -5,7 +5,7 @@ import java.util.function.Predicate; @@ -32446,23 +31947,23 @@ index b8922e4a13df535cdc5701e893a6e460b33ff90d..100807f8b8337f56f49cdb818ccc75be -public interface Palette<T> { +public interface Palette<T> extends ca.spottedleaf.moonrise.patches.fast_palette.FastPalette<T> { // Paper - optimise palette reads - int idFor(T object); + int idFor(T state); - boolean maybeHas(Predicate<T> predicate); + boolean maybeHas(Predicate<T> filter); diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java -index 69d6f203366df658e1ade55d917f0aa2b8a49be9..8b84bf2272556ac3321cbf16361d7f48a1cc6873 100644 +index a6028a54c75de068515e95913b21160ab4326985..f5da433050fd3060e0335d4002d520ebe8cd691f 100644 --- a/net/minecraft/world/level/chunk/PalettedContainer.java +++ b/net/minecraft/world/level/chunk/PalettedContainer.java @@ -29,7 +29,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer - private final PaletteResize<T> dummyPaletteResize = (newSize, added) -> 0; + private final PaletteResize<T> dummyPaletteResize = (bits, objectAdded) -> 0; public final IdMap<T> registry; private final T @org.jetbrains.annotations.Nullable [] presetValues; // Paper - Anti-Xray - Add preset values - private volatile PalettedContainer.Data<T> data; + public volatile PalettedContainer.Data<T> data; // Paper - optimise collisions - public private final PalettedContainer.Strategy strategy; - // private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused + //private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused -@@ -77,6 +77,33 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer +@@ -75,6 +75,33 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer ); } @@ -32494,9 +31995,9 @@ index 69d6f203366df658e1ade55d917f0aa2b8a49be9..8b84bf2272556ac3321cbf16361d7f48 + // Paper end - optimise palette reads + // Paper start - Anti-Xray - Add preset values - @Deprecated @io.papermc.paper.annotation.DoNotUse public PalettedContainer(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Configuration<T> dataProvider, BitStorage storage, List<T> paletteEntries) { this(idList, paletteProvider, dataProvider, storage, paletteEntries, null, null); } - public PalettedContainer( -@@ -113,6 +140,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer + @Deprecated @io.papermc.paper.annotation.DoNotUse + public PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values) { +@@ -109,6 +136,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer } } // Paper end @@ -32504,47 +32005,47 @@ index 69d6f203366df658e1ade55d917f0aa2b8a49be9..8b84bf2272556ac3321cbf16361d7f48 } // Paper start - Anti-Xray - Add preset values -@@ -122,6 +150,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer - this.registry = idList; - this.strategy = paletteProvider; +@@ -118,6 +146,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer + this.registry = registry; + this.strategy = strategy; this.data = data; + this.updateData(this.data); // Paper - optimise palette reads } - private PalettedContainer(PalettedContainer<T> container, T @org.jetbrains.annotations.Nullable [] presetValues) { // Paper - Anti-Xray - Add preset values -@@ -140,6 +169,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer - this.registry = idList; + private PalettedContainer(PalettedContainer<T> other, T @org.jetbrains.annotations.Nullable [] presetValues) { // Paper - Anti-Xray - Add preset values +@@ -139,6 +168,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer + this.registry = registry; this.data = this.createOrReuseData(null, 0); - this.data.palette.idFor(object); + this.data.palette.idFor(palette); + this.updateData(this.data); // Paper - optimise palette reads } - private PalettedContainer.Data<T> createOrReuseData(@Nullable PalettedContainer.Data<T> previousData, int bits) { -@@ -166,6 +196,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer - data2.copyFrom(data.palette, data.storage); - this.data = data2; + private PalettedContainer.Data<T> createOrReuseData(@Nullable PalettedContainer.Data<T> data, int id) { +@@ -163,6 +193,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer + this.data = data1; + // Paper start - Anti-Xray this.addPresetValues(); + this.updateData(this.data); // Paper - optimise palette reads - return object == null ? -1 : data2.palette.idFor(object); - // Paper end + return objectAdded == null ? -1 : data1.palette.idFor(objectAdded); } -@@ -198,9 +229,12 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer + private void addPresetValues() { +@@ -192,9 +223,12 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer } - private synchronized T getAndSet(int index, T value) { // Paper - synchronize -- int i = this.data.palette.idFor(value); -- int j = this.data.storage.getAndSet(index, i); -- return this.data.palette.valueFor(j); + private T getAndSet(int index, T state) { +- int i = this.data.palette.idFor(state); +- int andSet = this.data.storage.getAndSet(index, i); +- return this.data.palette.valueFor(andSet); + // Paper start - optimise palette reads -+ final int paletteIdx = this.data.palette.idFor(value); ++ final int paletteIdx = this.data.palette.idFor(state); + final PalettedContainer.Data<T> data = this.data; + final int prev = data.storage.getAndSet(index, paletteIdx); + return this.readPalette(data, prev); + // Paper end - optimise palette reads } - public void set(int x, int y, int z, T value) { -@@ -223,9 +257,11 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer + public synchronized void set(int x, int y, int z, T state) { // Paper - synchronize +@@ -217,9 +251,11 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer return this.get(this.strategy.getIndex(x, y, z)); } @@ -32559,19 +32060,19 @@ index 69d6f203366df658e1ade55d917f0aa2b8a49be9..8b84bf2272556ac3321cbf16361d7f48 } @Override -@@ -246,6 +282,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer - buf.readLongArray(data.storage.getRaw()); +@@ -240,6 +276,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer + buffer.readLongArray(data.storage.getRaw()); this.data = data; this.addPresetValues(); // Paper - Anti-Xray - Add preset values (inefficient, but this isn't used by the server) + this.updateData(this.data); // Paper - optimise palette reads } finally { this.release(); } -@@ -394,7 +431,44 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer - void accept(T object, int count); +@@ -390,7 +427,44 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer + void accept(T state, int count); } -- static record Data<T>(PalettedContainer.Configuration<T> configuration, BitStorage storage, Palette<T> palette) { +- record Data<T>(PalettedContainer.Configuration<T> configuration, BitStorage storage, Palette<T> palette) { + // Paper start - optimise palette reads + public static final class Data<T> implements ca.spottedleaf.moonrise.patches.fast_palette.FastPaletteData<T> { + @@ -32610,24 +32111,24 @@ index 69d6f203366df658e1ade55d917f0aa2b8a49be9..8b84bf2272556ac3321cbf16361d7f48 + } + // Paper end - optimise palette reads + - public void copyFrom(Palette<T> palette, BitStorage storage) { - for (int i = 0; i < storage.getSize(); i++) { - T object = palette.valueFor(storage.get(i)); + public void copyFrom(Palette<T> palette, BitStorage bitStorage) { + for (int i = 0; i < bitStorage.getSize(); i++) { + T object = palette.valueFor(bitStorage.get(i)); diff --git a/net/minecraft/world/level/chunk/ProtoChunk.java b/net/minecraft/world/level/chunk/ProtoChunk.java -index 15e14f5d006389c823fa6baf8c1a4f22804d4aa8..759adee51bad99bd4bbee4f44247e8c8486cfbd6 100644 +index 8c333d7f390d823a7c7f303e2f444f52ec16f799..e66239e2da91bd3ddf358d239be796719c0da327 100644 --- a/net/minecraft/world/level/chunk/ProtoChunk.java +++ b/net/minecraft/world/level/chunk/ProtoChunk.java -@@ -149,7 +149,7 @@ public class ProtoChunk extends ChunkAccess { +@@ -151,7 +151,7 @@ public class ProtoChunk extends ChunkAccess { } if (LightEngine.hasDifferentLightProperties(blockState, state)) { -- this.skyLightSources.update(this, m, j, o); +- this.skyLightSources.update(this, relativeBlockPosX, y, relativeBlockPosZ); + // Paper - rewrite chunk system this.lightEngine.checkBlock(pos); } } diff --git a/net/minecraft/world/level/chunk/SingleValuePalette.java b/net/minecraft/world/level/chunk/SingleValuePalette.java -index a45e6410600afc5464e5d29932c193786ce0a6fb..a1ba68c95c2cdebdc0d7782cce7895529918073c 100644 +index bc84910dbc688331efaea76972a6625014ff76f5..2ffae24b0cb1a20c7d5a8520f1b5197c2cedea11 100644 --- a/net/minecraft/world/level/chunk/SingleValuePalette.java +++ b/net/minecraft/world/level/chunk/SingleValuePalette.java @@ -8,12 +8,24 @@ import net.minecraft.network.FriendlyByteBuf; @@ -32653,16 +32154,16 @@ index a45e6410600afc5464e5d29932c193786ce0a6fb..a1ba68c95c2cdebdc0d7782cce789552 + } + // Paper end - optimise palette reads + - public SingleValuePalette(IdMap<T> idList, PaletteResize<T> listener, List<T> entries) { - this.registry = idList; - this.resizeHandler = listener; + public SingleValuePalette(IdMap<T> registry, PaletteResize<T> resizeHandler, List<T> value) { + this.registry = registry; + this.resizeHandler = resizeHandler; @@ -33,6 +45,11 @@ public class SingleValuePalette<T> implements Palette<T> { - return this.resizeHandler.onResize(1, object); + return this.resizeHandler.onResize(1, state); } else { - this.value = object; + this.value = state; + // Paper start - optimise palette reads + if (this.rawPalette != null) { -+ this.rawPalette[0] = object; ++ this.rawPalette[0] = state; + } + // Paper end - optimise palette reads return 0; @@ -32670,8 +32171,8 @@ index a45e6410600afc5464e5d29932c193786ce0a6fb..a1ba68c95c2cdebdc0d7782cce789552 } @@ -58,6 +75,11 @@ public class SingleValuePalette<T> implements Palette<T> { @Override - public void read(FriendlyByteBuf buf) { - this.value = this.registry.byIdOrThrow(buf.readVarInt()); + public void read(FriendlyByteBuf buffer) { + this.value = this.registry.byIdOrThrow(buffer.readVarInt()); + // Paper start - optimise palette reads + if (this.rawPalette != null) { + this.rawPalette[0] = this.value; @@ -32681,7 +32182,7 @@ index a45e6410600afc5464e5d29932c193786ce0a6fb..a1ba68c95c2cdebdc0d7782cce789552 @Override diff --git a/net/minecraft/world/level/chunk/status/ChunkPyramid.java b/net/minecraft/world/level/chunk/status/ChunkPyramid.java -index b1058bf0dcda544a074f4d3772d7899b94f98927..b7bf82f6b6023bd628d3e7ea84d2d6755a0d931a 100644 +index 9c6f4aa173fa25f9c8a3852d91a4585e069236b6..b14001afe0bf841dac7d0a1d1568fd10f6086237 100644 --- a/net/minecraft/world/level/chunk/status/ChunkPyramid.java +++ b/net/minecraft/world/level/chunk/status/ChunkPyramid.java @@ -54,7 +54,7 @@ public record ChunkPyramid(ImmutableList<ChunkStep> steps) { @@ -32694,7 +32195,7 @@ index b1058bf0dcda544a074f4d3772d7899b94f98927..b7bf82f6b6023bd628d3e7ea84d2d675 .step(ChunkStatus.FULL, builder -> builder.setTask(ChunkStatusTasks::full)) .build(); diff --git a/net/minecraft/world/level/chunk/status/ChunkStatus.java b/net/minecraft/world/level/chunk/status/ChunkStatus.java -index 4f84ff9cdb3303251e035a12ce9d8b9a0b58f46e..d80b7d555e02d1d4b82945373d383eaedbf4b976 100644 +index 7a64b00ff31d1273d0b0b9a3cfd43808c88ef46a..c9d8a1c0a75c34ccd9f5cead02cccd776276f3cb 100644 --- a/net/minecraft/world/level/chunk/status/ChunkStatus.java +++ b/net/minecraft/world/level/chunk/status/ChunkStatus.java @@ -11,7 +11,7 @@ import net.minecraft.resources.ResourceLocation; @@ -32706,7 +32207,7 @@ index 4f84ff9cdb3303251e035a12ce9d8b9a0b58f46e..d80b7d555e02d1d4b82945373d383eae public static final int MAX_STRUCTURE_DISTANCE = 8; private static final EnumSet<Heightmap.Types> WORLDGEN_HEIGHTMAPS = EnumSet.of(Heightmap.Types.OCEAN_FLOOR_WG, Heightmap.Types.WORLD_SURFACE_WG); public static final EnumSet<Heightmap.Types> FINAL_HEIGHTMAPS = EnumSet.of( -@@ -51,8 +51,68 @@ public class ChunkStatus { +@@ -51,8 +51,70 @@ public class ChunkStatus { return list; } @@ -32764,50 +32265,52 @@ index 4f84ff9cdb3303251e035a12ce9d8b9a0b58f46e..d80b7d555e02d1d4b82945373d383eae + // Paper end - rewrite chunk system + @VisibleForTesting - protected ChunkStatus(@Nullable ChunkStatus previous, EnumSet<Heightmap.Types> heightMapTypes, ChunkType chunkType) { + protected ChunkStatus(@Nullable ChunkStatus parent, EnumSet<Heightmap.Types> heightmapsAfter, ChunkType chunkType) { ++ // Paper start - rewrite chunk system + this.isParallelCapable = false; + this.writeRadius = -1; + this.nextStatus = (ChunkStatus)(Object)this; -+ if (previous != null) { -+ previous.nextStatus = (ChunkStatus)(Object)this; ++ if (parent != null) { ++ parent.nextStatus = (ChunkStatus)(Object)this; + } + this.warnedAboutNoImmediateComplete = new java.util.concurrent.atomic.AtomicBoolean(); - this.parent = previous == null ? this : previous; ++ // Paper end - rewrite chunk system + this.parent = parent == null ? this : parent; this.chunkType = chunkType; - this.heightmapsAfter = heightMapTypes; + this.heightmapsAfter = heightmapsAfter; diff --git a/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java b/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java -index 3d8a35d8cf29447ee7ac750dbc6ffcdb0f89b81b..9a3900e970f22892d8a3da8a28f922aa9b62765f 100644 +index c953bc93de8a42bcc12b7e8f46b3ae804e54964e..2ccbdfdcf81556306e098277ecf119d5fd02138c 100644 --- a/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java +++ b/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java -@@ -152,7 +152,7 @@ public class ChunkStatusTasks { - chunk1 = protochunkextension.getWrapped(); +@@ -182,7 +182,7 @@ public class ChunkStatusTasks { + if (protoChunk instanceof ImposterProtoChunk imposterProtoChunk) { + wrapped = imposterProtoChunk.getWrapped(); } else { - chunk1 = new LevelChunk(worldserver, protochunk, ($) -> { // Paper - decompile fix -- ChunkStatusTasks.postLoadProtoChunk(worldserver, protochunk.getEntities()); -+ ChunkStatusTasks.postLoadProtoChunk(worldserver, protochunk.getEntities(), protochunk.getPos()); // Paper - rewrite chunk system - }); - generationchunkholder.replaceProtoChunk(new ImposterProtoChunk(chunk1, false)); +- wrapped = new LevelChunk(serverLevel, protoChunk, chunk1 -> postLoadProtoChunk(serverLevel, protoChunk.getEntities())); ++ wrapped = new LevelChunk(serverLevel, protoChunk, chunk1 -> postLoadProtoChunk(serverLevel, protoChunk.getEntities(), protoChunk.getPos())); // Paper - rewrite chunk system + generationChunkHolder.replaceProtoChunk(new ImposterProtoChunk(wrapped, false)); } -@@ -168,7 +168,7 @@ public class ChunkStatusTasks { - }, context.mainThreadExecutor()); + +@@ -196,7 +196,7 @@ public class ChunkStatusTasks { + }, worldGenContext.mainThreadExecutor()); } -- public static void postLoadProtoChunk(ServerLevel world, List<CompoundTag> entities) { // Paper - public -+ public static void postLoadProtoChunk(ServerLevel world, List<CompoundTag> entities, ChunkPos pos) { // Paper - public // Paper - rewrite chunk system - add ChunkPos param - if (!entities.isEmpty()) { +- public static void postLoadProtoChunk(ServerLevel level, List<CompoundTag> entityTags) { // Paper - public ++ public static void postLoadProtoChunk(ServerLevel level, List<CompoundTag> entityTags, ChunkPos pos) { // Paper - public // Paper - rewrite chunk system - add ChunkPos param + if (!entityTags.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) -> { -@@ -180,7 +180,7 @@ public class ChunkStatusTasks { + level.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entityTags, level, EntitySpawnReason.LOAD).filter((entity) -> { +@@ -208,7 +208,7 @@ public class ChunkStatusTasks { } - checkDupeUUID(world, entity); // Paper - duplicate uuid resolving + checkDupeUUID(level, entity); // Paper - duplicate uuid resolving return !needsRemoval; - })); + }), pos); // Paper - rewrite chunk system // CraftBukkit end } - + } diff --git a/net/minecraft/world/level/chunk/status/ChunkStep.java b/net/minecraft/world/level/chunk/status/ChunkStep.java -index 3d37a0372cdd99e806a9651cc1cabaefa9338065..f9aad1b8c02b70e620efdc2a58cadf4fff0f3ed5 100644 +index 7a4d299d2ce36982204e30de9278ddfd5b37c3df..b8348976e80578d9eff64eea68c04c603fed49ad 100644 --- a/net/minecraft/world/level/chunk/status/ChunkStep.java +++ b/net/minecraft/world/level/chunk/status/ChunkStep.java @@ -11,9 +11,50 @@ import net.minecraft.util.profiling.jfr.callback.ProfiledDuration; @@ -32864,7 +32367,7 @@ index 3d37a0372cdd99e806a9651cc1cabaefa9338065..f9aad1b8c02b70e620efdc2a58cadf4f public int getAccumulatedRadiusOf(ChunkStatus status) { return status == this.targetStatus ? 0 : this.accumulatedDependencies.getRadiusOf(status); } -@@ -39,6 +80,56 @@ public record ChunkStep( +@@ -40,6 +81,56 @@ public record ChunkStep( return chunk; } @@ -32922,16 +32425,15 @@ index 3d37a0372cdd99e806a9651cc1cabaefa9338065..f9aad1b8c02b70e620efdc2a58cadf4f private final ChunkStatus status; @Nullable diff --git a/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/net/minecraft/world/level/chunk/storage/ChunkStorage.java -index 092f7b6bba4e1291f76c2c09155f33803e93eb04..46f4b6706a1ca24ff6fc28960ad01a067109819f 100644 +index 80bc7ad9ad076968d06279dedd845d5946cf2501..433feab7f7c1931f79836164a0b8c4a1c3b75ba6 100644 --- a/net/minecraft/world/level/chunk/storage/ChunkStorage.java +++ b/net/minecraft/world/level/chunk/storage/ChunkStorage.java -@@ -28,21 +28,31 @@ import net.minecraft.world.level.dimension.LevelStem; +@@ -22,20 +22,30 @@ import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.structure.LegacyStructureDataHandler; import net.minecraft.world.level.storage.DimensionDataStorage; -public class ChunkStorage implements AutoCloseable { +public class ChunkStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemChunkStorage { // Paper - rewrite chunk system - public static final int LAST_MONOLYTH_STRUCTURE_DATA_VERSION = 1493; - private final IOWorker worker; + // Paper - rewrite chunk system @@ -32949,29 +32451,29 @@ index 092f7b6bba4e1291f76c2c09155f33803e93eb04..46f4b6706a1ca24ff6fc28960ad01a06 + } + // Paper end - rewrite chunk system + - public ChunkStorage(RegionStorageInfo storageKey, Path directory, DataFixer dataFixer, boolean dsync) { - this.fixerUpper = dataFixer; -- this.worker = new IOWorker(storageKey, directory, dsync); -+ this.storage = new IOWorker(storageKey, directory, dsync).storage; // Paper - rewrite chunk system + public ChunkStorage(RegionStorageInfo info, Path folder, DataFixer fixerUpper, boolean sync) { + this.fixerUpper = fixerUpper; +- this.worker = new IOWorker(info, folder, sync); ++ this.storage = new IOWorker(info, folder, sync).storage; // Paper - rewrite chunk system } - public boolean isOldChunkAround(ChunkPos chunkPos, int checkRadius) { -- return this.worker.isOldChunkAround(chunkPos, checkRadius); + public boolean isOldChunkAround(ChunkPos pos, int radius) { +- return this.worker.isOldChunkAround(pos, radius); + return true; // Paper - rewrite chunk system } // CraftBukkit start -@@ -102,7 +112,9 @@ public class ChunkStorage implements AutoCloseable { - if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) { - LegacyStructureDataHandler persistentstructurelegacy = this.getLegacyStructureHandler(resourcekey, supplier); - -+ synchronized (persistentstructurelegacy) { // Paper - rewrite chunk system - nbttagcompound = persistentstructurelegacy.updateFromLegacy(nbttagcompound); -+ } // Paper - rewrite chunk system +@@ -99,7 +109,9 @@ public class ChunkStorage implements AutoCloseable { + chunkData = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, chunkData, version, 1493); // Paper - replace chunk converter + if (chunkData.getCompound("Level").getBoolean("hasLegacyStructureData")) { + LegacyStructureDataHandler legacyStructureHandler = this.getLegacyStructureHandler(levelKey, storage); ++ synchronized (legacyStructureHandler) { // Paper - rewrite chunk system + chunkData = legacyStructureHandler.updateFromLegacy(chunkData); ++ } } } -@@ -169,7 +181,13 @@ public class ChunkStorage implements AutoCloseable { +@@ -163,7 +175,13 @@ public class ChunkStorage implements AutoCloseable { } public CompletableFuture<Optional<CompoundTag>> read(ChunkPos chunkPos) { @@ -32985,15 +32487,15 @@ index 092f7b6bba4e1291f76c2c09155f33803e93eb04..46f4b6706a1ca24ff6fc28960ad01a06 + // Paper end - rewrite chunk system } - public CompletableFuture<Void> write(ChunkPos chunkPos, Supplier<CompoundTag> nbtSupplier) { -@@ -185,29 +203,54 @@ public class ChunkStorage implements AutoCloseable { + public CompletableFuture<Void> write(ChunkPos pos, Supplier<CompoundTag> tagSupplier) { +@@ -179,29 +197,54 @@ public class ChunkStorage implements AutoCloseable { }; // Paper end - guard against possible chunk pos desync - this.handleLegacyStructureIndex(chunkPos); -- return this.worker.store(chunkPos, guardedPosCheck); // Paper - guard against possible chunk pos desync + this.handleLegacyStructureIndex(pos); +- return this.worker.store(pos, guardedPosCheck); // Paper - guard against possible chunk pos desync + // Paper start - rewrite chunk system + try { -+ this.storage.write(chunkPos, guardedPosCheck.get()); ++ this.storage.write(pos, guardedPosCheck.get()); + return CompletableFuture.completedFuture(null); + } catch (final Throwable throwable) { + return CompletableFuture.failedFuture(throwable); @@ -33007,7 +32509,6 @@ index 092f7b6bba4e1291f76c2c09155f33803e93eb04..46f4b6706a1ca24ff6fc28960ad01a06 this.legacyStructureHandler.removeIndex(chunkPos.toLong()); + } // Paper - rewrite chunk system } - } public void flushWorker() { @@ -33021,6 +32522,7 @@ index 092f7b6bba4e1291f76c2c09155f33803e93eb04..46f4b6706a1ca24ff6fc28960ad01a06 + // Paper end - rewrite chunk system } + @Override public void close() throws IOException { - this.worker.close(); + this.storage.close(); // Paper - rewrite chunk system @@ -33048,26 +32550,26 @@ index 092f7b6bba4e1291f76c2c09155f33803e93eb04..46f4b6706a1ca24ff6fc28960ad01a06 } } diff --git a/net/minecraft/world/level/chunk/storage/EntityStorage.java b/net/minecraft/world/level/chunk/storage/EntityStorage.java -index a0cbccd2cf1ac785745d86c42b6f58fb8bad7ffa..16ca1c8672e5f0a27f8a30498c754a81cdec5191 100644 +index c3c9771138cb1712ea429d8c45596220830314eb..da05fb780c55381a7a08ced51d01764a645740b2 100644 --- a/net/minecraft/world/level/chunk/storage/EntityStorage.java +++ b/net/minecraft/world/level/chunk/storage/EntityStorage.java @@ -71,12 +71,12 @@ public class EntityStorage implements EntityPersistentStorage<Entity> { } } -- private static ChunkPos readChunkPos(CompoundTag chunkNbt) { -+ public static ChunkPos readChunkPos(CompoundTag chunkNbt) { // Paper - public - int[] is = chunkNbt.getIntArray("Position"); - return new ChunkPos(is[0], is[1]); +- private static ChunkPos readChunkPos(CompoundTag tag) { ++ public static ChunkPos readChunkPos(CompoundTag tag) { // Paper - public + int[] intArray = tag.getIntArray("Position"); + return new ChunkPos(intArray[0], intArray[1]); } -- private static void writeChunkPos(CompoundTag chunkNbt, ChunkPos pos) { -+ public static void writeChunkPos(CompoundTag chunkNbt, ChunkPos pos) { // Paper - public - chunkNbt.put("Position", new IntArrayTag(new int[]{pos.x, pos.z})); +- private static void writeChunkPos(CompoundTag tag, ChunkPos pos) { ++ public static void writeChunkPos(CompoundTag tag, ChunkPos pos) { // Paper - public + tag.put("Position", new IntArrayTag(new int[]{pos.x, pos.z})); } diff --git a/net/minecraft/world/level/chunk/storage/IOWorker.java b/net/minecraft/world/level/chunk/storage/IOWorker.java -index 1f2997cf5367200084f32c437f77040c8c6a18e6..a8a9e59a9721a76e34f78c1baa5026e5fe1d2bda 100644 +index 889e188e920edb284f04b264bcdd06146f54a4cb..2199a9e2a0141c646d108f2687a27f1d165453c5 100644 --- a/net/minecraft/world/level/chunk/storage/IOWorker.java +++ b/net/minecraft/world/level/chunk/storage/IOWorker.java @@ -30,7 +30,7 @@ public class IOWorker implements ChunkScanAccess, AutoCloseable { @@ -33080,21 +32582,21 @@ index 1f2997cf5367200084f32c437f77040c8c6a18e6..a8a9e59a9721a76e34f78c1baa5026e5 private final Long2ObjectLinkedOpenHashMap<CompletableFuture<BitSet>> regionCacheForBlender = new Long2ObjectLinkedOpenHashMap<>(); private static final int REGION_CACHE_SIZE = 1024; diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java -index 863960ead8deaa0553be1c98e4fa09f07fcb8ef0..057875cbbdc92ba49b429f9a129514760edb32a2 100644 +index 7491644233d52dc56d83de5ad3373f6a9a455378..b76f0fcecd3de1e7a802a6006c8851d94ba35329 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -28,7 +28,7 @@ import net.minecraft.nbt.NbtIo; // Paper +@@ -23,7 +23,7 @@ import net.minecraft.util.profiling.jfr.JvmProfiler; import net.minecraft.world.level.ChunkPos; import org.slf4j.Logger; -public class RegionFile implements AutoCloseable { +public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system - private static final Logger LOGGER = LogUtils.getLogger(); private static final int SECTOR_BYTES = 4096; -@@ -52,6 +52,21 @@ public class RegionFile implements AutoCloseable { @VisibleForTesting - protected final RegionBitmap usedSectors; +@@ -46,6 +46,21 @@ public class RegionFile implements AutoCloseable { + @VisibleForTesting + protected final RegionBitmap usedSectors = new RegionBitmap(); + // Paper start - rewrite chunk system + @Override @@ -33111,33 +32613,32 @@ index 863960ead8deaa0553be1c98e4fa09f07fcb8ef0..057875cbbdc92ba49b429f9a12951476 + } + // Paper end - rewrite chunk system + - public RegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { - this(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); // Paper - Configurable region compression format + public RegionFile(RegionStorageInfo info, Path path, Path externalFileDir, boolean sync) throws IOException { + this(info, path, externalFileDir, RegionFileVersion.getCompressionFormat(), sync); // Paper - Configurable region compression format } -@@ -224,6 +239,16 @@ public class RegionFile implements AutoCloseable { +@@ -205,6 +220,16 @@ public class RegionFile implements AutoCloseable { @Nullable - private DataInputStream createExternalChunkInputStream(ChunkPos pos, byte flags) throws IOException { + private DataInputStream createExternalChunkInputStream(ChunkPos chunkPos, byte versionByte) throws IOException { + // Paper start - rewrite chunk system -+ final DataInputStream is = this.createExternalChunkInputStream0(pos, flags); ++ final DataInputStream is = this.createExternalChunkInputStream0(chunkPos, versionByte); + if (is == null) { + return is; + } + return new ca.spottedleaf.moonrise.patches.chunk_system.util.stream.ExternalChunkStreamMarker(is); + } + @Nullable -+ private DataInputStream createExternalChunkInputStream0(ChunkPos pos, byte flags) throws IOException { ++ private DataInputStream createExternalChunkInputStream0(ChunkPos chunkPos, byte versionByte) throws IOException { + // Paper end - rewrite chunk system - Path path = this.getExternalChunkPath(pos); - - if (!Files.isRegularFile(path, new LinkOption[0])) { -@@ -514,10 +539,29 @@ public class RegionFile implements AutoCloseable { - + Path externalChunkPath = this.getExternalChunkPath(chunkPos); + if (!Files.isRegularFile(externalChunkPath)) { + LOGGER.error("External chunk path {} is not file", externalChunkPath); +@@ -399,9 +424,28 @@ public class RegionFile implements AutoCloseable { + } } - // Paper end -- private class ChunkBuffer extends ByteArrayOutputStream { -+ private class ChunkBuffer extends ByteArrayOutputStream implements ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemChunkBuffer { // Paper - rewrite chunk system +- class ChunkBuffer extends ByteArrayOutputStream { ++ class ChunkBuffer extends ByteArrayOutputStream implements ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemChunkBuffer { // Paper - rewrite chunk system private final ChunkPos pos; + // Paper start - rewrite chunk system @@ -33159,36 +32660,36 @@ index 863960ead8deaa0553be1c98e4fa09f07fcb8ef0..057875cbbdc92ba49b429f9a12951476 + } + // Paper end - rewrite chunk system + - public ChunkBuffer(final ChunkPos chunkcoordintpair) { + public ChunkBuffer(final ChunkPos pos) { super(8096); super.write(0); -@@ -534,7 +578,7 @@ public class RegionFile implements AutoCloseable { - +@@ -418,7 +462,7 @@ public class RegionFile implements AutoCloseable { + int i = this.count - 5 + 1; JvmProfiler.INSTANCE.onRegionFileWrite(RegionFile.this.info, this.pos, RegionFile.this.version, i); - bytebuffer.putInt(0, i); -- RegionFile.this.write(this.pos, bytebuffer); -+ if (this.writeOnClose) { RegionFile.this.write(this.pos, bytebuffer); } // Paper - rewrite chunk system + byteBuffer.putInt(0, i); +- RegionFile.this.write(this.pos, byteBuffer); ++ if (this.writeOnClose) { RegionFile.this.write(this.pos, byteBuffer); } // Paper - rewrite chunk system } } diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index e6abe35d6c43b7f76cf3da129ec9552e7b82453e..fdf8e18d24442178b52397acb482ffa3306a32e3 100644 +index 51bf310423013d0ae9d3202d66e36a053a767197..2661a21703994a18c4a9a44fba0f6931fd37151e 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -17,7 +17,7 @@ import net.minecraft.nbt.StreamTagVisitor; +@@ -14,7 +14,7 @@ import net.minecraft.nbt.StreamTagVisitor; import net.minecraft.util.ExceptionCollector; import net.minecraft.world.level.ChunkPos; -public final class RegionFileStorage implements AutoCloseable { -+public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage { // Paper - rewrite chunk system - ++public final class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage { // Paper - rewrite chunk system public static final String ANVIL_EXTENSION = ".mca"; private static final int MAX_CACHE_SIZE = 256; -@@ -26,33 +26,219 @@ public final class RegionFileStorage implements AutoCloseable { + public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); +@@ -22,29 +22,218 @@ public final class RegionFileStorage implements AutoCloseable { private final Path folder; private final boolean sync; -- RegionFileStorage(RegionStorageInfo storageKey, Path directory, boolean dsync) { +- RegionFileStorage(RegionStorageInfo info, Path folder, boolean sync) { + // Paper start - rewrite chunk system + private static final int REGION_SHIFT = 5; + private static final int MAX_NON_EXISTING_CACHE = 1024 * 4; @@ -33359,34 +32860,31 @@ index e6abe35d6c43b7f76cf3da129ec9552e7b82453e..fdf8e18d24442178b52397acb482ffa3 + } + } + // Paper end - rewrite chunk system -+ -+ protected RegionFileStorage(RegionStorageInfo storageKey, Path directory, boolean dsync) { // Paper - protected - this.folder = directory; - this.sync = dsync; - this.info = storageKey; - } - -- private RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit -- long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); -- RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i); + // Paper start - rewrite chunk system + public RegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { + return this.getRegionFile(chunkcoordintpair, false); + } + // Paper end - rewrite chunk system ++ ++ protected RegionFileStorage(RegionStorageInfo info, Path folder, boolean sync) { // Paper - protected + this.folder = folder; + this.sync = sync; + this.info = info; + } -- if (regionfile != null) { -- return regionfile; + @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit +- long packedChunkPos = ChunkPos.asLong(chunkPos.getRegionX(), chunkPos.getRegionZ()); +- RegionFile regionFile = this.regionCache.getAndMoveToFirst(packedChunkPos); +- if (regionFile != null) { +- return regionFile; - } else { - if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - Sanitise RegionFileCache and make configurable -- ((RegionFile) this.regionCache.removeLast()).close(); -+ public RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - public + // Paper start - rewrite chunk system + if (existingOnly) { -+ return this.moonrise$getRegionFileIfExists(chunkcoordintpair.x, chunkcoordintpair.z); ++ return this.moonrise$getRegionFileIfExists(chunkPos.x, chunkPos.z); + } + synchronized (this) { -+ final long key = ChunkPos.asLong(chunkcoordintpair.x >> REGION_SHIFT, chunkcoordintpair.z >> REGION_SHIFT); ++ final long key = ChunkPos.asLong(chunkPos.x >> REGION_SHIFT, chunkPos.z >> REGION_SHIFT); + + RegionFile ret = this.regionCache.getAndMoveToFirst(key); + if (ret != null) { @@ -33394,22 +32892,20 @@ index e6abe35d6c43b7f76cf3da129ec9552e7b82453e..fdf8e18d24442178b52397acb482ffa3 + } + + if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper -+ this.regionCache.removeLast().close(); + this.regionCache.removeLast().close(); } -+ final Path regionPath = this.folder.resolve(getRegionFileName(chunkcoordintpair.x, chunkcoordintpair.z)); ++ final Path regionPath = this.folder.resolve(getRegionFileName(chunkPos.x, chunkPos.z)); + + this.createRegionFile(key); + FileUtil.createDirectoriesSafe(this.folder); -- Path path = this.folder; -- int j = chunkcoordintpair.getRegionX(); -- Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); -- if (existingOnly && !java.nio.file.Files.exists(path1)) return null; // CraftBukkit -- RegionFile regionfile1 = new RegionFile(this.info, path1, this.folder, this.sync); - -- this.regionCache.putAndMoveToFirst(i, regionfile1); -- return regionfile1; +- Path path = this.folder.resolve("r." + chunkPos.getRegionX() + "." + chunkPos.getRegionZ() + ".mca"); +- if (existingOnly && !java.nio.file.Files.exists(path)) return null; // CraftBukkit +- RegionFile regionFile1 = new RegionFile(this.info, path, this.folder, this.sync); +- this.regionCache.putAndMoveToFirst(packedChunkPos, regionFile1); +- return regionFile1; ++ + ret = new RegionFile(this.info, regionPath, this.folder, this.sync); + + this.regionCache.putAndMoveToFirst(key, ret); @@ -33420,37 +32916,34 @@ index e6abe35d6c43b7f76cf3da129ec9552e7b82453e..fdf8e18d24442178b52397acb482ffa3 } // Paper start -@@ -175,8 +361,14 @@ public final class RegionFileStorage implements AutoCloseable { - +@@ -126,8 +315,14 @@ public final class RegionFileStorage implements AutoCloseable { + } } -- protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { -- RegionFile regionfile = this.getRegionFile(pos, false); // CraftBukkit -+ public void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { // Paper - rewrite chunk system - public -+ RegionFile regionfile = this.getRegionFile(pos, nbt == null); // CraftBukkit // Paper - rewrite chunk system +- protected void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException { +- RegionFile regionFile = this.getRegionFile(chunkPos, false); // CraftBukkit ++ public void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException { // Paper - rewrite chunk system - public ++ RegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system + // Paper start - rewrite chunk system -+ if (regionfile == null) { ++ if (regionFile == null) { + // if the RegionFile doesn't exist, no point in deleting from it + return; + } + // Paper end - rewrite chunk system + if (chunkData == null) { + regionFile.clear(chunkPos); + } else { +@@ -140,23 +335,36 @@ public final class RegionFileStorage implements AutoCloseable { - if (nbt == null) { - regionfile.clear(pos); -@@ -206,30 +398,37 @@ public final class RegionFileStorage implements AutoCloseable { - } - + @Override public void close() throws IOException { -- ExceptionCollector<IOException> exceptionsuppressor = new ExceptionCollector<>(); -- ObjectIterator objectiterator = this.regionCache.values().iterator(); -- -- while (objectiterator.hasNext()) { -- RegionFile regionfile = (RegionFile) objectiterator.next(); +- ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>(); - +- for (RegionFile regionFile : this.regionCache.values()) { - try { -- regionfile.close(); -- } catch (IOException ioexception) { -- exceptionsuppressor.add(ioexception); +- regionFile.close(); +- } catch (IOException var5) { +- exceptionCollector.add(var5); + // Paper start - rewrite chunk system + synchronized (this) { + final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>(); @@ -33461,19 +32954,16 @@ index e6abe35d6c43b7f76cf3da129ec9552e7b82453e..fdf8e18d24442178b52397acb482ffa3 + exceptionCollector.add(ex); + } } -- } - -- exceptionsuppressor.throwIfPresent(); + exceptionCollector.throwIfPresent(); -+ } + } +- +- exceptionCollector.throwIfPresent(); + // Paper end - rewrite chunk system } public void flush() throws IOException { -- ObjectIterator objectiterator = this.regionCache.values().iterator(); -- -- while (objectiterator.hasNext()) { -- RegionFile regionfile = (RegionFile) objectiterator.next(); +- for (RegionFile regionFile : this.regionCache.values()) { +- regionFile.flush(); + // Paper start - rewrite chunk system + synchronized (this) { + final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>(); @@ -33484,16 +32974,15 @@ index e6abe35d6c43b7f76cf3da129ec9552e7b82453e..fdf8e18d24442178b52397acb482ffa3 + exceptionCollector.add(ex); + } + } - -- regionfile.flush(); ++ + exceptionCollector.throwIfPresent(); } + // Paper end - rewrite chunk system - } + public RegionStorageInfo info() { diff --git a/net/minecraft/world/level/chunk/storage/SectionStorage.java b/net/minecraft/world/level/chunk/storage/SectionStorage.java -index 75b2cf0e13c23a8348b7ff55e72e5ee755aa7460..c3beb7fcad46a917d2b61bd0a0e98e5106056728 100644 +index 7dc1ffffd9d0fec54dbc254c154ee85ee750174d..778bd73a938c94ecb85ca0f8b686ff4e1baee040 100644 --- a/net/minecraft/world/level/chunk/storage/SectionStorage.java +++ b/net/minecraft/world/level/chunk/storage/SectionStorage.java @@ -40,10 +40,10 @@ import net.minecraft.world.level.ChunkPos; @@ -33526,26 +33015,26 @@ index 75b2cf0e13c23a8348b7ff55e72e5ee755aa7460..c3beb7fcad46a917d2b61bd0a0e98e51 + // Paper end - rewrite chunk system + public SectionStorage( - SimpleRegionStorage storageAccess, + SimpleRegionStorage simpleRegionStorage, Codec<P> codec, @@ -67,7 +79,7 @@ public class SectionStorage<R, P> implements AutoCloseable { - ChunkIOErrorReporter errorHandler, - LevelHeightAccessor world + ChunkIOErrorReporter errorReporter, + LevelHeightAccessor levelHeightAccessor ) { -- this.simpleRegionStorage = storageAccess; +- this.simpleRegionStorage = simpleRegionStorage; + // Paper - rewrite chunk system this.codec = codec; - this.packer = serializer; - this.unpacker = deserializer; + this.packer = packer; + this.unpacker = unpacker; @@ -75,6 +87,7 @@ public class SectionStorage<R, P> implements AutoCloseable { - this.registryAccess = registryManager; - this.errorReporter = errorHandler; - this.levelHeightAccessor = world; -+ this.regionStorage = storageAccess.worker.storage; // Paper - rewrite chunk system + this.registryAccess = registryAccess; + this.errorReporter = errorReporter; + this.levelHeightAccessor = levelHeightAccessor; ++ this.regionStorage = simpleRegionStorage.worker.storage; // Paper - rewrite chunk system } - protected void tick(BooleanSupplier shouldKeepTicking) { -@@ -188,64 +201,15 @@ public class SectionStorage<R, P> implements AutoCloseable { + protected void tick(BooleanSupplier aheadOfTime) { +@@ -188,65 +201,15 @@ public class SectionStorage<R, P> implements AutoCloseable { } private CompletableFuture<Optional<SectionStorage.PackedChunk<P>>> tryRead(ChunkPos chunkPos) { @@ -33553,43 +33042,44 @@ index 75b2cf0e13c23a8348b7ff55e72e5ee755aa7460..c3beb7fcad46a917d2b61bd0a0e98e51 - return this.simpleRegionStorage - .read(chunkPos) - .thenApplyAsync( -- chunkNbt -> chunkNbt.map( -- nbt -> SectionStorage.PackedChunk.parse(this.codec, registryOps, nbt, this.simpleRegionStorage, this.levelHeightAccessor) -- ), +- optional -> optional.map( +- compoundTag -> SectionStorage.PackedChunk.parse(this.codec, registryOps, compoundTag, this.simpleRegionStorage, this.levelHeightAccessor) +- ), - Util.backgroundExecutor().forName("parseSection") - ) -- .exceptionally(throwable -> { -- if (throwable instanceof CompletionException) { -- throwable = throwable.getCause(); +- .exceptionally(cause -> { +- if (cause instanceof CompletionException) { +- cause = cause.getCause(); - } - -- if (throwable instanceof IOException iOException) { -- LOGGER.error("Error reading chunk {} data from disk", chunkPos, iOException); -- this.errorReporter.reportChunkLoadFailure(iOException, this.simpleRegionStorage.storageInfo(), chunkPos); +- if (cause 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 CompletionException(cause); - } - }); + throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName()); // Paper - rewrite chunk system } - private void unpackChunk(ChunkPos chunkPos, @Nullable SectionStorage.PackedChunk<P> result) { -- if (result == null) { -- for (int i = this.levelHeightAccessor.getMinSectionY(); i <= this.levelHeightAccessor.getMaxSectionY(); i++) { -- this.storage.put(getKey(chunkPos, i), Optional.empty()); + private void unpackChunk(ChunkPos pos, @Nullable SectionStorage.PackedChunk<P> packedChunk) { +- if (packedChunk == null) { +- for (int sectionY = this.levelHeightAccessor.getMinSectionY(); sectionY <= this.levelHeightAccessor.getMaxSectionY(); sectionY++) { +- this.storage.put(getKey(pos, sectionY), Optional.empty()); - } - } else { -- boolean bl = result.versionChanged(); +- boolean versionChanged = packedChunk.versionChanged(); - -- for (int j = this.levelHeightAccessor.getMinSectionY(); j <= this.levelHeightAccessor.getMaxSectionY(); j++) { -- long l = getKey(chunkPos, j); -- Optional<R> optional = Optional.ofNullable(result.sectionsByY.get(j)).map(section -> this.unpacker.apply((P)section, () -> this.setDirty(l))); -- this.storage.put(l, optional); +- for (int sectionY1 = this.levelHeightAccessor.getMinSectionY(); sectionY1 <= this.levelHeightAccessor.getMaxSectionY(); sectionY1++) { +- long key = getKey(pos, sectionY1); +- Optional<R> optional = Optional.ofNullable(packedChunk.sectionsByY.get(sectionY1)) +- .map(object -> this.unpacker.apply((P)object, () -> this.setDirty(key))); +- this.storage.put(key, optional); - optional.ifPresent(object -> { -- this.onSectionLoad(l); -- if (bl) { -- this.setDirty(l); +- this.onSectionLoad(key); +- if (versionChanged) { +- this.setDirty(key); - } - }); - } @@ -33612,17 +33102,17 @@ index 75b2cf0e13c23a8348b7ff55e72e5ee755aa7460..c3beb7fcad46a917d2b61bd0a0e98e51 + throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName()); // Paper - rewrite chunk system } - private <T> Dynamic<T> writeChunk(ChunkPos chunkPos, DynamicOps<T> ops) { -@@ -281,7 +245,7 @@ public class SectionStorage<R, P> implements AutoCloseable { - protected void onSectionLoad(long pos) { + private <T> Dynamic<T> writeChunk(ChunkPos pos, DynamicOps<T> ops) { +@@ -282,7 +245,7 @@ public class SectionStorage<R, P> implements AutoCloseable { + protected void onSectionLoad(long sectionKey) { } -- protected void setDirty(long pos) { -+ public void setDirty(long pos) { // Paper - public - Optional<R> optional = this.storage.get(pos); +- protected void setDirty(long sectionPos) { ++ public void setDirty(long sectionPos) { // Paper - public + Optional<R> optional = this.storage.get(sectionPos); if (optional != null && !optional.isEmpty()) { - this.dirtyChunks.add(ChunkPos.asLong(SectionPos.x(pos), SectionPos.z(pos))); -@@ -302,7 +266,7 @@ public class SectionStorage<R, P> implements AutoCloseable { + this.dirtyChunks.add(ChunkPos.asLong(SectionPos.x(sectionPos), SectionPos.z(sectionPos))); +@@ -303,7 +266,7 @@ public class SectionStorage<R, P> implements AutoCloseable { @Override public void close() throws IOException { @@ -33630,27 +33120,27 @@ index 75b2cf0e13c23a8348b7ff55e72e5ee755aa7460..c3beb7fcad46a917d2b61bd0a0e98e51 + this.moonrise$close(); // Paper - rewrite chunk system } - static record PackedChunk<T>(Int2ObjectMap<T> sectionsByY, boolean versionChanged) { + record PackedChunk<T>(Int2ObjectMap<T> sectionsByY, boolean versionChanged) { diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -index 4bc7fa3324e9af3abce2acf960c7b0650aca2e36..0296f52fb2c871adbf2ce73a64d8f77fab826cd7 100644 +index cf6e2053d81f7b0f8c8e58b9c0fad3285ebc047d..e8aafbd4bd9eaba4aaa448333b37c30a8dd719bf 100644 --- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -@@ -129,7 +129,7 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun - long j = nbt.getLong("InhabitedTime"); - ChunkStatus chunkstatus = ChunkStatus.byName(nbt.getString("Status")); - UpgradeData chunkconverter = nbt.contains("UpgradeData", 10) ? new UpgradeData(nbt.getCompound("UpgradeData"), world) : UpgradeData.EMPTY; -- boolean flag = nbt.getBoolean("isLightOn"); -+ boolean flag = chunkstatus.isOrAfter(ChunkStatus.LIGHT) && (nbt.get("isLightOn") != null && nbt.getInt(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_VERSION_TAG) == ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_LIGHT_VERSION); // Paper - starlight - DataResult dataresult; - Logger logger; - BlendingData.Packed blendingdata_d; -@@ -246,7 +246,17 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun - DataLayer nibblearray = nbttagcompound3.contains("BlockLight", 7) ? new DataLayer(nbttagcompound3.getByteArray("BlockLight")) : null; - DataLayer nibblearray1 = nbttagcompound3.contains("SkyLight", 7) ? new DataLayer(nbttagcompound3.getByteArray("SkyLight")) : null; - -- list4.add(new SerializableChunkData.SectionData(b0, chunksection, nibblearray, nibblearray1)); +@@ -148,7 +148,7 @@ public record SerializableChunkData( + UpgradeData upgradeData = tag.contains("UpgradeData", 10) + ? new UpgradeData(tag.getCompound("UpgradeData"), levelHeightAccessor) + : UpgradeData.EMPTY; +- boolean _boolean = tag.getBoolean("isLightOn"); ++ boolean _boolean = chunkstatus.isOrAfter(ChunkStatus.LIGHT) && (nbt.get("isLightOn") != null && nbt.getInt(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_VERSION_TAG) == ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_LIGHT_VERSION); // Paper - starlight + BlendingData.Packed packed; + if (tag.contains("blending_data", 10)) { + packed = BlendingData.Packed.CODEC.parse(NbtOps.INSTANCE, tag.getCompound("blending_data")).resultOrPartial(LOGGER::error).orElse(null); +@@ -249,7 +249,17 @@ public record SerializableChunkData( + + DataLayer dataLayer = compound2.contains("BlockLight", 7) ? new DataLayer(compound2.getByteArray("BlockLight")) : null; + DataLayer dataLayer1 = compound2.contains("SkyLight", 7) ? new DataLayer(compound2.getByteArray("SkyLight")) : null; +- list8.add(new SerializableChunkData.SectionData(_byte, levelChunkSection, dataLayer, dataLayer1)); + // Paper start - starlight -+ SerializableChunkData.SectionData serializableChunkData = new SerializableChunkData.SectionData(b0, chunksection, nibblearray, nibblearray1); ++ SerializableChunkData.SectionData serializableChunkData = new SerializableChunkData.SectionData(_byte, levelChunkSection, dataLayer, dataLayer1); + if (sectionData.contains(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.BLOCKLIGHT_STATE_TAG, Tag.TAG_ANY_NUMERIC)) { + ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)serializableChunkData).starlight$setBlockLightState(sectionData.getInt(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.BLOCKLIGHT_STATE_TAG)); + } @@ -33658,12 +33148,12 @@ index 4bc7fa3324e9af3abce2acf960c7b0650aca2e36..0296f52fb2c871adbf2ce73a64d8f77f + if (sectionData.contains(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.SKYLIGHT_STATE_TAG, Tag.TAG_ANY_NUMERIC)) { + ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)serializableChunkData).starlight$setSkyLightState(sectionData.getInt(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.SKYLIGHT_STATE_TAG)); + } -+ list4.add(serializableChunkData); ++ list8.add(serializableChunkData); + // Paper end - starlight } - // CraftBukkit - ChunkBukkitValues -@@ -254,6 +264,59 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun + return new SerializableChunkData( +@@ -276,6 +286,59 @@ public record SerializableChunkData( } } @@ -33720,56 +33210,59 @@ index 4bc7fa3324e9af3abce2acf960c7b0650aca2e36..0296f52fb2c871adbf2ce73a64d8f77f + } + // Paper end - starlight + - public ProtoChunk read(ServerLevel world, PoiManager poiStorage, RegionStorageInfo key, ChunkPos expectedPos) { - if (!Objects.equals(expectedPos, this.chunkPos)) { - SerializableChunkData.LOGGER.error("Chunk file at {} is in the wrong location; relocating. (Expected {}, got {})", new Object[]{expectedPos, expectedPos, this.chunkPos}); -@@ -275,7 +338,7 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun - - if (serializablechunkdata_b.chunkSection != null) { - achunksection[world.getSectionIndexFromSectionY(serializablechunkdata_b.y)] = serializablechunkdata_b.chunkSection; -- poiStorage.checkConsistencyWithBlocks(sectionposition, serializablechunkdata_b.chunkSection); -+ //poiStorage.checkConsistencyWithBlocks(sectionposition, serializablechunkdata_b.chunkSection); // Paper - rewrite chunk system + public ProtoChunk read(ServerLevel level, PoiManager poiManager, RegionStorageInfo regionStorageInfo, ChunkPos pos) { + if (!Objects.equals(pos, this.chunkPos)) { + LOGGER.error("Chunk file at {} is in the wrong location; relocating. (Expected {}, got {})", pos, pos, this.chunkPos); +@@ -294,7 +357,7 @@ public record SerializableChunkData( + SectionPos sectionPos = SectionPos.of(pos, sectionData.y); + if (sectionData.chunkSection != null) { + levelChunkSections[level.getSectionIndexFromSectionY(sectionData.y)] = sectionData.chunkSection; +- poiManager.checkConsistencyWithBlocks(sectionPos, sectionData.chunkSection); ++ //poiManager.checkConsistencyWithBlocks(sectionPos, sectionData.chunkSection); // Paper - rewrite chunk system } - boolean flag2 = serializablechunkdata_b.blockLight != null; -@@ -352,7 +415,7 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun + boolean flag1 = sectionData.blockLight != null; +@@ -376,7 +439,7 @@ public record SerializableChunkData( } - if (chunktype == ChunkType.LEVELCHUNK) { -- return new ImposterProtoChunk((LevelChunk) object, false); -+ return this.loadStarlightLightData(world, new ImposterProtoChunk((LevelChunk) object, false)); // Paper - starlight + if (chunkType == ChunkType.LEVELCHUNK) { +- return new ImposterProtoChunk((LevelChunk)chunkAccess, false); ++ return this.loadStarlightLightData(new ImposterProtoChunk((LevelChunk)chunkAccess, false)); // Paper - starlight } else { - ProtoChunk protochunk1 = (ProtoChunk) object; - Iterator iterator2 = this.entities.iterator(); -@@ -382,7 +445,7 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun - protochunk1.setCarvingMask(new CarvingMask(this.carvingMask, ((ChunkAccess) object).getMinY())); + ProtoChunk protoChunk1 = (ProtoChunk)chunkAccess; + +@@ -399,7 +462,7 @@ public record SerializableChunkData( + protoChunk1.setCarvingMask(new CarvingMask(this.carvingMask, chunkAccess.getMinY())); } -- return protochunk1; -+ return this.loadStarlightLightData(world, protochunk1); // Paper - starlight +- return protoChunk1; ++ return this.loadStarlightLightData(level, protoChunk1); // Paper - starlight } } -@@ -405,24 +468,48 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun - throw new IllegalArgumentException("Chunk can't be serialized: " + String.valueOf(chunk)); +@@ -427,22 +490,48 @@ public record SerializableChunkData( + throw new IllegalArgumentException("Chunk can't be serialized: " + chunk); } else { - ChunkPos chunkcoordintpair = chunk.getPos(); -- List<SerializableChunkData.SectionData> list = new ArrayList(); -+ List<SerializableChunkData.SectionData> list = new ArrayList(); final List<SerializableChunkData.SectionData> sections = list; // Paper - starlight - OBFHELPER - LevelChunkSection[] achunksection = chunk.getSections(); - ThreadedLevelLightEngine lightenginethreaded = world.getChunkSource().getLightEngine(); - -- for (int i = lightenginethreaded.getMinLightSection(); i < lightenginethreaded.getMaxLightSection(); ++i) { -- int j = chunk.getSectionIndexFromSectionY(i); -- boolean flag = j >= 0 && j < achunksection.length; -- DataLayer nibblearray = lightenginethreaded.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(chunkcoordintpair, i)); -- DataLayer nibblearray1 = lightenginethreaded.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(chunkcoordintpair, i)); -- DataLayer nibblearray2 = nibblearray != null && !nibblearray.isEmpty() ? nibblearray.copy() : null; -- DataLayer nibblearray3 = nibblearray1 != null && !nibblearray1.isEmpty() ? nibblearray1.copy() : null; + ChunkPos pos = chunk.getPos(); +- List<SerializableChunkData.SectionData> list = new ArrayList<>(); ++ List<SerializableChunkData.SectionData> list = new ArrayList<>(); final List<SerializableChunkData.SectionData> sectionsList = list; // Paper - starlight - OBFHELPER + LevelChunkSection[] sections = chunk.getSections(); + LevelLightEngine lightEngine = level.getChunkSource().getLightEngine(); + +- for (int lightSection = lightEngine.getMinLightSection(); lightSection < lightEngine.getMaxLightSection(); lightSection++) { +- int sectionIndexFromSectionY = chunk.getSectionIndexFromSectionY(lightSection); +- boolean flag = sectionIndexFromSectionY >= 0 && sectionIndexFromSectionY < sections.length; +- DataLayer dataLayerData = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(pos, lightSection)); +- DataLayer dataLayerData1 = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(pos, lightSection)); +- DataLayer dataLayer = dataLayerData != null && !dataLayerData.isEmpty() ? dataLayerData.copy() : null; +- DataLayer dataLayer1 = dataLayerData1 != null && !dataLayerData1.isEmpty() ? dataLayerData1.copy() : null; +- if (flag || dataLayer != null || dataLayer1 != null) { +- LevelChunkSection levelChunkSection = flag ? sections[sectionIndexFromSectionY].copy() : null; +- list.add(new SerializableChunkData.SectionData(lightSection, levelChunkSection, dataLayer, dataLayer1)); + // Paper start - starlight -+ final int minLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinLightSection(world); -+ final int maxLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxLightSection(world); -+ final int minBlockSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(world); ++ final int minLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinLightSection(level); ++ final int maxLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxLightSection(level); ++ final int minBlockSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(level); + + final LevelChunkSection[] chunkSections = chunk.getSections(); + final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] blockNibbles = ((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)chunk).starlight$getBlockNibbles(); @@ -33778,17 +33271,14 @@ index 4bc7fa3324e9af3abce2acf960c7b0650aca2e36..0296f52fb2c871adbf2ce73a64d8f77f + for (int lightSection = minLightSection; lightSection <= maxLightSection; ++lightSection) { + final int lightSectionIdx = lightSection - minLightSection; + final int blockSectionIdx = lightSection - minBlockSection; - -- if (flag || nibblearray2 != null || nibblearray3 != null) { -- LevelChunkSection chunksection = flag ? achunksection[j].copy() : null; ++ + final LevelChunkSection chunkSection = (blockSectionIdx >= 0 && blockSectionIdx < chunkSections.length) ? chunkSections[blockSectionIdx].copy() : null; + final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray.SaveState blockNibble = blockNibbles[lightSectionIdx].getSaveState(); + final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray.SaveState skyNibble = skyNibbles[lightSectionIdx].getSaveState(); - -- list.add(new SerializableChunkData.SectionData(i, chunksection, nibblearray2, nibblearray3)); ++ + if (chunkSection == null && blockNibble == null && skyNibble == null) { + continue; - } ++ } + + final SerializableChunkData.SectionData sectionData = new SerializableChunkData.SectionData( + lightSection, chunkSection, @@ -33802,27 +33292,25 @@ index 4bc7fa3324e9af3abce2acf960c7b0650aca2e36..0296f52fb2c871adbf2ce73a64d8f77f + + if (skyNibble != null) { + ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)sectionData).starlight$setSkyLightState(skyNibble.state); -+ } + } + -+ sections.add(sectionData); ++ sectionsList.add(sectionData); } + // Paper end - starlight - List<CompoundTag> list1 = new ArrayList(chunk.getBlockEntitiesPos().size()); - Iterator iterator = chunk.getBlockEntitiesPos().iterator(); -@@ -521,8 +608,8 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun - Iterator iterator = this.sectionData.iterator(); + List<CompoundTag> list1 = new ArrayList<>(chunk.getBlockEntitiesPos().size()); - while (iterator.hasNext()) { -- SerializableChunkData.SectionData serializablechunkdata_b = (SerializableChunkData.SectionData) iterator.next(); -- CompoundTag nbttagcompound1 = new CompoundTag(); -+ SerializableChunkData.SectionData serializablechunkdata_b = (SerializableChunkData.SectionData) iterator.next(); final SerializableChunkData.SectionData sectionData = serializablechunkdata_b; // Paper - starlight - OBFHELPER -+ CompoundTag nbttagcompound1 = new CompoundTag(); final CompoundTag sectionNBT = nbttagcompound1; // Paper - starlight - OBFHELPER - LevelChunkSection chunksection = serializablechunkdata_b.chunkSection; - - if (chunksection != null) { -@@ -538,6 +625,19 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun - nbttagcompound1.putByteArray("SkyLight", serializablechunkdata_b.skyLight.getData()); +@@ -540,7 +629,7 @@ public record SerializableChunkData( + Codec<PalettedContainerRO<Holder<Biome>>> codec = makeBiomeCodec(this.biomeRegistry); + + for (SerializableChunkData.SectionData sectionData : this.sectionData) { +- CompoundTag compoundTag1 = new CompoundTag(); ++ CompoundTag compoundTag1 = new CompoundTag(); final CompoundTag sectionNBT = compoundTag1; // Paper - starlight - OBFHELPER + LevelChunkSection levelChunkSection = sectionData.chunkSection; + if (levelChunkSection != null) { + compoundTag1.put("block_states", BLOCK_STATE_CODEC.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()).getOrThrow()); +@@ -555,6 +644,19 @@ public record SerializableChunkData( + compoundTag1.putByteArray("SkyLight", sectionData.skyLight.getData()); } + // Paper start - starlight @@ -33838,29 +33326,29 @@ index 4bc7fa3324e9af3abce2acf960c7b0650aca2e36..0296f52fb2c871adbf2ce73a64d8f77f + } + // Paper end - starlight + - if (!nbttagcompound1.isEmpty()) { - nbttagcompound1.putByte("Y", (byte) serializablechunkdata_b.y); - nbttaglist.add(nbttagcompound1); -@@ -577,6 +677,14 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun - nbttagcompound.put("ChunkBukkitValues", this.persistentDataContainer); + if (!compoundTag1.isEmpty()) { + compoundTag1.putByte("Y", (byte)sectionData.y); + listTag.add(compoundTag1); +@@ -589,6 +691,14 @@ public record SerializableChunkData( + compoundTag.put("ChunkBukkitValues", this.persistentDataContainer); } // CraftBukkit end + // Paper start - starlight + if (this.lightCorrect && !this.chunkStatus.isBefore(net.minecraft.world.level.chunk.status.ChunkStatus.LIGHT)) { + // clobber vanilla value to force vanilla to relight -+ nbttagcompound.putBoolean("isLightOn", false); ++ compoundTag.putBoolean("isLightOn", false); + // store our light version -+ nbttagcompound.putInt(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_VERSION_TAG, ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_LIGHT_VERSION); ++ compoundTag.putInt(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_VERSION_TAG, ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_LIGHT_VERSION); + } + // Paper end - starlight - return nbttagcompound; + return compoundTag; } -@@ -763,7 +871,67 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun - return nbttaglist; +@@ -747,6 +857,66 @@ public record SerializableChunkData( + } } -- public static record SectionData(int y, @Nullable LevelChunkSection chunkSection, @Nullable DataLayer blockLight, @Nullable DataLayer skyLight) { +- public record SectionData(int y, @Nullable LevelChunkSection chunkSection, @Nullable DataLayer blockLight, @Nullable DataLayer skyLight) { + // Paper start - starlight - convert from record + public static final class SectionData implements ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData { // Paper - starlight - our diff + private final int y; @@ -33922,11 +33410,10 @@ index 4bc7fa3324e9af3abce2acf960c7b0650aca2e36..0296f52fb2c871adbf2ce73a64d8f77f + return skyLight; + } + // Paper end - starlight - convert from record - } - + } diff --git a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java -index 578d270d5b7efb9ac8f5dde539170f6021e2b786..c5085ebf4e801837010f3750c5e89576bb0c27a5 100644 +index 41ddaceb7485626b1f2ee258c2142eb3114c106e..f883c6400281788982403d0af3ee28613e9a29b1 100644 --- a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java +++ b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java @@ -14,7 +14,7 @@ import net.minecraft.util.datafix.DataFixTypes; @@ -33939,7 +33426,7 @@ index 578d270d5b7efb9ac8f5dde539170f6021e2b786..c5085ebf4e801837010f3750c5e89576 private final DataFixTypes dataFixType; diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java -index 74a285b8b018a9c94ccea519f1ce8b9e2ef3cb64..d8b4196adf955f8d414688dc451caac2d9c609d9 100644 +index 342c83309b19c64d86e0dd97c1756c96be52772b..423779a2b690f387a4f0bd07b97b50e0baefda76 100644 --- a/net/minecraft/world/level/entity/EntityTickList.java +++ b/net/minecraft/world/level/entity/EntityTickList.java @@ -9,52 +9,38 @@ import javax.annotation.Nullable; @@ -33960,9 +33447,9 @@ index 74a285b8b018a9c94ccea519f1ce8b9e2ef3cb64..d8b4196adf955f8d414688dc451caac2 - this.passive.put(entry.getIntKey(), entry.getValue()); - } - -- Int2ObjectMap<Entity> int2ObjectMap = this.active; +- Int2ObjectMap<Entity> map = this.active; - this.active = this.passive; -- this.passive = int2ObjectMap; +- this.passive = map; - } + // Paper - rewrite chunk system } @@ -33984,15 +33471,15 @@ index 74a285b8b018a9c94ccea519f1ce8b9e2ef3cb64..d8b4196adf955f8d414688dc451caac2 + return this.entities.contains(entity); // Paper - rewrite chunk system } - public void forEach(Consumer<Entity> action) { + public void forEach(Consumer<Entity> entity) { - if (this.iterated != null) { - throw new UnsupportedOperationException("Only one concurrent iteration supported"); - } else { - this.iterated = this.active; - - try { -- for (Entity entity : this.active.values()) { -- action.accept(entity); +- for (Entity entity1 : this.active.values()) { +- entity.accept(entity1); - } - } finally { - this.iterated = null; @@ -34002,7 +33489,7 @@ index 74a285b8b018a9c94ccea519f1ce8b9e2ef3cb64..d8b4196adf955f8d414688dc451caac2 + final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator<Entity> iterator = this.entities.iterator(); + try { + while (iterator.hasNext()) { -+ action.accept(iterator.next()); ++ entity.accept(iterator.next()); } + } finally { + iterator.finishedIterating(); @@ -34011,29 +33498,29 @@ index 74a285b8b018a9c94ccea519f1ce8b9e2ef3cb64..d8b4196adf955f8d414688dc451caac2 } } diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -index 1fcc2b287ed723cf51720f80e68f18f4a15cf429..3f39d6c786d9dfdd9ad591e08ff05fcbb41a1df6 100644 +index b50de067a2a968926bdda4174e42f2973c84ff8b..8b81257328771ad23b90d7670f13713f93eefa96 100644 --- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java +++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -@@ -86,7 +86,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { +@@ -78,7 +78,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { return CompletableFuture.supplyAsync(() -> { - this.doCreateBiomes(blender, noiseConfig, structureAccessor, chunk); + this.doCreateBiomes(blender, randomState, structureManager, chunk); return chunk; - }, Util.backgroundExecutor().forName("init_biomes")); + }, Runnable::run); // Paper - rewrite chunk system } - private void doCreateBiomes(Blender blender, RandomState noiseConfig, StructureManager structureAccessor, ChunkAccess chunk) { -@@ -311,7 +311,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { + private void doCreateBiomes(Blender blender, RandomState random, StructureManager structureManager, ChunkAccess chunk) { +@@ -318,7 +318,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { } - return ichunkaccess1; + return var20; - }, 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) { + private ChunkAccess doFill(Blender blender, StructureManager structureManager, RandomState random, ChunkAccess chunk, int minCellY, int cellCountY) { diff --git a/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/net/minecraft/world/level/levelgen/structure/StructureCheck.java -index c3586281c9594769593a6027ea0a78f7c76c0262..decdb275e83fa6244aa3a24458872b42c49d04ed 100644 +index 06b54c0bec4031689d5c2da5cfea4ef28dbd16bc..f7dc4957b38878ddd3bfc7546be8a4e0af65c807 100644 --- a/net/minecraft/world/level/levelgen/structure/StructureCheck.java +++ b/net/minecraft/world/level/levelgen/structure/StructureCheck.java @@ -47,8 +47,13 @@ public class StructureCheck { @@ -34051,63 +33538,63 @@ index c3586281c9594769593a6027ea0a78f7c76c0262..decdb275e83fa6244aa3a24458872b42 + // Paper end - rewrite chunk system public StructureCheck( - ChunkScanAccess chunkIoWorker, + ChunkScanAccess storageAccess, @@ -90,7 +95,7 @@ public class StructureCheck { - public StructureCheckResult checkStart(ChunkPos pos, Structure type, StructurePlacement placement, boolean skipReferencedStructures) { - long l = pos.toLong(); -- Object2IntMap<Structure> object2IntMap = this.loadedChunks.get(l); -+ Object2IntMap<Structure> object2IntMap = this.loadedChunksSafe.get(l); // Paper - rewrite chunk system - if (object2IntMap != null) { - return this.checkStructureInfo(object2IntMap, type, skipReferencedStructures); + public StructureCheckResult checkStart(ChunkPos chunkPos, Structure structure, StructurePlacement placement, boolean skipKnownStructures) { + long packedChunkPos = chunkPos.toLong(); +- Object2IntMap<Structure> map = this.loadedChunks.get(packedChunkPos); ++ Object2IntMap<Structure> map = this.loadedChunksSafe.get(packedChunkPos); // Paper - rewrite chunk system + if (map != null) { + return this.checkStructureInfo(map, structure, skipKnownStructures); } else { @@ -100,9 +105,11 @@ public class StructureCheck { - } else if (!placement.applyAdditionalChunkRestrictions(pos.x, pos.z, this.seed, this.getSaltOverride(type))) { // Paper - add missing structure seed configs + } else if (!placement.applyAdditionalChunkRestrictions(chunkPos.x, chunkPos.z, this.seed, this.getSaltOverride(structure))) { // Paper - add missing structure seed configs return StructureCheckResult.START_NOT_PRESENT; } else { -- boolean bl = this.featureChecks -- .computeIfAbsent(type, structure2 -> new Long2BooleanOpenHashMap()) -- .computeIfAbsent(l, chunkPos -> this.canCreateStructure(pos, type)); +- boolean flag = this.featureChecks +- .computeIfAbsent(structure, structure1 -> new Long2BooleanOpenHashMap()) +- .computeIfAbsent(packedChunkPos, l -> this.canCreateStructure(chunkPos, structure)); + // Paper start - rewrite chunk system -+ boolean bl = this.featureChecksSafe -+ .computeIfAbsent(type, structure2 -> new ca.spottedleaf.moonrise.common.map.SynchronisedLong2BooleanMap(PER_FEATURE_CHECK_LIMIT)) -+ .getOrCompute(l, chunkPos -> this.canCreateStructure(pos, type)); ++ boolean flag = this.featureChecksSafe ++ .computeIfAbsent(structure, structure1 -> new ca.spottedleaf.moonrise.common.map.SynchronisedLong2BooleanMap(PER_FEATURE_CHECK_LIMIT)) ++ .getOrCompute(packedChunkPos, l -> this.canCreateStructure(chunkPos, structure)); + // Paper end - rewrite chunk system - return !bl ? StructureCheckResult.START_NOT_PRESENT : StructureCheckResult.CHUNK_LOAD_NEEDED; + return !flag ? StructureCheckResult.START_NOT_PRESENT : StructureCheckResult.CHUNK_LOAD_NEEDED; } } @@ -228,15 +235,25 @@ public class StructureCheck { } - private void storeFullResults(long pos, Object2IntMap<Structure> referencesByStructure) { -- this.loadedChunks.put(pos, deduplicateEmptyMap(referencesByStructure)); -- this.featureChecks.values().forEach(generationPossibilityByChunkPos -> generationPossibilityByChunkPos.remove(pos)); + private void storeFullResults(long chunkPos, Object2IntMap<Structure> structureChunks) { +- this.loadedChunks.put(chunkPos, deduplicateEmptyMap(structureChunks)); +- this.featureChecks.values().forEach(map -> map.remove(chunkPos)); + // Paper start - rewrite chunk system -+ this.loadedChunksSafe.put(pos, deduplicateEmptyMap(referencesByStructure)); ++ this.loadedChunksSafe.put(chunkPos, deduplicateEmptyMap(structureChunks)); + // once we insert into loadedChunks, we don't really need to be very careful about removing everything + // from this map, as everything that checks this map uses loadedChunks first + // so, one way or another it's a race condition that doesn't matter + for (ca.spottedleaf.moonrise.common.map.SynchronisedLong2BooleanMap value : this.featureChecksSafe.values()) { -+ value.remove(pos); ++ value.remove(chunkPos); + } + // Paper end - rewrite chunk system } public void incrementReference(ChunkPos pos, Structure structure) { -- this.loadedChunks.compute(pos.toLong(), (posx, referencesByStructure) -> { -- if (referencesByStructure == null || referencesByStructure.isEmpty()) { -+ this.loadedChunksSafe.compute(pos.toLong(), (posx, referencesByStructure) -> { // Paper start - rewrite chunk system -+ if (referencesByStructure == null) { - referencesByStructure = new Object2IntOpenHashMap<>(); +- this.loadedChunks.compute(pos.toLong(), (_long, map) -> { +- if (map == null || map.isEmpty()) { ++ this.loadedChunksSafe.compute(pos.toLong(), (_long, map) -> { // Paper start - rewrite chunk system ++ if (map == null) { + map = new Object2IntOpenHashMap<>(); + } else { -+ referencesByStructure = referencesByStructure instanceof Object2IntOpenHashMap<Structure> fastClone ? fastClone.clone() : new Object2IntOpenHashMap<>(referencesByStructure); ++ map = map instanceof Object2IntOpenHashMap<Structure> fastClone ? fastClone.clone() : new Object2IntOpenHashMap<>(map); } + // Paper end - rewrite chunk system - referencesByStructure.computeInt(structure, (feature, references) -> references == null ? 1 : references + 1); - return referencesByStructure; + map.computeInt(structure, (structure1, integer) -> integer == null ? 1 : integer + 1); + return map; diff --git a/net/minecraft/world/level/lighting/LevelLightEngine.java b/net/minecraft/world/level/lighting/LevelLightEngine.java -index 8d90e783967280025d711c709facbcc87f611f8a..987e3397503cd07d3a2f172cede341297bc58dba 100644 +index ca23af013967b50420ebee178878ea79333de53b..83c3ec06be51f632b7c1b682cfa8dce73ff7e0c0 100644 --- a/net/minecraft/world/level/lighting/LevelLightEngine.java +++ b/net/minecraft/world/level/lighting/LevelLightEngine.java @@ -9,151 +9,111 @@ import net.minecraft.world.level.LightLayer; @@ -34148,15 +33635,15 @@ index 8d90e783967280025d711c709facbcc87f611f8a..987e3397503cd07d3a2f172cede34129 + } + // Paper end - rewrite chunk system - public LevelLightEngine(LightChunkGetter chunkProvider, boolean hasBlockLight, boolean hasSkyLight) { - this.levelHeightAccessor = chunkProvider.getLevel(); -- this.blockEngine = hasBlockLight ? new BlockLightEngine(chunkProvider) : null; -- this.skyEngine = hasSkyLight ? new SkyLightEngine(chunkProvider) : null; + public LevelLightEngine(LightChunkGetter lightChunkGetter, boolean blockLight, boolean skyLight) { + this.levelHeightAccessor = lightChunkGetter.getLevel(); +- this.blockEngine = blockLight ? new BlockLightEngine(lightChunkGetter) : null; +- this.skyEngine = skyLight ? new SkyLightEngine(lightChunkGetter) : null; + // Paper start - rewrite chunk system -+ if (chunkProvider.getLevel() instanceof net.minecraft.world.level.Level) { -+ this.lightEngine = new ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface(chunkProvider, hasSkyLight, hasBlockLight, (LevelLightEngine)(Object)this); ++ if (lightChunkGetter.getLevel() instanceof net.minecraft.world.level.Level) { ++ this.lightEngine = new ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface(lightChunkGetter, skyLight, blockLight, (LevelLightEngine)(Object)this); + } else { -+ this.lightEngine = new ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface(null, hasSkyLight, hasBlockLight, (LevelLightEngine)(Object)this); ++ this.lightEngine = new ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface(null, skyLight, blockLight, (LevelLightEngine)(Object)this); + } + // Paper end - rewrite chunk system } @@ -34206,25 +33693,25 @@ index 8d90e783967280025d711c709facbcc87f611f8a..987e3397503cd07d3a2f172cede34129 } @Override - public void updateSectionStatus(SectionPos pos, boolean notReady) { + public void updateSectionStatus(SectionPos pos, boolean isEmpty) { - if (this.blockEngine != null) { -- this.blockEngine.updateSectionStatus(pos, notReady); +- this.blockEngine.updateSectionStatus(pos, isEmpty); - } - - if (this.skyEngine != null) { -- this.skyEngine.updateSectionStatus(pos, notReady); +- this.skyEngine.updateSectionStatus(pos, isEmpty); - } + this.lightEngine.sectionChange(pos, notReady); // Paper - rewrite chunk system } @Override - public void setLightEnabled(ChunkPos pos, boolean retainData) { + public void setLightEnabled(ChunkPos chunkPos, boolean lightEnabled) { - if (this.blockEngine != null) { -- this.blockEngine.setLightEnabled(pos, retainData); +- this.blockEngine.setLightEnabled(chunkPos, lightEnabled); - } - - if (this.skyEngine != null) { -- this.skyEngine.setLightEnabled(pos, retainData); +- this.skyEngine.setLightEnabled(chunkPos, lightEnabled); - } + // Paper - rewrite chunk system } @@ -34241,82 +33728,82 @@ index 8d90e783967280025d711c709facbcc87f611f8a..987e3397503cd07d3a2f172cede34129 + // Paper - rewrite chunk system } - public LayerLightEventListener getLayerListener(LightLayer lightType) { -- if (lightType == LightLayer.BLOCK) { + public LayerLightEventListener getLayerListener(LightLayer type) { +- if (type == LightLayer.BLOCK) { - return (LayerLightEventListener)(this.blockEngine == null ? LayerLightEventListener.DummyLightLayerEventListener.INSTANCE : this.blockEngine); - } else { - return (LayerLightEventListener)(this.skyEngine == null ? LayerLightEventListener.DummyLightLayerEventListener.INSTANCE : this.skyEngine); - } -+ return lightType == LightLayer.BLOCK ? this.lightEngine.getBlockReader() : this.lightEngine.getSkyReader(); // Paper - rewrite chunk system ++ return type == LightLayer.BLOCK ? this.lightEngine.getBlockReader() : this.lightEngine.getSkyReader(); // Paper - rewrite chunk system } - public String getDebugData(LightLayer lightType, SectionPos pos) { -- if (lightType == LightLayer.BLOCK) { + public String getDebugData(LightLayer lightLayer, SectionPos sectionPos) { +- if (lightLayer == LightLayer.BLOCK) { - if (this.blockEngine != null) { -- return this.blockEngine.getDebugData(pos.asLong()); +- return this.blockEngine.getDebugData(sectionPos.asLong()); - } - } else if (this.skyEngine != null) { -- return this.skyEngine.getDebugData(pos.asLong()); +- return this.skyEngine.getDebugData(sectionPos.asLong()); - } - - return "n/a"; + return "n/a"; // Paper - rewrite chunk system } - public LayerLightSectionStorage.SectionType getDebugSectionType(LightLayer lightType, SectionPos pos) { -- if (lightType == LightLayer.BLOCK) { + public LayerLightSectionStorage.SectionType getDebugSectionType(LightLayer lightLayer, SectionPos sectionPos) { +- if (lightLayer == LightLayer.BLOCK) { - if (this.blockEngine != null) { -- return this.blockEngine.getDebugSectionType(pos.asLong()); +- return this.blockEngine.getDebugSectionType(sectionPos.asLong()); - } - } else if (this.skyEngine != null) { -- return this.skyEngine.getDebugSectionType(pos.asLong()); +- return this.skyEngine.getDebugSectionType(sectionPos.asLong()); - } - - return LayerLightSectionStorage.SectionType.EMPTY; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public void queueSectionData(LightLayer lightType, SectionPos pos, @Nullable DataLayer nibbles) { -- if (lightType == LightLayer.BLOCK) { + public void queueSectionData(LightLayer lightLayer, SectionPos sectionPos, @Nullable DataLayer dataLayer) { +- if (lightLayer == LightLayer.BLOCK) { - if (this.blockEngine != null) { -- this.blockEngine.queueSectionData(pos.asLong(), nibbles); +- this.blockEngine.queueSectionData(sectionPos.asLong(), dataLayer); - } - } else if (this.skyEngine != null) { -- this.skyEngine.queueSectionData(pos.asLong(), nibbles); +- this.skyEngine.queueSectionData(sectionPos.asLong(), dataLayer); - } + // Paper - rewrite chunk system } - public void retainData(ChunkPos pos, boolean retainData) { + public void retainData(ChunkPos pos, boolean retain) { - if (this.blockEngine != null) { -- this.blockEngine.retainData(pos, retainData); +- this.blockEngine.retainData(pos, retain); - } - - if (this.skyEngine != null) { -- this.skyEngine.retainData(pos, retainData); +- this.skyEngine.retainData(pos, retain); - } + // Paper - rewrite chunk system } - public int getRawBrightness(BlockPos pos, int ambientDarkness) { -- int i = this.skyEngine == null ? 0 : this.skyEngine.getLightValue(pos) - ambientDarkness; -- int j = this.blockEngine == null ? 0 : this.blockEngine.getLightValue(pos); -- return Math.max(j, i); -+ return this.lightEngine.getRawBrightness(pos, ambientDarkness); // Paper - rewrite chunk system + public int getRawBrightness(BlockPos blockPos, int amount) { +- int i = this.skyEngine == null ? 0 : this.skyEngine.getLightValue(blockPos) - amount; +- int i1 = this.blockEngine == null ? 0 : this.blockEngine.getLightValue(blockPos); +- return Math.max(i1, i); ++ return this.lightEngine.getRawBrightness(blockPos, amount); // Paper - rewrite chunk system } - public boolean lightOnInColumn(long sectionPos) { + public boolean lightOnInColumn(long columnPos) { - return this.blockEngine == null -- || this.blockEngine.storage.lightOnInColumn(sectionPos) && (this.skyEngine == null || this.skyEngine.storage.lightOnInColumn(sectionPos)); +- || this.blockEngine.storage.lightOnInColumn(columnPos) && (this.skyEngine == null || this.skyEngine.storage.lightOnInColumn(columnPos)); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system // Paper - not implemented on server } public int getLightSectionCount() { diff --git a/net/minecraft/world/level/material/FlowingFluid.java b/net/minecraft/world/level/material/FlowingFluid.java -index 261e5994d13f8bc30490b86691c80c0a21e7640a..f4fbcbb8ff6d2677af1a02a0801a323c06dce9b1 100644 +index b9ad980b9a203bbc295f780bf54941f19a2f6525..19beef65b292c474f3a25b6c3ff679e31c17c7f4 100644 --- a/net/minecraft/world/level/material/FlowingFluid.java +++ b/net/minecraft/world/level/material/FlowingFluid.java -@@ -55,6 +55,48 @@ public abstract class FlowingFluid extends Fluid { +@@ -45,6 +45,48 @@ public abstract class FlowingFluid extends Fluid { }); private final Map<FluidState, VoxelShape> shapes = Maps.newIdentityHashMap(); @@ -34362,97 +33849,97 @@ index 261e5994d13f8bc30490b86691c80c0a21e7640a..f4fbcbb8ff6d2677af1a02a0801a323c + } + // Paper end - fluid method optimisations + - public FlowingFluid() {} - @Override -@@ -246,65 +288,70 @@ public abstract class FlowingFluid extends Fluid { + protected void createFluidStateDefinition(StateDefinition.Builder<Fluid, FluidState> builder) { + builder.add(FALLING); +@@ -209,61 +251,71 @@ public abstract class FlowingFluid extends Fluid { } } -- private static boolean canPassThroughWall(Direction face, BlockGetter world, BlockPos pos, BlockState state, BlockPos fromPos, BlockState fromState) { -- VoxelShape voxelshape = fromState.getCollisionShape(world, fromPos); +- private static boolean canPassThroughWall( +- Direction direction, BlockGetter level, BlockPos pos, BlockState state, BlockPos spreadPos, BlockState spreadState +- ) { +- VoxelShape collisionShape = spreadState.getCollisionShape(level, spreadPos); +- if (collisionShape == Shapes.block()) { +- return false; +- } else { +- VoxelShape collisionShape1 = state.getCollisionShape(level, pos); +- if (collisionShape1 == Shapes.block()) { +- return false; +- } else if (collisionShape1 == Shapes.empty() && collisionShape == Shapes.empty()) { +- return true; +- } else { +- Object2ByteLinkedOpenHashMap<FlowingFluid.BlockStatePairKey> map; +- if (!state.getBlock().hasDynamicShape() && !spreadState.getBlock().hasDynamicShape()) { +- map = OCCLUSION_CACHE.get(); +- } else { +- map = null; +- } + // Paper start - fluid method optimisations + private static boolean canPassThroughWall(final Direction direction, final BlockGetter level, -+ final BlockPos fromPos, final BlockState fromState, -+ final BlockPos toPos, final BlockState toState) { ++ final BlockPos fromPos, final BlockState fromState, ++ final BlockPos toPos, final BlockState toState) { + if (((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)fromState).moonrise$emptyCollisionShape() & ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)toState).moonrise$emptyCollisionShape()) { + // don't even try to cache simple cases + return true; + } -- 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; -- } 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(); +- FlowingFluid.BlockStatePairKey blockStatePairKey; +- if (map != null) { +- blockStatePairKey = new FlowingFluid.BlockStatePairKey(state, spreadState, direction); +- byte andMoveToFirst = map.getAndMoveToFirst(blockStatePairKey); +- if (andMoveToFirst != 127) { +- return andMoveToFirst != 0; +- } - } else { -- object2bytelinkedopenhashmap = null; +- blockStatePairKey = null; - } ++ 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; + } -- FlowingFluid.BlockStatePairKey fluidtypeflowing_a; +- boolean flag = !Shapes.mergedFaceOccludes(collisionShape1, collisionShape, direction); +- if (map != null) { +- if (map.size() == 200) { +- map.removeLastByte(); +- } + 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) { -- fluidtypeflowing_a = new FlowingFluid.BlockStatePairKey(state, fromState, face); -- byte b0 = object2bytelinkedopenhashmap.getAndMoveToFirst(fluidtypeflowing_a); +- map.putAndMoveToFirst(blockStatePairKey, (byte)(flag ? 1 : 0)); +- } + 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; -- } -- } else { -- fluidtypeflowing_a = null; -- } -- -- boolean flag = !Shapes.mergedFaceOccludes(voxelshape1, voxelshape, face); +- return flag; + 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(); -+ } -+ } - -- if (object2bytelinkedopenhashmap != null) { -- if (object2bytelinkedopenhashmap.size() == 200) { -- object2bytelinkedopenhashmap.removeLastByte(); -- } + } + } ++ + final VoxelShape shape1 = fromState.getCollisionShape(level, fromPos); + final VoxelShape shape2 = toState.getCollisionShape(level, toPos); - -- object2bytelinkedopenhashmap.putAndMoveToFirst(fluidtypeflowing_a, (byte) (flag ? 1 : 0)); -- } ++ + final boolean result = !Shapes.mergedFaceOccludes(shape1, shape2, direction); - -- 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 result; } + // Paper end - fluid method optimisations ++ public abstract Fluid getFlowing(); public FluidState getFlowing(int level, boolean falling) { -- return (FluidState) ((FluidState) this.getFlowing().defaultFluidState().setValue(FlowingFluid.LEVEL, level)).setValue(FlowingFluid.FALLING, falling); +- return this.getFlowing().defaultFluidState().setValue(LEVEL, Integer.valueOf(level)).setValue(FALLING, Boolean.valueOf(falling)); + // Paper start - fluid method optimisations + final int amount = level; + if (!this.init) { @@ -34466,7 +33953,7 @@ index 261e5994d13f8bc30490b86691c80c0a21e7640a..f4fbcbb8ff6d2677af1a02a0801a323c public abstract Fluid getSource(); public FluidState getSource(boolean falling) { -- return (FluidState) this.getSource().defaultFluidState().setValue(FlowingFluid.FALLING, falling); +- return this.getSource().defaultFluidState().setValue(FALLING, Boolean.valueOf(falling)); + // Paper start - fluid method optimisations + if (!this.init) { + this.init(); @@ -34475,9 +33962,9 @@ index 261e5994d13f8bc30490b86691c80c0a21e7640a..f4fbcbb8ff6d2677af1a02a0801a323c + // Paper end - fluid method optimisations } - protected abstract boolean canConvertToSource(ServerLevel world); + protected abstract boolean canConvertToSource(ServerLevel level); diff --git a/net/minecraft/world/level/material/FluidState.java b/net/minecraft/world/level/material/FluidState.java -index 87adfe152abd1b8b4d547034576883c5d1cdf134..2d50d72bf026d0cf9c546a3c6fc1859379bfd805 100644 +index d2d71b22666639c003d86a6b6403fcbd2912c5af..481cb46973acb9785fdee5732e98aac560c6ec08 100644 --- a/net/minecraft/world/level/material/FluidState.java +++ b/net/minecraft/world/level/material/FluidState.java @@ -22,12 +22,30 @@ import net.minecraft.world.level.block.state.properties.Property; @@ -34509,9 +33996,9 @@ index 87adfe152abd1b8b4d547034576883c5d1cdf134..2d50d72bf026d0cf9c546a3c6fc18593 + } + // Paper end - fluid method optimisations + - public FluidState(Fluid fluid, Reference2ObjectArrayMap<Property<?>, Comparable<?>> propertyMap, MapCodec<FluidState> codec) { - super(fluid, propertyMap, codec); - this.isEmpty = fluid.isEmpty(); // Paper - Perf: moved from isEmpty() + public FluidState(Fluid owner, Reference2ObjectArrayMap<Property<?>, Comparable<?>> values, MapCodec<FluidState> propertiesCodec) { + super(owner, values, propertiesCodec); + this.isEmpty = owner.isEmpty(); // Paper - Perf: moved from isEmpty() @@ -38,11 +56,11 @@ public final class FluidState extends StateHolder<Fluid, FluidState> { } @@ -34539,7 +34026,7 @@ index 87adfe152abd1b8b4d547034576883c5d1cdf134..2d50d72bf026d0cf9c546a3c6fc18593 + return this.amount; // Paper - fluid method optimisations } - public boolean shouldRenderBackwardUpFace(BlockGetter world, BlockPos pos) { + public boolean shouldRenderBackwardUpFace(BlockGetter level, BlockPos pos) { @@ -84,7 +102,7 @@ public final class FluidState extends StateHolder<Fluid, FluidState> { } @@ -34548,7 +34035,7 @@ index 87adfe152abd1b8b4d547034576883c5d1cdf134..2d50d72bf026d0cf9c546a3c6fc18593 + return this.isRandomlyTicking; // Paper - fluid method optimisations } - public void randomTick(ServerLevel world, BlockPos pos, RandomSource random) { + public void randomTick(ServerLevel level, BlockPos pos, RandomSource random) { @@ -96,7 +114,12 @@ public final class FluidState extends StateHolder<Fluid, FluidState> { } @@ -34564,31 +34051,31 @@ index 87adfe152abd1b8b4d547034576883c5d1cdf134..2d50d72bf026d0cf9c546a3c6fc18593 @Nullable diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java -index 5dc2674b537f4a61b2e21a21bdb2e8dc090d3a3c..6cf6d4ec7b9e43c7b2b4c0e2fb080964ff588130 100644 +index 047e1fd078d7f49a2547daeca9eec31306d25dd0..85148858db1fd5e9da8bbdde4b0d84110d80e373 100644 --- a/net/minecraft/world/phys/AABB.java +++ b/net/minecraft/world/phys/AABB.java -@@ -331,7 +331,7 @@ public class AABB { +@@ -314,7 +314,7 @@ public class AABB { } @Nullable -- private static Direction getDirection( -+ public static Direction getDirection( // Paper - optimise collisions - public - AABB box, Vec3 intersectingVector, double[] traceDistanceResult, @Nullable Direction approachDirection, double deltaX, double deltaY, double deltaZ - ) { - return getDirection( +- private static Direction getDirection(AABB aabb, Vec3 start, double[] minDistance, @Nullable Direction facing, double deltaX, double deltaY, double deltaZ) { ++ public static Direction getDirection(AABB aabb, Vec3 start, double[] minDistance, @Nullable Direction facing, double deltaX, double deltaY, double deltaZ) { // Paper - optimise collisions - public + return getDirection(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ, start, minDistance, facing, deltaX, deltaY, deltaZ); + } + diff --git a/net/minecraft/world/phys/shapes/ArrayVoxelShape.java b/net/minecraft/world/phys/shapes/ArrayVoxelShape.java -index 4fee67f7214b464b9e09862778e3ef187fcb8b72..31a54af04ab072a433d6df9fe37beb12243fea80 100644 +index adb5f1be35d3a712499076719a1bb819ef52b9a8..39a634e1392239e17818a11750ba869ea7d195ce 100644 --- a/net/minecraft/world/phys/shapes/ArrayVoxelShape.java +++ b/net/minecraft/world/phys/shapes/ArrayVoxelShape.java @@ -20,7 +20,7 @@ public class ArrayVoxelShape extends VoxelShape { ); } -- ArrayVoxelShape(DiscreteVoxelShape shape, DoubleList xPoints, DoubleList yPoints, DoubleList zPoints) { -+ public ArrayVoxelShape(DiscreteVoxelShape shape, DoubleList xPoints, DoubleList yPoints, DoubleList zPoints) { // Paper - optimise collisions - public +- ArrayVoxelShape(DiscreteVoxelShape shape, DoubleList xs, DoubleList ys, DoubleList zs) { ++ public ArrayVoxelShape(DiscreteVoxelShape shape, DoubleList xs, DoubleList ys, DoubleList zs) { // Paper - optimise collisions - public super(shape); int i = shape.getXSize() + 1; - int j = shape.getYSize() + 1; + int i1 = shape.getYSize() + 1; @@ -34,6 +34,7 @@ public class ArrayVoxelShape extends VoxelShape { new IllegalArgumentException("Lengths of point arrays must be consistent with the size of the VoxelShape.") ); @@ -34598,7 +34085,7 @@ index 4fee67f7214b464b9e09862778e3ef187fcb8b72..31a54af04ab072a433d6df9fe37beb12 @Override diff --git a/net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape.java b/net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape.java -index e8f3307727e7e3da9a7629cafc6e1ee53790b75d..97ef481156ec5d821779f126ab98a8f28cbaf30b 100644 +index 14a12bdaa428556fa7b0c43e37b79699ae2fcb92..3a56e4ad9b3cba0cdf4bc373f7d0457d8643fdc4 100644 --- a/net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape.java +++ b/net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape.java @@ -4,13 +4,13 @@ import java.util.BitSet; @@ -34620,14 +34107,14 @@ index e8f3307727e7e3da9a7629cafc6e1ee53790b75d..97ef481156ec5d821779f126ab98a8f2 + public int yMax; // Paper - optimise collisions - public + public int zMax; // Paper - optimise collisions - public - public BitSetDiscreteVoxelShape(int sizeX, int sizeY, int sizeZ) { - super(sizeX, sizeY, sizeZ); + public BitSetDiscreteVoxelShape(int xSize, int ySize, int zSize) { + super(xSize, ySize, zSize); @@ -150,47 +150,109 @@ public final class BitSetDiscreteVoxelShape extends DiscreteVoxelShape { return bitSetDiscreteVoxelShape; } -- protected static void forAllBoxes(DiscreteVoxelShape voxelSet, DiscreteVoxelShape.IntLineConsumer callback, boolean coalesce) { -- BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = new BitSetDiscreteVoxelShape(voxelSet); +- protected static void forAllBoxes(DiscreteVoxelShape shape, DiscreteVoxelShape.IntLineConsumer consumer, boolean combine) { +- BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = new BitSetDiscreteVoxelShape(shape); + // Paper start - optimise collisions + public static void forAllBoxes(final DiscreteVoxelShape shape, final DiscreteVoxelShape.IntLineConsumer consumer, final boolean mergeAdjacent) { + // Paper - remove debug @@ -34669,19 +34156,19 @@ index e8f3307727e7e3da9a7629cafc6e1ee53790b75d..97ef481156ec5d821779f126ab98a8f2 + // this branch is actually important to optimise, as it affects uncached toAabbs() (which affects optimize()) - for (int i = 0; i < bitSetDiscreteVoxelShape.ySize; i++) { -- for (int j = 0; j < bitSetDiscreteVoxelShape.xSize; j++) { -- int k = -1; +- for (int i1 = 0; i1 < bitSetDiscreteVoxelShape.xSize; i1++) { +- int i2 = -1; + // only clone when we may write to it + bitset = ca.spottedleaf.moonrise.common.util.MixinWorkarounds.clone(bitset); -- for (int l = 0; l <= bitSetDiscreteVoxelShape.zSize; l++) { -- if (bitSetDiscreteVoxelShape.isFullWide(j, i, l)) { -- if (coalesce) { -- if (k == -1) { -- k = l; +- for (int i3 = 0; i3 <= bitSetDiscreteVoxelShape.zSize; i3++) { +- if (bitSetDiscreteVoxelShape.isFullWide(i1, i, i3)) { +- if (combine) { +- if (i2 == -1) { +- i2 = i3; - } - } else { -- callback.consume(j, i, l, j + 1, i + 1, l + 1); +- consumer.consume(i1, i, i3, i1 + 1, i + 1, i3 + 1); + for (int y = 0; y < sizeY; ++y, indexY += incY) { + indexX = indexY; + for (int x = 0; x < sizeX; ++x, indexX += incX) { @@ -34696,14 +34183,14 @@ index e8f3307727e7e3da9a7629cafc6e1ee53790b75d..97ef481156ec5d821779f126ab98a8f2 + if (lastSetZ == -1) { + lastSetZ = endIndex; } -- } else if (k != -1) { -- int m = j; -- int n = i; -- bitSetDiscreteVoxelShape.clearZStrip(k, l, j, i); +- } else if (i2 != -1) { +- int i4 = i1; +- int i5 = i; +- bitSetDiscreteVoxelShape.clearZStrip(i2, i3, i1, i); - -- while (bitSetDiscreteVoxelShape.isZStripFull(k, l, m + 1, i)) { -- bitSetDiscreteVoxelShape.clearZStrip(k, l, m + 1, i); -- m++; +- while (bitSetDiscreteVoxelShape.isZStripFull(i2, i3, i4 + 1, i)) { +- bitSetDiscreteVoxelShape.clearZStrip(i2, i3, i4 + 1, i); +- i4++; + + ca.spottedleaf.moonrise.common.util.FlatBitsetUtil.clearRange(bitset, firstSetZ, lastSetZ); + @@ -34717,9 +34204,9 @@ index e8f3307727e7e3da9a7629cafc6e1ee53790b75d..97ef481156ec5d821779f126ab98a8f2 + ca.spottedleaf.moonrise.common.util.FlatBitsetUtil.clearRange(bitset, neighbourIdxStart, neighbourIdxEnd); } -- while (bitSetDiscreteVoxelShape.isXZRectangleFull(j, m + 1, k, l, n + 1)) { -- for (int o = j; o <= m; o++) { -- bitSetDiscreteVoxelShape.clearZStrip(k, l, o, n + 1); +- while (bitSetDiscreteVoxelShape.isXZRectangleFull(i1, i4 + 1, i2, i3, i5 + 1)) { +- for (int i6 = i1; i6 <= i4; i6++) { +- bitSetDiscreteVoxelShape.clearZStrip(i2, i3, i6, i5 + 1); + // try to merge neighbouring on the Y axis + + int endY; // exclusive @@ -34736,7 +34223,7 @@ index e8f3307727e7e3da9a7629cafc6e1ee53790b75d..97ef481156ec5d821779f126ab98a8f2 + } } -- n++; +- i5++; + ++endY; + + // passed, so we can clear it @@ -34746,8 +34233,8 @@ index e8f3307727e7e3da9a7629cafc6e1ee53790b75d..97ef481156ec5d821779f126ab98a8f2 + } } -- callback.consume(j, i, k, m + 1, n + 1, l); -- k = -1; +- consumer.consume(i1, i, i2, i4 + 1, i5 + 1, i3); +- i2 = -1; + consumer.consume(x, y, firstSetZ - indexX, endX, endY, lastSetZ - indexX); + zIdx = lastSetZ; } @@ -34757,22 +34244,22 @@ index e8f3307727e7e3da9a7629cafc6e1ee53790b75d..97ef481156ec5d821779f126ab98a8f2 } + // Paper end - optimise collisions - private boolean isZStripFull(int z1, int z2, int x, int y) { - return x < this.xSize && y < this.ySize && this.storage.nextClearBit(this.getIndex(x, y, z1)) >= this.getIndex(x, y, z2); + private boolean isZStripFull(int zMin, int zMax, int x, int y) { + return x < this.xSize && y < this.ySize && this.storage.nextClearBit(this.getIndex(x, y, zMin)) >= this.getIndex(x, y, zMax); diff --git a/net/minecraft/world/phys/shapes/CubeVoxelShape.java b/net/minecraft/world/phys/shapes/CubeVoxelShape.java -index d812949c7329ae2696b38dc792fa011ba87decb9..7743495c7ec3fc5e17947144457cef7bbe0f4b38 100644 +index f6b6481591e009de80f6b6318d35f193aabb7df3..e9b5069dcd572966b2f5aa220cef30e7a328fa2c 100644 --- a/net/minecraft/world/phys/shapes/CubeVoxelShape.java +++ b/net/minecraft/world/phys/shapes/CubeVoxelShape.java @@ -7,6 +7,7 @@ import net.minecraft.util.Mth; public final class CubeVoxelShape extends VoxelShape { - protected CubeVoxelShape(DiscreteVoxelShape voxels) { - super(voxels); + protected CubeVoxelShape(DiscreteVoxelShape shape) { + super(shape); + ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)this).moonrise$initCache(); // Paper - optimise collisions } @Override diff --git a/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java b/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java -index 01693ba050b12b9debcdaefceeff9cbcd503b369..fbe0c4b0fdbb992b7002f6afe1e74d63cbb420f2 100644 +index 4fc61b329ccb7c9aeb6105dc53d71545a3baea89..309a34f192f7737204ce7a5c3b4004bdd83842f2 100644 --- a/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java +++ b/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java @@ -3,12 +3,79 @@ package net.minecraft.world.phys.shapes; @@ -34853,11 +34340,11 @@ index 01693ba050b12b9debcdaefceeff9cbcd503b369..fbe0c4b0fdbb992b7002f6afe1e74d63 + } + // Paper end - optimise collisions + - protected DiscreteVoxelShape(int sizeX, int sizeY, int sizeZ) { - if (sizeX >= 0 && sizeY >= 0 && sizeZ >= 0) { - this.xSize = sizeX; + protected DiscreteVoxelShape(int xSize, int ySize, int zSize) { + if (xSize >= 0 && ySize >= 0 && zSize >= 0) { + this.xSize = xSize; diff --git a/net/minecraft/world/phys/shapes/OffsetDoubleList.java b/net/minecraft/world/phys/shapes/OffsetDoubleList.java -index 7ec02a7849437a18860aa0df7d9ddd71b2447d4c..5e45e49ab09344cb95736f4124b1c6e002ef5b82 100644 +index ac1488875537421b74f0c491c9b7a40e75539c92..9eb27eb8d6dcaad6ce02f8ce4546acc224c4196f 100644 --- a/net/minecraft/world/phys/shapes/OffsetDoubleList.java +++ b/net/minecraft/world/phys/shapes/OffsetDoubleList.java @@ -4,8 +4,8 @@ import it.unimi.dsi.fastutil.doubles.AbstractDoubleList; @@ -34869,10 +34356,10 @@ index 7ec02a7849437a18860aa0df7d9ddd71b2447d4c..5e45e49ab09344cb95736f4124b1c6e0 + public final DoubleList delegate; // Paper - optimise collisions - public + public final double offset; // Paper - optimise collisions - public - public OffsetDoubleList(DoubleList oldList, double offset) { - this.delegate = oldList; + public OffsetDoubleList(DoubleList delegate, double offset) { + this.delegate = delegate; diff --git a/net/minecraft/world/phys/shapes/Shapes.java b/net/minecraft/world/phys/shapes/Shapes.java -index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f175394c0 100644 +index e759221fb54aa510d2d8bbba47e1d794367aec6d..5665cfaae4fc9e72b77fd41e16e7f64460b099b0 100644 --- a/net/minecraft/world/phys/shapes/Shapes.java +++ b/net/minecraft/world/phys/shapes/Shapes.java @@ -16,9 +16,15 @@ public final class Shapes { @@ -34932,9 +34419,9 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + // Paper start - optimise collisions if (!(maxX - minX < 1.0E-7) && !(maxY - minY < 1.0E-7) && !(maxZ - minZ < 1.0E-7)) { - int i = findBits(minX, maxX); -- int j = findBits(minY, maxY); -- int k = findBits(minZ, maxZ); -- if (i < 0 || j < 0 || k < 0) { +- int i1 = findBits(minY, maxY); +- int i2 = findBits(minZ, maxZ); +- if (i < 0 || i1 < 0 || i2 < 0) { + final int bitsX = findBits(minX, maxX); + final int bitsY = findBits(minY, maxY); + final int bitsZ = findBits(minZ, maxZ); @@ -34967,22 +34454,22 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + 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) { +- } else if (i == 0 && i1 == 0 && i2 == 0) { - return block(); - } else { -- int l = 1 << i; -- int m = 1 << j; -- int n = 1 << k; +- int i3 = 1 << i; +- int i4 = 1 << i1; +- int i5 = 1 << i2; - BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = BitSetDiscreteVoxelShape.withFilledBounds( -- l, -- m, -- n, -- (int)Math.round(minX * (double)l), -- (int)Math.round(minY * (double)m), -- (int)Math.round(minZ * (double)n), -- (int)Math.round(maxX * (double)l), -- (int)Math.round(maxY * (double)m), -- (int)Math.round(maxZ * (double)n) +- i3, +- i4, +- i5, +- (int)Math.round(minX * i3), +- (int)Math.round(minY * i4), +- (int)Math.round(minZ * i5), +- (int)Math.round(maxX * i3), +- (int)Math.round(maxY * i4), +- (int)Math.round(maxZ * i5) - ); - return new CubeVoxelShape(bitSetDiscreteVoxelShape); } @@ -34993,18 +34480,15 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + // Paper end - optimise collisions } - public static VoxelShape create(AABB box) { -@@ -119,80 +152,54 @@ public final class Shapes { - return join(first, second, BooleanOp.OR); + public static VoxelShape create(AABB aabb) { +@@ -120,85 +153,52 @@ public final class Shapes { } -- public static VoxelShape or(VoxelShape first, VoxelShape... others) { -- return Arrays.stream(others).reduce(first, Shapes::or); -+ // Paper start - optimise collisions -+ public static VoxelShape or(VoxelShape shape, VoxelShape... others) { + public static VoxelShape or(VoxelShape shape1, VoxelShape... others) { +- return Arrays.stream(others).reduce(shape1, Shapes::or); + int size = others.length; + if (size == 0) { -+ return shape; ++ return shape1; + } + + // reduce complexity of joins by splitting the merges @@ -35013,7 +34497,7 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + ++size; + final VoxelShape[] tmp = Arrays.copyOf(others, size); + // insert first shape -+ tmp[size - 1] = shape; ++ tmp[size - 1] = shape1; + + while (size > 1) { + int newSize = 0; @@ -35038,88 +34522,94 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + // Paper end - optimise collisions } - public static VoxelShape join(VoxelShape first, VoxelShape second, BooleanOp function) { -- return joinUnoptimized(first, second, function).optimize(); -+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.joinOptimized(first, second, function); // Paper - optimise collisions + public static VoxelShape join(VoxelShape shape1, VoxelShape shape2, BooleanOp function) { +- return joinUnoptimized(shape1, shape2, function).optimize(); ++ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.joinOptimized(shape1, shape2, function); // Paper - optimise collisions } - public static VoxelShape joinUnoptimized(VoxelShape one, VoxelShape two, BooleanOp function) { + public static VoxelShape joinUnoptimized(VoxelShape shape1, VoxelShape shape2, BooleanOp function) { - if (function.apply(false, false)) { - throw (IllegalArgumentException)Util.pauseInIde(new IllegalArgumentException()); -- } else if (one == two) { -- return function.apply(true, true) ? one : empty(); +- } else if (shape1 == shape2) { +- return function.apply(true, true) ? shape1 : empty(); - } else { -- boolean bl = function.apply(true, false); -- boolean bl2 = function.apply(false, true); -- if (one.isEmpty()) { -- return bl2 ? two : empty(); -- } else if (two.isEmpty()) { -- return bl ? one : empty(); +- boolean flag = function.apply(true, false); +- boolean flag1 = function.apply(false, true); +- if (shape1.isEmpty()) { +- return flag1 ? shape2 : empty(); +- } else if (shape2.isEmpty()) { +- return flag ? shape1 : empty(); - } else { -- IndexMerger indexMerger = createIndexMerger(1, one.getCoords(Direction.Axis.X), two.getCoords(Direction.Axis.X), bl, bl2); -- IndexMerger indexMerger2 = createIndexMerger(indexMerger.size() - 1, one.getCoords(Direction.Axis.Y), two.getCoords(Direction.Axis.Y), bl, bl2); -- IndexMerger indexMerger3 = createIndexMerger( -- (indexMerger.size() - 1) * (indexMerger2.size() - 1), one.getCoords(Direction.Axis.Z), two.getCoords(Direction.Axis.Z), bl, bl2 +- IndexMerger indexMerger = createIndexMerger(1, shape1.getCoords(Direction.Axis.X), shape2.getCoords(Direction.Axis.X), flag, flag1); +- IndexMerger indexMerger1 = createIndexMerger( +- indexMerger.size() - 1, shape1.getCoords(Direction.Axis.Y), shape2.getCoords(Direction.Axis.Y), flag, flag1 +- ); +- IndexMerger indexMerger2 = createIndexMerger( +- (indexMerger.size() - 1) * (indexMerger1.size() - 1), shape1.getCoords(Direction.Axis.Z), shape2.getCoords(Direction.Axis.Z), flag, flag1 - ); - BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = BitSetDiscreteVoxelShape.join( -- one.shape, two.shape, indexMerger, indexMerger2, indexMerger3, function +- shape1.shape, shape2.shape, indexMerger, indexMerger1, indexMerger2, function - ); - return (VoxelShape)(indexMerger instanceof DiscreteCubeMerger +- && indexMerger1 instanceof DiscreteCubeMerger - && indexMerger2 instanceof DiscreteCubeMerger -- && indexMerger3 instanceof DiscreteCubeMerger - ? new CubeVoxelShape(bitSetDiscreteVoxelShape) -- : new ArrayVoxelShape(bitSetDiscreteVoxelShape, indexMerger.getList(), indexMerger2.getList(), indexMerger3.getList())); +- : new ArrayVoxelShape(bitSetDiscreteVoxelShape, indexMerger.getList(), indexMerger1.getList(), indexMerger2.getList())); - } - } -+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.joinUnoptimized(one, two, function); // Paper - optimise collisions ++ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.joinUnoptimized(shape1, shape2, function); // Paper - optimise collisions } - public static boolean joinIsNotEmpty(VoxelShape shape1, VoxelShape shape2, BooleanOp predicate) { -- if (predicate.apply(false, false)) { + public static boolean joinIsNotEmpty(VoxelShape shape1, VoxelShape shape2, BooleanOp resultOperator) { +- if (resultOperator.apply(false, false)) { - throw (IllegalArgumentException)Util.pauseInIde(new IllegalArgumentException()); - } else { -- boolean bl = shape1.isEmpty(); -- boolean bl2 = shape2.isEmpty(); -- if (!bl && !bl2) { +- boolean isEmpty = shape1.isEmpty(); +- boolean isEmpty1 = shape2.isEmpty(); +- if (!isEmpty && !isEmpty1) { - if (shape1 == shape2) { -- return predicate.apply(true, true); +- return resultOperator.apply(true, true); - } else { -- boolean bl3 = predicate.apply(true, false); -- boolean bl4 = predicate.apply(false, true); +- boolean flag = resultOperator.apply(true, false); +- boolean flag1 = resultOperator.apply(false, true); - - for (Direction.Axis axis : AxisCycle.AXIS_VALUES) { - if (shape1.max(axis) < shape2.min(axis) - 1.0E-7) { -- return bl3 || bl4; +- return flag || flag1; - } - - if (shape2.max(axis) < shape1.min(axis) - 1.0E-7) { -- return bl3 || bl4; +- return flag || flag1; - } - } - -- IndexMerger indexMerger = createIndexMerger(1, shape1.getCoords(Direction.Axis.X), shape2.getCoords(Direction.Axis.X), bl3, bl4); -- IndexMerger indexMerger2 = createIndexMerger( -- indexMerger.size() - 1, shape1.getCoords(Direction.Axis.Y), shape2.getCoords(Direction.Axis.Y), bl3, bl4 +- IndexMerger indexMerger = createIndexMerger(1, shape1.getCoords(Direction.Axis.X), shape2.getCoords(Direction.Axis.X), flag, flag1); +- IndexMerger indexMerger1 = createIndexMerger( +- indexMerger.size() - 1, shape1.getCoords(Direction.Axis.Y), shape2.getCoords(Direction.Axis.Y), flag, flag1 - ); -- IndexMerger indexMerger3 = createIndexMerger( -- (indexMerger.size() - 1) * (indexMerger2.size() - 1), shape1.getCoords(Direction.Axis.Z), shape2.getCoords(Direction.Axis.Z), bl3, bl4 +- IndexMerger indexMerger2 = createIndexMerger( +- (indexMerger.size() - 1) * (indexMerger1.size() - 1), +- shape1.getCoords(Direction.Axis.Z), +- shape2.getCoords(Direction.Axis.Z), +- flag, +- flag1 - ); -- return joinIsNotEmpty(indexMerger, indexMerger2, indexMerger3, shape1.shape, shape2.shape, predicate); +- return joinIsNotEmpty(indexMerger, indexMerger1, indexMerger2, shape1.shape, shape2.shape, resultOperator); - } - } else { -- return predicate.apply(!bl, !bl2); +- return resultOperator.apply(!isEmpty, !isEmpty1); - } - } -+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isJoinNonEmpty(shape1, shape2, predicate); // Paper - optimise collisions ++ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isJoinNonEmpty(shape1, shape2, resultOperator); // Paper - optimise collisions } private static boolean joinIsNotEmpty( -@@ -219,51 +226,116 @@ public final class Shapes { - return maxDist; +@@ -230,52 +230,116 @@ public final class Shapes { + return desiredOffset; } -- public static boolean blockOccudes(VoxelShape shape, VoxelShape neighbor, Direction direction) { -- if (shape == block() && neighbor == block()) { +- public static boolean blockOccudes(VoxelShape shape, VoxelShape adjacentShape, Direction side) { +- if (shape == block() && adjacentShape == block()) { + // Paper start - optimise collisions + public static boolean blockOccudes(final VoxelShape first, final VoxelShape second, final Direction direction) { + final boolean firstBlock = first == BLOCK; @@ -35127,7 +34617,7 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + + if (firstBlock & secondBlock) { return true; -- } else if (neighbor.isEmpty()) { +- } else if (adjacentShape.isEmpty()) { + } + + if (first.isEmpty() | second.isEmpty()) { @@ -35140,14 +34630,14 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + if (newFirst.isEmpty()) { return false; - } else { -- Direction.Axis axis = direction.getAxis(); -- Direction.AxisDirection axisDirection = direction.getAxisDirection(); -- VoxelShape voxelShape = axisDirection == Direction.AxisDirection.POSITIVE ? shape : neighbor; -- VoxelShape voxelShape2 = axisDirection == Direction.AxisDirection.POSITIVE ? neighbor : shape; +- Direction.Axis axis = side.getAxis(); +- Direction.AxisDirection axisDirection = side.getAxisDirection(); +- VoxelShape voxelShape = axisDirection == Direction.AxisDirection.POSITIVE ? shape : adjacentShape; +- VoxelShape voxelShape1 = axisDirection == Direction.AxisDirection.POSITIVE ? adjacentShape : shape; - BooleanOp booleanOp = axisDirection == Direction.AxisDirection.POSITIVE ? BooleanOp.ONLY_FIRST : BooleanOp.ONLY_SECOND; - return DoubleMath.fuzzyEquals(voxelShape.max(axis), 1.0, 1.0E-7) -- && DoubleMath.fuzzyEquals(voxelShape2.min(axis), 0.0, 1.0E-7) -- && !joinIsNotEmpty(new SliceShape(voxelShape, axis, voxelShape.shape.getSize(axis) - 1), new SliceShape(voxelShape2, axis, 0), booleanOp); +- && DoubleMath.fuzzyEquals(voxelShape1.min(axis), 0.0, 1.0E-7) +- && !joinIsNotEmpty(new SliceShape(voxelShape, axis, voxelShape.shape.getSize(axis) - 1), new SliceShape(voxelShape1, axis, 0), booleanOp); } + final VoxelShape newSecond = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$getFaceShapeClamped(direction.getOpposite()); + if (newSecond.isEmpty()) { @@ -35158,12 +34648,12 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + // Paper end - optimise collisions } -- public static boolean mergedFaceOccludes(VoxelShape one, VoxelShape two, Direction direction) { -- if (one != block() && two != block()) { -- Direction.Axis axis = direction.getAxis(); -- Direction.AxisDirection axisDirection = direction.getAxisDirection(); -- VoxelShape voxelShape = axisDirection == Direction.AxisDirection.POSITIVE ? one : two; -- VoxelShape voxelShape2 = axisDirection == Direction.AxisDirection.POSITIVE ? two : one; +- public static boolean mergedFaceOccludes(VoxelShape shape, VoxelShape adjacentShape, Direction side) { +- if (shape != block() && adjacentShape != block()) { +- Direction.Axis axis = side.getAxis(); +- Direction.AxisDirection axisDirection = side.getAxisDirection(); +- VoxelShape voxelShape = axisDirection == Direction.AxisDirection.POSITIVE ? shape : adjacentShape; +- VoxelShape voxelShape1 = axisDirection == Direction.AxisDirection.POSITIVE ? adjacentShape : shape; - if (!DoubleMath.fuzzyEquals(voxelShape.max(axis), 1.0, 1.0E-7)) { - voxelShape = empty(); - } @@ -35173,8 +34663,8 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + final AABB bounds1 = shape1.bounds(); + final AABB bounds2 = shape2.bounds(); -- if (!DoubleMath.fuzzyEquals(voxelShape2.min(axis), 0.0, 1.0E-7)) { -- voxelShape2 = empty(); +- if (!DoubleMath.fuzzyEquals(voxelShape1.min(axis), 0.0, 1.0E-7)) { +- voxelShape1 = empty(); - } + final double minX = Math.min(bounds1.minX, bounds2.minX); + final double minY = Math.min(bounds1.minY, bounds2.minY); @@ -35182,7 +34672,7 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f - return !joinIsNotEmpty( - block(), -- joinUnoptimized(new SliceShape(voxelShape, axis, voxelShape.shape.getSize(axis) - 1), new SliceShape(voxelShape2, axis, 0), BooleanOp.OR), +- joinUnoptimized(new SliceShape(voxelShape, axis, voxelShape.shape.getSize(axis) - 1), new SliceShape(voxelShape1, axis, 0), BooleanOp.OR), - BooleanOp.ONLY_FIRST - ); - } else { @@ -35200,8 +34690,8 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + 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; -+ } + return true; + } + + if (first.isEmpty() & second.isEmpty()) { + return false; @@ -35214,8 +34704,8 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + + // see if any of the shapes on their own occludes, only if cached + if (((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)newFirst).moonrise$occludesFullBlockIfCached() || ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)newSecond).moonrise$occludesFullBlockIfCached()) { - return true; - } ++ return true; ++ } + + final boolean firstEmpty = newFirst.isEmpty(); + final boolean secondEmpty = newSecond.isEmpty(); @@ -35256,29 +34746,30 @@ index 76d7435e6fe81a3f1d24b35eae72d06232a1792b..ca3a2419252721bb3b3b719eb19afb5f + return ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)shape1).moonrise$occludesFullBlock(); + } -- public static boolean faceShapeOccludes(VoxelShape one, VoxelShape two) { -- return one == block() -- || two == block() -- || (!one.isEmpty() || !two.isEmpty()) && !joinIsNotEmpty(block(), joinUnoptimized(one, two, BooleanOp.OR), BooleanOp.ONLY_FIRST); +- public static boolean faceShapeOccludes(VoxelShape voxelShape1, VoxelShape voxelShape2) { +- return voxelShape1 == block() +- || voxelShape2 == block() +- || (!voxelShape1.isEmpty() || !voxelShape2.isEmpty()) +- && !joinIsNotEmpty(block(), joinUnoptimized(voxelShape1, voxelShape2, BooleanOp.OR), BooleanOp.ONLY_FIRST); + return mergedMayOccludeBlock(shape1, shape2) && ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)shape1).moonrise$orUnoptimized(shape2)).moonrise$occludesFullBlock(); + // Paper end - optimise collisions } @VisibleForTesting diff --git a/net/minecraft/world/phys/shapes/SliceShape.java b/net/minecraft/world/phys/shapes/SliceShape.java -index b07f1c58e00d232e7c83e6df3499e4b677645609..b88c71f27996d24d29048e06a69a004617eb53a2 100644 +index 79f7f04207891dd98cc0b2d93ecb2e07c8baa7b6..7ca12213c10f962ff597a8d51413a17b1827bbb4 100644 --- a/net/minecraft/world/phys/shapes/SliceShape.java +++ b/net/minecraft/world/phys/shapes/SliceShape.java @@ -12,6 +12,7 @@ public class SliceShape extends VoxelShape { - super(makeSlice(shape.shape, axis, sliceWidth)); - this.delegate = shape; + super(makeSlice(delegate.shape, axis, index)); + this.delegate = delegate; this.axis = axis; + ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)this).moonrise$initCache(); // Paper - optimise collisions } - private static DiscreteVoxelShape makeSlice(DiscreteVoxelShape voxelSet, Direction.Axis axis, int sliceWidth) { + private static DiscreteVoxelShape makeSlice(DiscreteVoxelShape shape, Direction.Axis axis, int index) { diff --git a/net/minecraft/world/phys/shapes/VoxelShape.java b/net/minecraft/world/phys/shapes/VoxelShape.java -index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9cffc3071 100644 +index 006065c32baf3b1ddc5647196cb9f863c7969064..2c7e70675b62cb753447d2acebf2f36cdac74973 100644 --- a/net/minecraft/world/phys/shapes/VoxelShape.java +++ b/net/minecraft/world/phys/shapes/VoxelShape.java @@ -15,61 +15,546 @@ import net.minecraft.world.phys.AABB; @@ -35706,8 +35197,8 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 + } + // Paper end - optimise collisions + - protected VoxelShape(DiscreteVoxelShape voxels) { - this.shape = voxels; + protected VoxelShape(DiscreteVoxelShape shape) { + this.shape = shape; } public double min(Direction.Axis axis) { @@ -35777,11 +35268,11 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 + // Paper start - optimise collisions + if (this.isEmpty) { + throw Util.pauseInIde(new UnsupportedOperationException("No bounds for empty shape.")); -+ } + } + AABB cached = this.cachedBounds; + if (cached != null) { + return cached; - } ++ } + + final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeData = this.cachedShapeData; + @@ -35856,18 +35347,18 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 + return this.isEmpty; // Paper - optimise collisions } - public VoxelShape move(Vec3 vec3d) { -@@ -77,24 +562,96 @@ public abstract class VoxelShape { + public VoxelShape move(Vec3 offset) { +@@ -77,20 +562,96 @@ public abstract class VoxelShape { } - public VoxelShape move(double x, double y, double z) { + public VoxelShape move(double xOffset, double yOffset, double zOffset) { - return (VoxelShape)(this.isEmpty() - ? Shapes.empty() - : new ArrayVoxelShape( - this.shape, -- new OffsetDoubleList(this.getCoords(Direction.Axis.X), x), -- new OffsetDoubleList(this.getCoords(Direction.Axis.Y), y), -- new OffsetDoubleList(this.getCoords(Direction.Axis.Z), z) +- new OffsetDoubleList(this.getCoords(Direction.Axis.X), xOffset), +- new OffsetDoubleList(this.getCoords(Direction.Axis.Y), yOffset), +- new OffsetDoubleList(this.getCoords(Direction.Axis.Z), zOffset) - )); + // Paper start - optimise collisions + if (this.isEmpty) { @@ -35876,14 +35367,14 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 + + final ArrayVoxelShape ret = new ArrayVoxelShape( + this.shape, -+ offsetList(this.rootCoordinatesX, this.offsetX + x), -+ offsetList(this.rootCoordinatesY, this.offsetY + y), -+ offsetList(this.rootCoordinatesZ, this.offsetZ + z) ++ offsetList(this.rootCoordinatesX, this.offsetX + xOffset), ++ offsetList(this.rootCoordinatesY, this.offsetY + yOffset), ++ offsetList(this.rootCoordinatesZ, this.offsetZ + zOffset) + ); + + final ca.spottedleaf.moonrise.patches.collisions.shape.CachedToAABBs cachedToAABBs = this.cachedToAABBs; + if (cachedToAABBs != null) { -+ ((VoxelShape)(Object)ret).cachedToAABBs = ca.spottedleaf.moonrise.patches.collisions.shape.CachedToAABBs.offset(cachedToAABBs, x, y, z); ++ ((VoxelShape)(Object)ret).cachedToAABBs = ca.spottedleaf.moonrise.patches.collisions.shape.CachedToAABBs.offset(cachedToAABBs, xOffset, yOffset, zOffset); + } + + return ret; @@ -35892,11 +35383,7 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 public VoxelShape optimize() { - VoxelShape[] voxelShapes = new VoxelShape[]{Shapes.empty()}; -- this.forAllBoxes( -- (minX, minY, minZ, maxX, maxY, maxZ) -> voxelShapes[0] = Shapes.joinUnoptimized( -- voxelShapes[0], Shapes.box(minX, minY, minZ, maxX, maxY, maxZ), BooleanOp.OR -- ) -- ); +- this.forAllBoxes((x1, y1, z1, x2, y2, z2) -> voxelShapes[0] = Shapes.joinUnoptimized(voxelShapes[0], Shapes.box(x1, y1, z1, x2, y2, z2), BooleanOp.OR)); - return voxelShapes[0]; + // Paper start - optimise collisions + if (this.isEmpty) { @@ -35968,8 +35455,8 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 + // Paper end - optimise collisions } - public void forAllEdges(Shapes.DoubleLineConsumer consumer) { -@@ -131,9 +688,24 @@ public abstract class VoxelShape { + public void forAllEdges(Shapes.DoubleLineConsumer action) { +@@ -122,9 +683,24 @@ public abstract class VoxelShape { } public List<AABB> toAabbs() { @@ -35996,14 +35483,14 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 + // Paper end - optimise collisions } - public double min(Direction.Axis axis, double from, double to) { -@@ -155,46 +727,92 @@ public abstract class VoxelShape { + public double min(Direction.Axis axis, double primaryPosition, double secondaryPosition) { +@@ -146,46 +722,92 @@ public abstract class VoxelShape { } - protected int findIndex(Direction.Axis axis, double coord) { -- return Mth.binarySearch(0, this.shape.getSize(axis) + 1, i -> coord < this.get(axis, i)) - 1; + protected int findIndex(Direction.Axis axis, double position) { +- return Mth.binarySearch(0, this.shape.getSize(axis) + 1, value -> position < this.get(axis, value)) - 1; + // Paper start - optimise collisions -+ final double value = coord; ++ final double value = position; + switch (axis) { + case X: { + final double[] values = this.rootCoordinatesX; @@ -36031,68 +35518,66 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 } @Nullable -- public BlockHitResult clip(Vec3 start, Vec3 end, BlockPos pos) { + public BlockHitResult clip(Vec3 startVec, Vec3 endVec, BlockPos pos) { - if (this.isEmpty()) { -+ // Paper start - optimise collisions -+ public BlockHitResult clip(final Vec3 from, final Vec3 to, final BlockPos offset) { ++ // Paper start - optimise collisions + if (this.isEmpty) { return null; - } else { -- Vec3 vec3 = end.subtract(start); +- Vec3 vec3 = endVec.subtract(startVec); - if (vec3.lengthSqr() < 1.0E-7) { - return null; - } else { -- Vec3 vec32 = start.add(vec3.scale(0.001)); +- Vec3 vec31 = startVec.add(vec3.scale(0.001)); - return this.shape - .isFullWide( -- this.findIndex(Direction.Axis.X, vec32.x - (double)pos.getX()), -- this.findIndex(Direction.Axis.Y, vec32.y - (double)pos.getY()), -- this.findIndex(Direction.Axis.Z, vec32.z - (double)pos.getZ()) +- this.findIndex(Direction.Axis.X, vec31.x - pos.getX()), +- this.findIndex(Direction.Axis.Y, vec31.y - pos.getY()), +- this.findIndex(Direction.Axis.Z, vec31.z - pos.getZ()) - ) -- ? new BlockHitResult(vec32, Direction.getApproximateNearest(vec3.x, vec3.y, vec3.z).getOpposite(), pos, true) -- : AABB.clip(this.toAabbs(), start, end, pos); +- ? new BlockHitResult(vec31, Direction.getApproximateNearest(vec3.x, vec3.y, vec3.z).getOpposite(), pos, true) +- : AABB.clip(this.toAabbs(), startVec, endVec, pos); + } + -+ final Vec3 directionOpposite = to.subtract(from); ++ final Vec3 directionOpposite = endVec.subtract(startVec); + if (directionOpposite.lengthSqr() < ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON) { + return null; + } + -+ final Vec3 fromBehind = from.add(directionOpposite.scale(0.001)); -+ final double fromBehindOffsetX = fromBehind.x - (double)offset.getX(); -+ final double fromBehindOffsetY = fromBehind.y - (double)offset.getY(); -+ final double fromBehindOffsetZ = fromBehind.z - (double)offset.getZ(); ++ final Vec3 fromBehind = startVec.add(directionOpposite.scale(0.001)); ++ final double fromBehindOffsetX = fromBehind.x - (double) pos.getX(); ++ final double fromBehindOffsetY = fromBehind.y - (double) pos.getY(); ++ final double fromBehindOffsetZ = fromBehind.z - (double) pos.getZ(); + + final AABB singleAABB = this.singleAABBRepresentation; + if (singleAABB != null) { + if (singleAABB.contains(fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) { -+ return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true); ++ return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), pos, true); } -+ return clip(singleAABB, from, to, offset); ++ return clip(singleAABB, startVec, endVec, pos); + } + -+ if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.strictlyContains((VoxelShape)(Object)this, fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) { -+ return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true); ++ if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.strictlyContains((VoxelShape) (Object) this, fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) { ++ return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), pos, true); } + -+ return AABB.clip(((VoxelShape)(Object)this).toAabbs(), from, to, offset); ++ return AABB.clip(((VoxelShape) (Object) this).toAabbs(), startVec, endVec, pos); + // Paper end - optimise collisions } -- public Optional<Vec3> closestPointTo(Vec3 target) { -- if (this.isEmpty()) { + // Paper start - optimise collisions -+ public Optional<Vec3> closestPointTo(Vec3 point) { + public Optional<Vec3> closestPointTo(Vec3 point) { +- if (this.isEmpty()) { + if (this.isEmpty) { return Optional.empty(); - } else { - Vec3[] vec3s = new Vec3[1]; -- this.forAllBoxes((minX, minY, minZ, maxX, maxY, maxZ) -> { -- double d = Mth.clamp(target.x(), minX, maxX); -- double e = Mth.clamp(target.y(), minY, maxY); -- double f = Mth.clamp(target.z(), minZ, maxZ); -- if (vec3s[0] == null || target.distanceToSqr(d, e, f) < target.distanceToSqr(vec3s[0])) { -- vec3s[0] = new Vec3(d, e, f); +- this.forAllBoxes((x1, y1, z1, x2, y2, z2) -> { +- double d = Mth.clamp(point.x(), x1, x2); +- double d1 = Mth.clamp(point.y(), y1, y2); +- double d2 = Mth.clamp(point.z(), z1, z2); +- if (vec3s[0] == null || point.distanceToSqr(d, d1, d2) < point.distanceToSqr(vec3s[0])) { +- vec3s[0] = new Vec3(d, d1, d2); - } - }); - return Optional.of(vec3s[0]); @@ -36119,35 +35604,33 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 + // Paper end - optimise collisions } - public VoxelShape getFaceShape(Direction facing) { -@@ -216,20 +834,24 @@ public abstract class VoxelShape { - } + public VoxelShape getFaceShape(Direction side) { +@@ -208,19 +830,23 @@ public abstract class VoxelShape { } -- private VoxelShape calculateFace(Direction facing) { -- Direction.Axis axis = facing.getAxis(); + private VoxelShape calculateFace(Direction side) { +- Direction.Axis axis = side.getAxis(); - if (this.isCubeLikeAlong(axis)) { - return this; - } else { -- Direction.AxisDirection axisDirection = facing.getAxisDirection(); +- Direction.AxisDirection axisDirection = side.getAxisDirection(); - int i = this.findIndex(axis, axisDirection == Direction.AxisDirection.POSITIVE ? 0.9999999 : 1.0E-7); - 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(); ++ final Direction.Axis axis = side.getAxis(); + switch (axis) { + case X: { -+ return this.calculateFaceDirect(direction, axis, this.rootCoordinatesX, this.offsetX); ++ return this.calculateFaceDirect(side, axis, this.rootCoordinatesX, this.offsetX); + } + case Y: { -+ return this.calculateFaceDirect(direction, axis, this.rootCoordinatesY, this.offsetY); ++ return this.calculateFaceDirect(side, axis, this.rootCoordinatesY, this.offsetY); + } + case Z: { -+ return this.calculateFaceDirect(direction, axis, this.rootCoordinatesZ, this.offsetZ); ++ return this.calculateFaceDirect(side, axis, this.rootCoordinatesZ, this.offsetZ); + } + default: { + throw new IllegalStateException("Unknown axis: " + axis); @@ -36157,12 +35640,12 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 } protected boolean isCubeLike() { -@@ -249,9 +871,30 @@ public abstract class VoxelShape { - && DoubleMath.fuzzyEquals(doubleList.getDouble(1), 1.0, 1.0E-7); +@@ -238,9 +864,30 @@ public abstract class VoxelShape { + return coords.size() == 2 && DoubleMath.fuzzyEquals(coords.getDouble(0), 0.0, 1.0E-7) && DoubleMath.fuzzyEquals(coords.getDouble(1), 1.0, 1.0E-7); } -- public double collide(Direction.Axis axis, AABB box, double maxDist) { -- return this.collideX(AxisCycle.between(axis, Direction.Axis.X), box, maxDist); +- public double collide(Direction.Axis movementAxis, AABB collisionBox, double desiredOffset) { +- return this.collideX(AxisCycle.between(movementAxis, Direction.Axis.X), collisionBox, desiredOffset); + // Paper start - optimise collisions + public double collide(final Direction.Axis axis, final AABB source, final double source_move) { + if (this.isEmpty) { @@ -36188,10 +35671,10 @@ index bcb79462c8b3309ae8701cba4753b27a9d22eb2e..6182f1d37c7a63479f6c6e7c37a7edc9 } + // Paper end - optimise collisions - protected double collideX(AxisCycle axisCycle, AABB box, double maxDist) { + protected double collideX(AxisCycle movementAxis, AABB collisionBox, double desiredOffset) { if (this.isEmpty()) { diff --git a/net/minecraft/world/ticks/LevelChunkTicks.java b/net/minecraft/world/ticks/LevelChunkTicks.java -index 26620c06d26a2c0eb957fbadc6ac3d7a309bff46..3858c83c58e78435a6e29de84c33faa2f26d593d 100644 +index 5b6bd88a5bbbce6cce351938418eba4326e41002..faf45ac459f7c25309d6ef6dce371d484a0dae7b 100644 --- a/net/minecraft/world/ticks/LevelChunkTicks.java +++ b/net/minecraft/world/ticks/LevelChunkTicks.java @@ -17,7 +17,7 @@ import net.minecraft.core.BlockPos; @@ -36245,10 +35728,10 @@ index 26620c06d26a2c0eb957fbadc6ac3d7a309bff46..3858c83c58e78435a6e29de84c33faa2 return scheduledTick; @@ -58,7 +82,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon @Override - public void schedule(ScheduledTick<T> orderedTick) { - if (this.ticksPerPosition.add(orderedTick)) { -- this.scheduleUnchecked(orderedTick); -+ this.scheduleUnchecked(orderedTick); this.dirty = true; // Paper - rewrite chunk system + public void schedule(ScheduledTick<T> tick) { + if (this.ticksPerPosition.add(tick)) { +- this.scheduleUnchecked(tick); ++ this.scheduleUnchecked(tick); this.dirty = true; // Paper - rewrite chunk system } } @@ -36264,327 +35747,16 @@ index 26620c06d26a2c0eb957fbadc6ac3d7a309bff46..3858c83c58e78435a6e29de84c33faa2 @@ -110,6 +134,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon } - public ListTag save(long time, Function<T, String> typeToNameFunction) { -+ this.lastSaved = time; // Paper - rewrite chunk system + public ListTag save(long gametime, Function<T, String> idGetter) { ++ this.lastSaved = gametime; // Paper - rewrite chunk system ListTag listTag = new ListTag(); - for (SavedTick<T> savedTick : this.pack(time)) { + for (SavedTick<T> savedTick : this.pack(gametime)) { @@ -121,6 +146,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon - public void unpack(long time) { + public void unpack(long gameTime) { if (this.pendingTicks != null) { -+ this.lastSaved = time; // Paper - rewrite chunk system ++ this.lastSaved = gameTime; // Paper - rewrite chunk system int i = -this.pendingTicks.size(); for (SavedTick<T> savedTick : this.pendingTicks) { -diff --git a/org/bukkit/craftbukkit/CraftChunk.java b/org/bukkit/craftbukkit/CraftChunk.java -index f3ab07e44e2e912ea66c6148cfdb2a4a528741b2..c2bffe3450ee9f768e00a23ec09df74d7a06d49b 100644 ---- a/org/bukkit/craftbukkit/CraftChunk.java -+++ b/org/bukkit/craftbukkit/CraftChunk.java -@@ -83,6 +83,12 @@ public class CraftChunk implements Chunk { - } - - public ChunkAccess getHandle(ChunkStatus chunkStatus) { -+ // Paper start - rewrite chunk system -+ net.minecraft.world.level.chunk.LevelChunk full = this.worldServer.getChunkIfLoaded(this.x, this.z); -+ if (full != null) { -+ return full; -+ } -+ // Paper end - rewrite chunk system - ChunkAccess chunkAccess = this.worldServer.getChunk(this.x, this.z, chunkStatus); - - // SPIGOT-7332: Get unwrapped extension -@@ -117,60 +123,12 @@ public class CraftChunk implements Chunk { - - @Override - public boolean isEntitiesLoaded() { -- return this.getCraftWorld().getHandle().entityManager.areEntitiesLoaded(ChunkPos.asLong(this.x, this.z)); -+ return this.getCraftWorld().getHandle().areEntitiesLoaded(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(this.x, this.z)); // Paper - rewrite chunk system - } - - @Override - public Entity[] getEntities() { -- if (!this.isLoaded()) { -- this.getWorld().getChunkAt(this.x, this.z); // Transient load for this tick -- } -- -- PersistentEntitySectionManager<net.minecraft.world.entity.Entity> entityManager = this.getCraftWorld().getHandle().entityManager; -- long pair = ChunkPos.asLong(this.x, this.z); -- -- if (entityManager.areEntitiesLoaded(pair)) { -- return entityManager.getEntities(new ChunkPos(this.x, this.z)).stream() -- .map(net.minecraft.world.entity.Entity::getBukkitEntity) -- .filter(Objects::nonNull).toArray(Entity[]::new); -- } -- -- entityManager.ensureChunkQueuedForLoad(pair); // Start entity loading -- -- // SPIGOT-6772: Use entity mailbox and re-schedule entities if they get unloaded -- ConsecutiveExecutor mailbox = ((EntityStorage) entityManager.permanentStorage).entityDeserializerQueue; -- BooleanSupplier supplier = () -> { -- // only execute inbox if our entities are not present -- if (entityManager.areEntitiesLoaded(pair)) { -- return true; -- } -- -- if (!entityManager.isPending(pair)) { -- // Our entities got unloaded, this should normally not happen. -- entityManager.ensureChunkQueuedForLoad(pair); // Re-start entity loading -- } -- -- // tick loading inbox, which loads the created entities to the world -- // (if present) -- entityManager.tick(); -- // check if our entities are loaded -- return entityManager.areEntitiesLoaded(pair); -- }; -- -- // now we wait until the entities are loaded, -- // the converting from NBT to entity object is done on the main Thread which is why we wait -- while (!supplier.getAsBoolean()) { -- if (mailbox.size() != 0) { -- mailbox.run(); -- } else { -- Thread.yield(); -- LockSupport.parkNanos("waiting for entity loading", 100000L); -- } -- } -- -- return entityManager.getEntities(new ChunkPos(this.x, this.z)).stream() -- .map(net.minecraft.world.entity.Entity::getBukkitEntity) -- .filter(Objects::nonNull).toArray(Entity[]::new); -+ return this.getCraftWorld().getHandle().getChunkEntities(this.x, this.z); // Paper - rewrite chunk system - } - - @Override -diff --git a/org/bukkit/craftbukkit/CraftServer.java b/org/bukkit/craftbukkit/CraftServer.java -index 5b64111bc8baca45ecc7bfa384e5f8a004163a0b..97b5d6ba2b19a7c730730c74175a29157aed1840 100644 ---- a/org/bukkit/craftbukkit/CraftServer.java -+++ b/org/bukkit/craftbukkit/CraftServer.java -@@ -1448,7 +1448,7 @@ public final class CraftServer implements Server { - // Paper - Put world into worldlist before initing the world; move up - - this.getServer().prepareLevels(internal.getChunkSource().chunkMap.progressListener, internal); -- internal.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API -+ // Paper - rewrite chunk system - - this.pluginManager.callEvent(new WorldLoadEvent(internal.getWorld())); - return internal.getWorld(); -@@ -1493,7 +1493,7 @@ public final class CraftServer implements Server { - } - - handle.getChunkSource().close(save); -- handle.entityManager.close(save); // SPIGOT-6722: close entityManager -+ // Paper - rewrite chunk system - handle.convertable.close(); - } catch (Exception ex) { - this.getLogger().log(Level.SEVERE, null, ex); -@@ -2531,7 +2531,7 @@ public final class CraftServer implements Server { - - @Override - public boolean isPrimaryThread() { -- return Thread.currentThread().equals(this.console.serverThread) || this.console.hasStopped() || !org.spigotmc.AsyncCatcher.enabled; // All bets are off if we have shut down (e.g. due to watchdog) -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThread(); // Paper - rewrite chunk system - } - - // Paper start - Adventure -diff --git a/org/bukkit/craftbukkit/CraftWorld.java b/org/bukkit/craftbukkit/CraftWorld.java -index ca62105a0ff0aa69385cbf2018f8fe6a4bb69fd4..92d9f0ea8f7810ae20d3996f49aefa539b4bcb69 100644 ---- a/org/bukkit/craftbukkit/CraftWorld.java -+++ b/org/bukkit/craftbukkit/CraftWorld.java -@@ -507,15 +507,17 @@ public class CraftWorld extends CraftRegionAccessor implements World { - ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); - if (playerChunk == null) return false; - -- playerChunk.getTickingChunkFuture().thenAccept(either -> { -- either.ifSuccess(chunk -> { -+ // Paper start - chunk system -+ net.minecraft.world.level.chunk.LevelChunk chunk = playerChunk.getChunkToSend(); -+ if (chunk == null) { -+ return false; -+ } -+ // Paper end - chunk system - List<ServerPlayer> playersInRange = playerChunk.playerProvider.getPlayers(playerChunk.getPos(), false); -- if (playersInRange.isEmpty()) return; -+ if (playersInRange.isEmpty()) return true; // Paper - chunk system - - FeatureHooks.sendChunkRefreshPackets(playersInRange, chunk); -- }); -- }); -- -+ // Paper - chunk system - return true; - } - -@@ -618,20 +620,8 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - public Collection<Plugin> getPluginChunkTickets(int x, int z) { - DistanceManager chunkDistanceManager = this.world.getChunkSource().chunkMap.distanceManager; -- SortedArraySet<Ticket<?>> tickets = chunkDistanceManager.tickets.get(ChunkPos.asLong(x, z)); -- -- if (tickets == null) { -- return Collections.emptyList(); -- } - -- ImmutableList.Builder<Plugin> ret = ImmutableList.builder(); -- for (Ticket<?> ticket : tickets) { -- if (ticket.getType() == TicketType.PLUGIN_TICKET) { -- ret.add((Plugin) ticket.key); -- } -- } -- -- return ret.build(); -+ return chunkDistanceManager.moonrise$getChunkHolderManager().getPluginChunkTickets(x, z); // Paper - rewrite chunk system - } - - @Override -@@ -639,7 +629,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - Map<Plugin, ImmutableList.Builder<Chunk>> ret = new HashMap<>(); - DistanceManager chunkDistanceManager = this.world.getChunkSource().chunkMap.distanceManager; - -- for (Long2ObjectMap.Entry<SortedArraySet<Ticket<?>>> chunkTickets : chunkDistanceManager.tickets.long2ObjectEntrySet()) { -+ for (Long2ObjectMap.Entry<SortedArraySet<Ticket<?>>> chunkTickets : chunkDistanceManager.moonrise$getChunkHolderManager().getTicketsCopy().long2ObjectEntrySet()) { // Paper - rewrite chunk system - long chunkKey = chunkTickets.getLongKey(); - SortedArraySet<Ticket<?>> tickets = chunkTickets.getValue(); - -@@ -1342,12 +1332,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public int getViewDistance() { -- return this.world.getChunkSource().chunkMap.serverViewDistance; -+ return this.getHandle().moonrise$getPlayerChunkLoader().getAPIViewDistance(); // Paper - rewrite chunk system - } - - @Override - public int getSimulationDistance() { -- return this.world.getChunkSource().chunkMap.getDistanceManager().simulationDistance; -+ return this.getHandle().moonrise$getPlayerChunkLoader().getAPITickDistance(); // Paper - rewrite chunk system - } - - public BlockMetadataStore getBlockMetadata() { -@@ -2486,17 +2476,20 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setSimulationDistance(final int simulationDistance) { -- throw new UnsupportedOperationException("Not implemented yet"); -+ if (simulationDistance < 2 || simulationDistance > 32) { -+ throw new IllegalArgumentException("Simulation distance " + simulationDistance + " is out of range of [2, 32]"); -+ } -+ this.getHandle().chunkSource.setSimulationDistance(simulationDistance); // Paper - rewrite chunk system - } - - @Override - public int getSendViewDistance() { -- return this.getViewDistance(); -+ return this.getHandle().moonrise$getPlayerChunkLoader().getAPISendViewDistance(); // Paper - rewrite chunk system - } - - @Override - public void setSendViewDistance(final int viewDistance) { -- throw new UnsupportedOperationException("Not implemented yet"); -+ this.getHandle().chunkSource.setSendViewDistance(viewDistance); // Paper - rewrite chunk system - } - - // Paper start - implement pointers -diff --git a/org/bukkit/craftbukkit/entity/CraftPlayer.java b/org/bukkit/craftbukkit/entity/CraftPlayer.java -index e9df37ff66700278bc94ea1e42135b92d97d03f7..6a647cab8b2e476987931486e290703b8726f2c7 100644 ---- a/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3527,7 +3527,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public void setViewDistance(final int viewDistance) { -- throw new UnsupportedOperationException("Not implemented yet"); -+ // Paper - rewrite chunk system - TODO do this better -+ ((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer)this.getHandle()) -+ .moonrise$getViewDistanceHolder().setLoadViewDistance(viewDistance + 1); - } - - @Override -@@ -3537,7 +3539,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public void setSimulationDistance(final int simulationDistance) { -- throw new UnsupportedOperationException("Not implemented yet"); -+ // Paper - rewrite chunk system - TODO do this better -+ ((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer)this.getHandle()) -+ .moonrise$getViewDistanceHolder().setTickViewDistance(simulationDistance); - } - - @Override -@@ -3547,7 +3551,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public void setSendViewDistance(final int viewDistance) { -- throw new UnsupportedOperationException("Not implemented yet"); -+ // Paper - rewrite chunk system - TODO do this better -+ ((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer)this.getHandle()) -+ .moonrise$getViewDistanceHolder().setSendViewDistance(viewDistance); - } - - // Paper start - entity effect API -diff --git a/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java -index 39377ba0739f9660567b38475f101672f7b5e035..c025a4ff42257a4e84f0f9574b84f6987ef8ac11 100644 ---- a/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java -+++ b/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java -@@ -264,7 +264,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator { - return ichunkaccess1; - }; - -- return future == null ? CompletableFuture.supplyAsync(() -> function.apply(chunk), net.minecraft.Util.backgroundExecutor()) : future.thenApply(function); -+ return future == null ? CompletableFuture.supplyAsync(() -> function.apply(chunk), Runnable::run) : future.thenApply(function); // Paper - rewrite chunk system - } - - @Override -diff --git a/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -index 54c4434662d057a08800918641b95708cda61207..37458e8fd5d57acbf90a6bea4e66797cb07f69fa 100644 ---- a/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -+++ b/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -@@ -810,6 +810,13 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { - public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { - return this.handle.getChunkIfLoadedImmediately(x, z); - } -+ -+ // Paper start - rewrite chunk system -+ @Override -+ public java.util.List<net.minecraft.world.entity.Entity> moonrise$getHardCollidingEntities(final net.minecraft.world.entity.Entity entity, final net.minecraft.world.phys.AABB box, final java.util.function.Predicate<? super net.minecraft.world.entity.Entity> predicate) { -+ return this.handle.moonrise$getHardCollidingEntities(entity, box, predicate); -+ } -+ // Paper end - rewrite chunk system - // Paper end - } - -diff --git a/org/spigotmc/AsyncCatcher.java b/org/spigotmc/AsyncCatcher.java -index ef2598760458833021ef1bee92137f42c9fe591f..1f23e775eba1c34e01145bd91b0ce26fed6ca9de 100644 ---- a/org/spigotmc/AsyncCatcher.java -+++ b/org/spigotmc/AsyncCatcher.java -@@ -9,7 +9,7 @@ public class AsyncCatcher - - public static void catchOp(String reason) - { -- if ( AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread ) -+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) // Paper // Paper - rewrite chunk system - { - MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); // Paper - throw new IllegalStateException( "Asynchronous " + reason + "!" ); -diff --git a/org/spigotmc/WatchdogThread.java b/org/spigotmc/WatchdogThread.java -index ad282d34919716b75acd10426cd071da9d064a51..529df2a41dd93d6e1505053bd04032dbf0cdaa31 100644 ---- a/org/spigotmc/WatchdogThread.java -+++ b/org/spigotmc/WatchdogThread.java -@@ -8,7 +8,7 @@ import java.util.logging.Logger; - import net.minecraft.server.MinecraftServer; - import org.bukkit.Bukkit; - --public class WatchdogThread extends Thread -+public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThread // Paper - rewrite chunk system - { - - private static WatchdogThread instance; -@@ -115,6 +115,7 @@ public class WatchdogThread extends Thread - // Paper end - Different message for short timeout - log.log( Level.SEVERE, "------------------------------" ); - log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper -+ ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - rewrite chunk system - WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log ); - log.log( Level.SEVERE, "------------------------------" ); - // |