From 479ca6ef4d1c4c4948b73e81ff7e750c9dc4309a Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Mon, 15 Jul 2024 11:11:04 -0700 Subject: [PATCH] Port random ticking optimisation from Moonrise --- patches/server/Anti-Xray.patch | 6 +- .../Moonrise-optimisation-patches.patch | 411 +++++++++++++++--- 2 files changed, 361 insertions(+), 56 deletions(-) diff --git a/patches/server/Anti-Xray.patch b/patches/server/Anti-Xray.patch index ebd49e9b32..5d4e41c16f 100644 --- a/patches/server/Anti-Xray.patch +++ b/patches/server/Anti-Xray.patch @@ -1181,7 +1181,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private org.spigotmc.TickLimiter entityLimiter; @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } - // Paper end - optimise collisions + // Paper end - optimise random ticking - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator) { // Paper - create paper world config + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config & Anti-Xray @@ -1247,7 +1247,7 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.jav index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -0,0 +0,0 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.collis +@@ -0,0 +0,0 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ this.recalcBlockCounts(); } @@ -1263,7 +1263,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public BlockState getBlockState(int x, int y, int z) { -@@ -0,0 +0,0 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.collis +@@ -0,0 +0,0 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ this.biomes = datapaletteblock; } diff --git a/patches/server/Moonrise-optimisation-patches.patch b/patches/server/Moonrise-optimisation-patches.patch index 1137a6e777..d5a5d8b3dc 100644 --- a/patches/server/Moonrise-optimisation-patches.patch +++ b/patches/server/Moonrise-optimisation-patches.patch @@ -7,6 +7,7 @@ Currently includes: - Starlight + Chunk System - Entity tracker optimisations - Collision optimisations + - Random block ticking optimisations See https://github.com/Tuinity/Moonrise @@ -3363,6 +3364,39 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new RuntimeException(); + } +} +diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.moonrise.patches.block_counting; ++ ++import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; ++import it.unimi.dsi.fastutil.ints.IntArrayList; ++ ++public interface BlockCountingBitStorage { ++ ++ public Int2ObjectOpenHashMap moonrise$countEntries(); ++ ++} +diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java +@@ -0,0 +0,0 @@ ++package ca.spottedleaf.moonrise.patches.block_counting; ++ ++import ca.spottedleaf.moonrise.common.list.IBlockDataList; ++ ++public interface BlockCountingChunkSection { ++ ++ public int moonrise$getSpecialCollidingBlocks(); ++ ++ public IBlockDataList moonrise$getTickingBlockList(); ++ ++} diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_getblock/GetBlockChunk.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_getblock/GetBlockChunk.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -19946,7 +19980,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + continue; + } + -+ final boolean hasSpecial = ((ca.spottedleaf.moonrise.patches.collisions.world.CollisionLevelChunkSection)section).moonrise$getSpecialCollidingBlocks() != 0; ++ final boolean hasSpecial = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection)section).moonrise$getSpecialCollidingBlocks() != 0; + final int sectionAdjust = !hasSpecial ? 1 : 0; + + final net.minecraft.world.level.chunk.PalettedContainer blocks = section.states; @@ -20599,19 +20633,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public int moonrise$getMaxSection(); + +} -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/world/CollisionLevelChunkSection.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/world/CollisionLevelChunkSection.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/world/CollisionLevelChunkSection.java -@@ -0,0 +0,0 @@ -+package ca.spottedleaf.moonrise.patches.collisions.world; -+ -+public interface CollisionLevelChunkSection { -+ -+ public int moonrise$getSpecialCollidingBlocks(); -+ -+} diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/entity_tracker/EntityTrackerEntity.java b/src/main/java/ca/spottedleaf/moonrise/patches/entity_tracker/EntityTrackerEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -28699,7 +28720,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } else { - return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks - } -+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getFullChunkIfLoaded(chunkX, chunkZ); // Paper - rewrite chunk system ++ return this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); // Paper - rewrite chunk system } private void clearCache() { @@ -28986,16 +29007,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Override + public final LevelChunk moonrise$getFullChunkIfLoaded(final int chunkX, final int chunkZ) { -+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ if (newChunkHolder == null || !newChunkHolder.isFullChunkReady()) { -+ return null; -+ } -+ -+ if (newChunkHolder.getCurrentChunk() instanceof LevelChunk levelChunk) { -+ return levelChunk; -+ } -+ // race condition: chunk unloaded, only happens off-main -+ return null; ++ return this.chunkSource.getChunkNow(chunkX, chunkZ); + } + + @Override @@ -29220,6 +29232,107 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } protected void tickTime() { +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { + }); + } + ++ // Paper start - optimise random ticking ++ private void optimiseRandomTick(final LevelChunk chunk, final int tickSpeed) { ++ final LevelChunkSection[] sections = chunk.getSections(); ++ final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection((ServerLevel)(Object)this); ++ final RandomSource random = this.random; ++ final boolean tickFluids = false; // Paper - not configurable - MC-224294 ++ ++ final ChunkPos cpos = chunk.getPos(); ++ final int offsetX = cpos.x << 4; ++ final int offsetZ = cpos.z << 4; ++ ++ for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { ++ final int offsetY = (sectionIndex + minSection) << 4; ++ final LevelChunkSection section = sections[sectionIndex]; ++ final net.minecraft.world.level.chunk.PalettedContainer states = section.states; ++ if (section == null || !section.isRandomlyTickingBlocks()) { ++ continue; ++ } ++ ++ final ca.spottedleaf.moonrise.common.list.IBlockDataList tickList = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection)section).moonrise$getTickingBlockList(); ++ if (tickList.size() == 0) { ++ continue; ++ } ++ ++ for (int i = 0; i < tickSpeed; ++i) { ++ final int tickingBlocks = tickList.size(); ++ final int index = random.nextInt() & ((16 * 16 * 16) - 1); ++ ++ if (index >= tickingBlocks) { ++ // most of the time we fall here ++ continue; ++ } ++ ++ final long raw = tickList.getRaw(index); ++ final int location = ca.spottedleaf.moonrise.common.list.IBlockDataList.getLocationFromRaw(raw); ++ final int randomX = (location & 15); ++ final int randomY = ((location >>> (4 + 4)) & 255); ++ final int randomZ = ((location >>> 4) & 15); ++ final BlockState state = states.get(randomX | (randomZ << 4) | (randomY << 8)); ++ ++ // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! ++ final BlockPos pos = new BlockPos(randomX | offsetX, randomY | offsetY, randomZ | offsetZ); ++ ++ state.randomTick((ServerLevel)(Object)this, pos, random); ++ if (tickFluids) { ++ final FluidState fluidState = state.getFluidState(); ++ if (fluidState.isRandomlyTicking()) { ++ fluidState.randomTick((ServerLevel)(Object)this, pos, random); ++ } ++ } ++ } ++ } ++ ++ return; ++ } ++ // Paper end - optimise random ticking ++ + public void tickChunk(LevelChunk chunk, int randomTickSpeed) { + ChunkPos chunkcoordintpair = chunk.getPos(); + boolean flag = this.isRaining(); +@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { + gameprofilerfiller.popPush("tickBlocks"); + timings.chunkTicksBlocks.startTiming(); // Paper + 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); +- } +- +- FluidState fluid = iblockdata.getFluidState(); +- +- if (fluid.isRandomlyTicking()) { +- fluid.randomTick(this, blockposition1, this.random); +- } +- +- gameprofilerfiller.pop(); +- } +- } +- } ++ this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking + } + + timings.chunkTicksBlocks.stopTiming(); // Paper @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { if (fluid1.is(fluid)) { fluid1.tick(this, pos); @@ -29940,6 +30053,87 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 handler.send(new ClientboundLevelChunkWithLightPacket(chunk, world.getLightEngine(), null, null)); // Paper start - PlayerChunkLoadEvent if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { +diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/util/BitStorage.java ++++ b/src/main/java/net/minecraft/util/BitStorage.java +@@ -0,0 +0,0 @@ package net.minecraft.util; + + import java.util.function.IntConsumer; + +-public interface BitStorage { ++public interface BitStorage extends ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage { // Paper - block counting + int getAndSet(int index, int value); + + void set(int index, int value); +@@ -0,0 +0,0 @@ public interface BitStorage { + void unpack(int[] out); + + BitStorage copy(); ++ ++ // Paper start - block counting ++ // provide default impl in case mods implement this... ++ @Override ++ public default it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap moonrise$countEntries() { ++ final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(); ++ ++ final int size = this.getSize(); ++ for (int index = 0; index < size; ++index) { ++ final int paletteIdx = this.get(index); ++ ret.computeIfAbsent(paletteIdx, (final int key) -> { ++ return new it.unimi.dsi.fastutil.ints.IntArrayList(); ++ }).add(index); ++ } ++ ++ return ret; ++ } ++ // Paper end - block counting + } +diff --git a/src/main/java/net/minecraft/util/SimpleBitStorage.java b/src/main/java/net/minecraft/util/SimpleBitStorage.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/util/SimpleBitStorage.java ++++ b/src/main/java/net/minecraft/util/SimpleBitStorage.java +@@ -0,0 +0,0 @@ public class SimpleBitStorage implements BitStorage { + return new SimpleBitStorage(this.bits, this.size, (long[])this.data.clone()); + } + ++ // Paper start - block counting ++ @Override ++ public final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap moonrise$countEntries() { ++ final int valuesPerLong = this.valuesPerLong; ++ final int bits = this.bits; ++ final long mask = this.mask; ++ final int size = this.size; ++ ++ // we may be backed by global palette, so limit bits for init capacity ++ final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>( ++ 1 << Math.min(6, bits) ++ ); ++ ++ int index = 0; ++ ++ for (long value : this.data) { ++ int li = 0; ++ do { ++ final int paletteIdx = (int)(value & mask); ++ value >>= bits; ++ ++ ret.computeIfAbsent(paletteIdx, (final int key) -> { ++ return new it.unimi.dsi.fastutil.ints.IntArrayList(); ++ }).add(index); ++ ++ ++li; ++ ++index; ++ } while (li < valuesPerLong && index < size); ++ } ++ ++ return ret; ++ } ++ // Paper end - block counting ++ + public static class InitializationException extends RuntimeException { + InitializationException(String message) { + super(message); diff --git a/src/main/java/net/minecraft/util/SortedArraySet.java b/src/main/java/net/minecraft/util/SortedArraySet.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/util/SortedArraySet.java @@ -30035,6 +30229,33 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private SortedArraySet(int initialCapacity, Comparator comparator) { this.comparator = comparator; if (initialCapacity < 0) { +diff --git a/src/main/java/net/minecraft/util/ZeroBitStorage.java b/src/main/java/net/minecraft/util/ZeroBitStorage.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/util/ZeroBitStorage.java ++++ b/src/main/java/net/minecraft/util/ZeroBitStorage.java +@@ -0,0 +0,0 @@ public class ZeroBitStorage implements BitStorage { + public BitStorage copy() { + return this; + } ++ ++ // Paper start - block counting ++ @Override ++ public final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap moonrise$countEntries() { ++ final int size = this.size; ++ ++ final int[] raw = new int[size]; ++ for (int i = 0; i < size; ++i) { ++ raw[i] = i; ++ } ++ ++ final it.unimi.dsi.fastutil.ints.IntArrayList coordinates = it.unimi.dsi.fastutil.ints.IntArrayList.wrap(raw, size); ++ ++ final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(1); ++ ret.put(0, coordinates); ++ return ret; ++ } ++ // Paper end - block counting + } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java @@ -31387,6 +31608,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void moonrise$midTickTasks() { + // no-op on ClientLevel + } ++ /** ++ * @reason Turn all getChunk(x, z, status) calls into virtual invokes, instead of interface invokes: ++ * 1. The interface invoke is expensive ++ * 2. The method makes other interface invokes (again, expensive) ++ * Instead, we just directly call getChunk(x, z, status, true) which avoids the interface invokes entirely. ++ * @author Spottedleaf ++ */ ++ @Override ++ public ChunkAccess getChunk(final int x, final int z, final ChunkStatus status) { ++ return ((Level)(Object)this).getChunk(x, z, status, true); ++ } ++ ++ @Override ++ public BlockPos getHeightmapPos(Heightmap.Types types, BlockPos blockPos) { ++ return new BlockPos(blockPos.getX(), this.getHeight(types, blockPos.getX(), blockPos.getZ()), blockPos.getZ()); ++ } + // Paper end - rewrite chunk system + // Paper start - optimise collisions + private final int minSection; @@ -31776,6 +32013,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return java.util.Optional.ofNullable(selected); + } + // Paper end - optimise collisions ++ // Paper start - optimise random ticking ++ @Override ++ public abstract Holder getUncachedNoiseBiome(final int x, final int y, final int z); ++ ++ /** ++ * @reason Make getChunk and getUncachedNoiseBiome virtual calls instead of interface calls ++ * by implementing the superclass method in this class. ++ * @author Spottedleaf ++ */ ++ @Override ++ public Holder getNoiseBiome(final int x, final int y, final int z) { ++ final ChunkAccess chunk = this.getChunk(x >> 2, z >> 2, ChunkStatus.BIOMES, false); ++ ++ return chunk != null ? chunk.getNoiseBiome(x, y, z) : this.getUncachedNoiseBiome(x, y, z); ++ } ++ // Paper end - optimise random ticking + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator) { // Paper - create paper world config this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot @@ -31858,19 +32111,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public List getEntities(@Nullable Entity except, AABB box, Predicate predicate) { this.getProfiler().incrementCounter("getEntities"); - List list = Lists.newArrayList(); -- ++ // Paper start - rewrite chunk system ++ final List ret = new java.util.ArrayList<>(); + - this.getEntities().get(box, (entity1) -> { - if (entity1 != except && predicate.test(entity1)) { - list.add(entity1); - } -+ // Paper start - rewrite chunk system -+ final List ret = new java.util.ArrayList<>(); ++ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(except, box, ret, predicate); - if (entity1 instanceof EnderDragon) { - EnderDragonPart[] aentitycomplexpart = ((EnderDragon) entity1).getSubEntities(); - int i = aentitycomplexpart.length; -+ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(except, box, ret, predicate); - +- - for (int j = 0; j < i; ++j) { - EnderDragonPart entitycomplexpart = aentitycomplexpart[j]; - @@ -32010,6 +32263,32 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create); +diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/biome/Biome.java ++++ b/src/main/java/net/minecraft/world/level/biome/Biome.java +@@ -0,0 +0,0 @@ public final class Biome { + + @Deprecated + public float getTemperature(BlockPos blockPos) { +- long l = blockPos.asLong(); +- Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = this.temperatureCache.get(); +- float f = long2FloatLinkedOpenHashMap.get(l); +- if (!Float.isNaN(f)) { +- return f; +- } else { +- float g = this.getHeightAdjustedTemperature(blockPos); +- if (long2FloatLinkedOpenHashMap.size() == 1024) { +- long2FloatLinkedOpenHashMap.removeFirstFloat(); +- } +- +- long2FloatLinkedOpenHashMap.put(l, g); +- return g; +- } ++ return this.getHeightAdjustedTemperature(blockPos); // Paper - optimise random ticking + } + + public boolean shouldFreeze(LevelReader world, BlockPos blockPos) { diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java @@ -32627,7 +32906,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.world.level.material.FluidState; -public class LevelChunkSection { -+public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.collisions.world.CollisionLevelChunkSection { // Paper - optimise collisions ++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; @@ -32635,14 +32914,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start - read/write private PalettedContainer> biomes; -+ // Paper start - optimise collisions ++ // Paper start - block counting ++ private static final it.unimi.dsi.fastutil.ints.IntArrayList FULL_LIST = new it.unimi.dsi.fastutil.ints.IntArrayList(16*16*16); ++ static { ++ for (int i = 0; i < (16*16*16); ++i) { ++ FULL_LIST.add(i); ++ } ++ } ++ + private int specialCollidingBlocks; ++ private final ca.spottedleaf.moonrise.common.list.IBlockDataList tickingBlocks = new ca.spottedleaf.moonrise.common.list.IBlockDataList(); + + @Override + public final int moonrise$getSpecialCollidingBlocks() { + return this.specialCollidingBlocks; + } -+ // Paper end - optimise collisions ++ ++ @Override ++ public final ca.spottedleaf.moonrise.common.list.IBlockDataList moonrise$getTickingBlockList() { ++ return this.tickingBlocks; ++ } ++ // Paper end - block counting + public LevelChunkSection(PalettedContainer datapaletteblock, PalettedContainer> palettedcontainerro) { // CraftBukkit end @@ -32651,14 +32943,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 ++this.tickingFluidCount; } -+ // Paper start - optimise collisions -+ if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isSpecialCollidingBlock(state)) { -+ ++this.specialCollidingBlocks; -+ } ++ // Paper start - block counting + if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isSpecialCollidingBlock(iblockdata1)) { + --this.specialCollidingBlocks; + } -+ // Paper end - optimise collisions ++ if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isSpecialCollidingBlock(state)) { ++ ++this.specialCollidingBlocks; ++ } ++ ++ if (iblockdata1.isRandomlyTicking()) { ++ this.tickingBlocks.remove(x, y, z); ++ } ++ if (state.isRandomlyTicking()) { ++ this.tickingBlocks.add(x, y, z, state); ++ } ++ // Paper end - block counting + return iblockdata1; } @@ -32668,12 +32967,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void recalcBlockCounts() { - class a implements PalettedContainer.CountConsumer { -+ // Paper start - optimise collisions ++ // Paper start - block counting + // reset, then recalculate + this.nonEmptyBlockCount = (short)0; + this.tickingBlockCount = (short)0; + this.tickingFluidCount = (short)0; + this.specialCollidingBlocks = (short)0; ++ this.tickingBlocks.clear(); + + if (this.maybeHas((final BlockState state) -> !state.isAir())) { + final PalettedContainer.Data data = this.states.data; @@ -32681,22 +32981,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final int paletteSize = palette.getSize(); + final net.minecraft.util.BitStorage storage = data.storage(); + -+ final it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap counts = new it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap(paletteSize); ++ final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap counts; + if (paletteSize == 1) { -+ counts.addTo(0, storage.getSize()); ++ counts = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(1); ++ counts.put(0, FULL_LIST); + } else { -+ storage.getAll((final int paletteIdx) -> { -+ counts.addTo(paletteIdx, 1); -+ }); ++ counts = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage)storage).moonrise$countEntries(); + } - public int nonEmptyBlockCount; - public int tickingBlockCount; - public int tickingFluidCount; -+ for (final java.util.Iterator iterator = counts.int2IntEntrySet().fastIterator(); iterator.hasNext();) { -+ final it.unimi.dsi.fastutil.ints.Int2IntMap.Entry entry = iterator.next(); ++ for (final java.util.Iterator> iterator = counts.int2ObjectEntrySet().fastIterator(); iterator.hasNext();) { ++ final it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry entry = iterator.next(); + final int paletteIdx = entry.getIntKey(); -+ final int paletteCount = entry.getIntValue(); ++ final it.unimi.dsi.fastutil.ints.IntArrayList coordinates = entry.getValue(); ++ final int paletteCount = coordinates.size(); - a(final LevelChunkSection chunksection) {} + final BlockState state = palette.valueFor(paletteIdx); @@ -32711,17 +33011,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.nonEmptyBlockCount += i; - if (iblockdata.isRandomlyTicking()) { - this.tickingBlockCount += i; -- } + if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isSpecialCollidingBlock(state)) { + this.specialCollidingBlocks += paletteCount; - } ++ } + this.nonEmptyBlockCount += paletteCount; + if (state.isRandomlyTicking()) { + this.tickingBlockCount += paletteCount; -+ } ++ final int[] raw = coordinates.elements(); + -+ final FluidState fluid = state.getFluidState(); ++ java.util.Objects.checkFromToIndex(0, paletteCount, raw.length); ++ for (int i = 0; i < paletteCount; ++i) { ++ this.tickingBlocks.add(raw[i], state); + } + } ++ final FluidState fluid = state.getFluidState(); ++ if (!fluid.isEmpty()) { - this.nonEmptyBlockCount += i; + //this.nonEmptyBlockCount += count; // fix vanilla bug: make non empty block count correct @@ -32740,7 +33045,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.nonEmptyBlockCount = (short) a0.nonEmptyBlockCount; - this.tickingBlockCount = (short) a0.tickingBlockCount; - this.tickingFluidCount = (short) a0.tickingFluidCount; -+ // Paper end - optimise collisions ++ // Paper end - block counting } public PalettedContainer getStates() { @@ -32748,7 +33053,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 datapaletteblock.read(buf); this.biomes = datapaletteblock; -+ this.recalcBlockCounts(); // Paper - optimise collisions ++ this.recalcBlockCounts(); // Paper - block counting } public void readBiomes(FriendlyByteBuf buf) {