Port random ticking optimisation from Moonrise

This commit is contained in:
Spottedleaf 2024-07-15 11:11:04 -07:00
parent e08de25a2a
commit 479ca6ef4d
2 changed files with 361 additions and 56 deletions

View file

@ -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<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> 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<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator) { // Paper - create paper world config
+ protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> 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<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> 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;
}

View file

@ -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<IntArrayList> 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<net.minecraft.world.level.block.state.BlockState> 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<net.minecraft.world.level.block.state.BlockState> 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<it.unimi.dsi.fastutil.ints.IntArrayList> moonrise$countEntries() {
+ final it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<it.unimi.dsi.fastutil.ints.IntArrayList> 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<it.unimi.dsi.fastutil.ints.IntArrayList> 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<it.unimi.dsi.fastutil.ints.IntArrayList> 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<T> 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<it.unimi.dsi.fastutil.ints.IntArrayList> 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<it.unimi.dsi.fastutil.ints.IntArrayList> 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<Biome> 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<Biome> 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<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> 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<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> 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<Entity> getEntities(@Nullable Entity except, AABB box, Predicate<? super Entity> predicate) {
this.getProfiler().incrementCounter("getEntities");
- List<Entity> list = Lists.newArrayList();
-
+ // Paper start - rewrite chunk system
+ final List<Entity> 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<Entity> 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<Holder<Biome>> 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<BlockState> datapaletteblock, PalettedContainer<Holder<Biome>> 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<BlockState> {
+ // 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<BlockState> 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<it.unimi.dsi.fastutil.ints.IntArrayList> 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<it.unimi.dsi.fastutil.ints.Int2IntMap.Entry> iterator = counts.int2IntEntrySet().fastIterator(); iterator.hasNext();) {
+ final it.unimi.dsi.fastutil.ints.Int2IntMap.Entry entry = iterator.next();
+ for (final java.util.Iterator<it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry<it.unimi.dsi.fastutil.ints.IntArrayList>> iterator = counts.int2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
+ final it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry<it.unimi.dsi.fastutil.ints.IntArrayList> 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<BlockState> 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) {