mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-19 15:09:25 +00:00
remove hash lookup in optimize random tick
This commit is contained in:
@@ -36,72 +36,22 @@ index 27da552e2542153a58d6177f592cf30d858c41a9..35fb0770eb385e3837cb29711905c41b
|
||||
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting
|
||||
ChunkPos pos = chunk.getPos();
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index a3674ddb883eecb255279375a5e2eece7e016c0f..9249041fb249539b8dffbc0d4d338dc79941650f 100644
|
||||
index a3674ddb883eecb255279375a5e2eece7e016c0f..963a882af639f1f69698bafad1d70eda6d22b846 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -152,6 +152,61 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
@@ -152,6 +152,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
}
|
||||
// Gale end - Airplane - optimize random calls in chunk ticking - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively
|
||||
|
||||
+ // Leaf start - optimize random tick
|
||||
+ private boolean leaf$tickingBlocksDirty = true;
|
||||
+ private int leaf$tickingBlocksCount = 0;
|
||||
+ private int leaf$firstTickingSectionIndex = -1;
|
||||
+ private int leaf$mostTickingSectionIndex = -1;
|
||||
+ public final int leaf$tickingBlocksCount() {
|
||||
+ if (!leaf$tickingBlocksDirty) {
|
||||
+ return leaf$tickingBlocksCount;
|
||||
+ }
|
||||
+ leaf$tickingBlocksDirty = false;
|
||||
+ int sum = 0;
|
||||
+ leaf$firstTickingSectionIndex = -1;
|
||||
+ leaf$mostTickingSectionIndex = -1;
|
||||
+ int most = 0;
|
||||
+ for (int i = 0; i < sections.length; i++) {
|
||||
+ ca.spottedleaf.moonrise.common.list.ShortList list = sections[i].moonrise$getTickingBlockList();
|
||||
+ int size = list.size();
|
||||
+ if (size != 0 && leaf$firstTickingSectionIndex == -1) {
|
||||
+ leaf$firstTickingSectionIndex = i;
|
||||
+ }
|
||||
+ if (size > most) {
|
||||
+ leaf$mostTickingSectionIndex = i;
|
||||
+ }
|
||||
+ sum += size;
|
||||
+ }
|
||||
+ leaf$tickingBlocksCount = sum;
|
||||
+ return sum;
|
||||
+ }
|
||||
+ public final java.util.OptionalLong leaf$getTickingPos(int idx) {
|
||||
+ if (leaf$firstTickingSectionIndex != -1) {
|
||||
+ int most = leaf$mostTickingSectionIndex;
|
||||
+ var mostList = sections[most].moonrise$getTickingBlockList();
|
||||
+ int mostSectionSize = mostList.size();
|
||||
+ if (idx < mostSectionSize) {
|
||||
+ short loc = mostList.getRaw(idx);
|
||||
+ return java.util.OptionalLong.of(BlockPos.asLong((loc & 15) | (locX << 4), (loc >>> 8) | ((getMinSectionY() + most) << 4), ((loc >>> 4) & 15) | (locZ << 4)));
|
||||
+ }
|
||||
+ idx -= mostSectionSize;
|
||||
+ for (int i = leaf$firstTickingSectionIndex; i < sections.length; i++) {
|
||||
+ if (i == most) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ var list = sections[i].moonrise$getTickingBlockList();
|
||||
+ int size = list.size();
|
||||
+ if (idx < size) {
|
||||
+ short loc = list.getRaw(idx);
|
||||
+ return java.util.OptionalLong.of(BlockPos.asLong((loc & 15) | (locX << 4), (loc >>> 8) | ((getMinSectionY() + i) << 4), ((loc >>> 4) & 15) | (locZ << 4)));
|
||||
+ }
|
||||
+ idx -= size;
|
||||
+ }
|
||||
+ }
|
||||
+ leaf$tickingBlocksDirty = true;
|
||||
+ return java.util.OptionalLong.empty();
|
||||
+ }
|
||||
+ public boolean leaf$tickingBlocksDirty = true;
|
||||
+ public short[] leaf$tickingBlocksCount = {};
|
||||
+ public short[] leaf$tickingIdx = {};
|
||||
+ // Leaf end - optimize random tick
|
||||
public LevelChunk(Level level, ChunkPos pos) {
|
||||
this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null);
|
||||
}
|
||||
@@ -416,6 +471,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
@@ -416,6 +421,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
if (blockState == state) {
|
||||
return null;
|
||||
} else {
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
package org.dreeam.leaf.world;
|
||||
|
||||
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||
import ca.spottedleaf.moonrise.common.list.ShortList;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.levelgen.BitRandomSource;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
|
||||
import java.util.OptionalLong;
|
||||
|
||||
public final class RandomTickSystem {
|
||||
private static final long SCALE = 0x100000L;
|
||||
private static final long TICK_FILTER_MASK = 0b11L;
|
||||
@@ -21,13 +22,18 @@ public final class RandomTickSystem {
|
||||
private static final int BITS_STEP = 2;
|
||||
private static final int BITS_MAX = 60;
|
||||
|
||||
private final LongArrayList queue = new LongArrayList();
|
||||
private final LongArrayList samples = new LongArrayList();
|
||||
private final LongArrayList weights = new LongArrayList();
|
||||
private final IntArrayList queue = new IntArrayList();
|
||||
private final ShortArrayList yList = new ShortArrayList();
|
||||
private final IntArrayList xzList = new IntArrayList();
|
||||
private final LongArrayList weightList = new LongArrayList();
|
||||
|
||||
public void tick(ServerLevel world) {
|
||||
final BitRandomSource random = world.simpleRandom;
|
||||
queue.clear();
|
||||
yList.clear();
|
||||
xzList.clear();
|
||||
weightList.clear();
|
||||
|
||||
final BitRandomSource random = world.simpleRandom;
|
||||
final ReferenceList<LevelChunk> entityTickingChunks = world.moonrise$getEntityTickingChunks();
|
||||
final int randomTickSpeed = world.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
||||
final LevelChunk[] raw = entityTickingChunks.getRawDataUnchecked();
|
||||
@@ -39,33 +45,27 @@ public final class RandomTickSystem {
|
||||
if (!disableIceAndSnow) {
|
||||
iceSnow(world, size, randomTickSpeed, random, raw);
|
||||
}
|
||||
final long weightsSum = fillWeight(size, random, raw, randomTickSpeed);
|
||||
if (weights.isEmpty() || samples.isEmpty() || weightsSum == 0L) {
|
||||
final long weightsSum = collectTickingChunks(size, random, raw, randomTickSpeed);
|
||||
if (weightList.isEmpty() || yList.isEmpty() || weightsSum == 0L) {
|
||||
return;
|
||||
}
|
||||
sus(random, weightsSum);
|
||||
weights.clear();
|
||||
samples.clear();
|
||||
sampling(random, weightsSum);
|
||||
|
||||
final ConcurrentLong2ReferenceChainedHashTable<LevelChunk> fullChunks = world.chunkSource.fullChunks;
|
||||
final long[] q = queue.elements();
|
||||
final int l = queue.size();
|
||||
LevelChunk a = null;
|
||||
long b = 0L;
|
||||
for (int k = 0; k < l; k++) {
|
||||
final long pos = q[k];
|
||||
if (a == null || b != pos) {
|
||||
a = fullChunks.get(pos);
|
||||
b = pos;
|
||||
}
|
||||
final int[] q = queue.elements();
|
||||
final int qs = queue.size();
|
||||
final short[] yl = yList.elements();
|
||||
final int[] xzl = xzList.elements();
|
||||
final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(world);
|
||||
for (int k = 0; k < qs; k++) {
|
||||
final int index = q[k];
|
||||
final LevelChunk a = raw[xzl[index]];
|
||||
if (a != null) {
|
||||
tickBlock(world, a, random);
|
||||
tickBlock(world, a, yl[index], random, minSection);
|
||||
}
|
||||
}
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
private void sus(BitRandomSource random, long weightsSum) {
|
||||
private void sampling(BitRandomSource random, long weightsSum) {
|
||||
final long chosen;
|
||||
if (((weightsSum % SCALE) >= boundedNextLong(random, SCALE))) {
|
||||
chosen = weightsSum / SCALE + 1L;
|
||||
@@ -76,9 +76,7 @@ public final class RandomTickSystem {
|
||||
return;
|
||||
}
|
||||
|
||||
final long[] weightsRaw = weights.elements();
|
||||
final long[] samplesRaw = samples.elements();
|
||||
|
||||
final long[] weightsRaw = weightList.elements();
|
||||
long accumulated = weightsRaw[0];
|
||||
final long spoke = weightsSum / chosen;
|
||||
if (spoke == 0L) return;
|
||||
@@ -89,12 +87,12 @@ public final class RandomTickSystem {
|
||||
i++;
|
||||
accumulated += weightsRaw[i];
|
||||
}
|
||||
queue.add(samplesRaw[i]);
|
||||
queue.add(i);
|
||||
current += spoke;
|
||||
}
|
||||
}
|
||||
|
||||
private long fillWeight(int size, BitRandomSource random, LevelChunk[] raw, long randomTickSpeed) {
|
||||
private long collectTickingChunks(int size, BitRandomSource random, LevelChunk[] raw, long randomTickSpeed) {
|
||||
int bits = 0;
|
||||
long cacheRandom = random.nextLong();
|
||||
long weightsSum = 0L;
|
||||
@@ -110,17 +108,46 @@ public final class RandomTickSystem {
|
||||
continue;
|
||||
}
|
||||
final LevelChunk chunk = raw[i];
|
||||
final long count = chunk.leaf$tickingBlocksCount();
|
||||
if (count != 0L) {
|
||||
long weight = (randomTickSpeed * count * SCALE) / CHUNK_BLOCKS;
|
||||
samples.add(chunk.locX & 4294967295L | (chunk.locZ & 4294967295L) << 32);
|
||||
weights.add(weight);
|
||||
if (chunk.leaf$tickingBlocksDirty) {
|
||||
populateChunkTickingCount(chunk);
|
||||
}
|
||||
short[] count = chunk.leaf$tickingBlocksCount;
|
||||
short[] idx = chunk.leaf$tickingIdx;
|
||||
for (int j = 0; j < count.length; j++) {
|
||||
long weight = (randomTickSpeed * ((long) count[j]) * SCALE) / CHUNK_BLOCKS;
|
||||
yList.add(idx[j]);
|
||||
xzList.add(i);
|
||||
weightList.add(weight);
|
||||
weightsSum += weight;
|
||||
}
|
||||
}
|
||||
return weightsSum;
|
||||
}
|
||||
|
||||
private static void populateChunkTickingCount(LevelChunk chunk) {
|
||||
chunk.leaf$tickingBlocksDirty = false;
|
||||
int sum = 0;
|
||||
for (LevelChunkSection section : chunk.getSections()) {
|
||||
sum += (section.moonrise$getTickingBlockList().size() == 0) ? 0 : 1;
|
||||
}
|
||||
if (chunk.leaf$tickingBlocksCount.length != sum) {
|
||||
chunk.leaf$tickingBlocksCount = new short[sum];
|
||||
chunk.leaf$tickingIdx = new short[sum];
|
||||
}
|
||||
short[] count = chunk.leaf$tickingBlocksCount;
|
||||
short[] idx = chunk.leaf$tickingIdx;
|
||||
int k = 0;
|
||||
for (int j = 0, sectionsLength = chunk.getSections().length; j < sectionsLength; j++) {
|
||||
LevelChunkSection section = chunk.getSections()[j];
|
||||
int n = (short) section.moonrise$getTickingBlockList().size();
|
||||
if (n != 0) {
|
||||
count[k] = (short) n;
|
||||
idx[k] = (short) j;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void iceSnow(ServerLevel world, int size, int randomTickSpeed, BitRandomSource random, LevelChunk[] raw) {
|
||||
int currentIceAndSnowTick = random.nextInt(48 * 16);
|
||||
for (int i = 0; i < size; i++) {
|
||||
@@ -136,17 +163,14 @@ public final class RandomTickSystem {
|
||||
}
|
||||
}
|
||||
|
||||
private static void tickBlock(ServerLevel world, LevelChunk chunk, BitRandomSource random) {
|
||||
int count = chunk.leaf$tickingBlocksCount();
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
OptionalLong optionalPos = chunk.leaf$getTickingPos(random.nextInt(count));
|
||||
if (optionalPos.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
BlockPos pos = BlockPos.of(optionalPos.getAsLong());
|
||||
BlockState state = chunk.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
|
||||
private static void tickBlock(ServerLevel world, LevelChunk chunk, int sectionIdx, BitRandomSource random, int minSection) {
|
||||
LevelChunkSection section = chunk.getSection(sectionIdx);
|
||||
ShortList list = section.moonrise$getTickingBlockList();
|
||||
int sz = list.size();
|
||||
if (sz == 0) return;
|
||||
short location = list.getRaw(boundedNextInt(random, sz));
|
||||
BlockState state = section.states.get(location);
|
||||
final BlockPos pos = new BlockPos((location & 15) | chunk.locX << 4, (location >>> (4 + 4)) | (sectionIdx + minSection) << 4, ((location >>> 4) & 15) | chunk.locZ << 4);
|
||||
state.randomTick(world, pos, random);
|
||||
|
||||
final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294();
|
||||
@@ -172,4 +196,19 @@ public final class RandomTickSystem {
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
private static int boundedNextInt(BitRandomSource rng, int bound) {
|
||||
final int m = bound - 1;
|
||||
int r = rng.nextInt();
|
||||
if ((bound & m) == 0) {
|
||||
r &= m;
|
||||
} else {
|
||||
//noinspection StatementWithEmptyBody
|
||||
for (int u = r >>> 1;
|
||||
u + m - (r = u % bound) < 0;
|
||||
u = rng.nextInt() >>> 1)
|
||||
;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user