9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-19 15:09:25 +00:00

fix random tick

This commit is contained in:
hayanesuru
2025-06-08 17:31:34 +09:00
parent 47c1783afc
commit aad17b0a5b
2 changed files with 28 additions and 207 deletions

View File

@@ -17,7 +17,7 @@ index 2f927b422c2c4f2f65d822befe3cbfd9e3bb3708..d0fcfeaf093b718c8acd6e057176d569
if (flagAndHasNaturalSpawn) { // Gale - MultiPaper - skip unnecessary mob spawning computations
this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index eb849c57992658005e0f514c6f7923f8ca43bebf..2efcdb9bc91b9106b4aef9e24cc20596be4a5661 100644
index eb849c57992658005e0f514c6f7923f8ca43bebf..0bf765334f20fa5a999400076797d5b1f82c7469 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1128,6 +1128,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -33,13 +33,13 @@ index eb849c57992658005e0f514c6f7923f8ca43bebf..2efcdb9bc91b9106b4aef9e24cc20596
if (randomTickSpeed > 0) {
- this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking
+ if (org.dreeam.leaf.config.modules.opt.OptimizeRandomTick.enabled) randomTickSystem.randomTickChunk(chunk, randomTickSpeed); // Leaf - random tick
+ if (org.dreeam.leaf.config.modules.opt.OptimizeRandomTick.enabled) randomTickSystem.randomTickChunk(this.simpleRandom, chunk, randomTickSpeed); // Leaf - random tick
+ else this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking // Leaf - random tick
}
}
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 624a177695580510c0a49d4503dee72da7fd7114..affe9fff1ff2f7e221f8cfe345d40d707e0f3dbc 100644
index 624a177695580510c0a49d4503dee72da7fd7114..f85d46c23824de177fe0c08b2ce6fbbb81c3535b 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -151,6 +151,52 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
@@ -48,8 +48,8 @@ index 624a177695580510c0a49d4503dee72da7fd7114..affe9fff1ff2f7e221f8cfe345d40d70
+ // Leaf start - random tick
+ private long leaf$randomTickChance;
+ private long leaf$countTickingBlocks;
+ private long leaf$countTickingSections;
+ private int leaf$countTickingBlocks;
+ private int leaf$countTickingSections;
+
+ public final long leaf$randomTickChance() {
+ return leaf$randomTickChance;
@@ -57,15 +57,15 @@ index 624a177695580510c0a49d4503dee72da7fd7114..affe9fff1ff2f7e221f8cfe345d40d70
+ public final void leaf$setRandomTickChance(long chance) {
+ leaf$randomTickChance = chance;
+ }
+ public final long leaf$countTickingBlocks() {
+ public final int leaf$countTickingBlocks() {
+ return leaf$countTickingBlocks;
+ }
+ public final long leaf$countTickingSections() {
+ public final int leaf$countTickingSections() {
+ return leaf$countTickingSections;
+ }
+ public final void leaf$recompute() {
+ long total1 = 0L;
+ long total2 = 0L;
+ int total1 = 0;
+ int total2 = 0;
+ for (LevelChunkSection section : sections) {
+ total1 += section.moonrise$getTickingBlockList().size();
+ if (section.isRandomlyTickingBlocks()) {

View File

@@ -16,15 +16,10 @@ import java.util.OptionalLong;
public final class RandomTickSystem {
private final LongArrayList tickPos = new LongArrayList();
private final WyRand rand = new WyRand(RandomSupport.generateUniqueSeed());
private static final long SCALE = 0x100000L;
private static final long MASK = 0xfffffL;
private static final long MASK_ONE_FOURTH = 0x300000L;
private static final long CHUNK_BLOCKS = 4096L;
private static final long CHUNK_BLOCKS_HALF = 2048L;
private long cache = rand.next();
private int cacheIdx = 0;
private static final int MASK = 0xfffff;
private static final int MASK_ONE_FOURTH = 0x300000;
public void tick(ServerLevel world) {
var simpleRandom = world.simpleRandom;
@@ -43,9 +38,6 @@ public final class RandomTickSystem {
return;
}
BlockState state = chunk.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
if (state == null) {
return;
}
state.randomTick(world, pos, tickRand);
if (doubleTickFluids) {
final FluidState fluidState = state.getFluidState();
@@ -63,216 +55,45 @@ public final class RandomTickSystem {
chunk.leaf$setRandomTickChance(0L);
return 0L;
}
long product = tickSpeed * tickingCount;
long chance = ((product + CHUNK_BLOCKS_HALF) * SCALE) / CHUNK_BLOCKS;
long chance = (tickSpeed * tickingCount * SCALE) / CHUNK_BLOCKS;
chunk.leaf$setRandomTickChance(chance);
return chance;
}
/*
public void randomTickChunkOrigin(
ServerLevel level,
LevelChunk chunk,
long tickSpeed
) {
final LevelChunkSection[] sections = chunk.getSections();
final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(level); // Leaf - Micro optimizations for random tick - no redundant cast
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = level.simpleRandom; // Leaf - Faster random generator - upcasting
final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294();
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++) {
// Leaf start - Micro optimizations for random tick
final LevelChunkSection section = sections[sectionIndex];
if (!section.isRandomlyTickingBlocks()) {
continue;
}
final int offsetY = (sectionIndex + minSection) << 4;
final net.minecraft.world.level.chunk.PalettedContainer<net.minecraft.world.level.block.state.BlockState> states = section.states;
// Leaf end - Micro optimizations for random tick
final ca.spottedleaf.moonrise.common.list.ShortList tickList = section.moonrise$getTickingBlockList(); // Leaf - Micro optimizations for random tick - no redundant cast
for (int i = 0; i < tickSpeed; ++i) {
final int index = simpleRandom.nextInt() & ((16 * 16 * 16) - 1);
if (index >= tickList.size()) { // Leaf - Micro optimizations for random tick - inline one-time value
// most of the time we fall here
continue;
}
final int location = tickList.getRaw(index); // Leaf - Micro optimizations for random tick - no unnecessary operations
final BlockState state = states.get(location);
// do not use a mutable pos, as some random tick implementations store the input without calling immutable()!
final BlockPos pos = new BlockPos((location & 15) | offsetX, (location >>> (4 + 4)) | offsetY, ((location >>> 4) & 15) | offsetZ); // Leaf - Micro optimizations for random tick - no redundant mask
state.randomTick(level, pos, simpleRandom); // Leaf - Micro optimizations for random tick - no redundant cast
if (doubleTickFluids) {
final FluidState fluidState = state.getFluidState();
if (fluidState.isRandomlyTicking()) {
fluidState.randomTick(level, pos, simpleRandom); // Leaf - Micro optimizations for random tick - no redundant cast
}
}
}
}
}
*/
public void randomTickChunk(
RandomSource randomSource,
LevelChunk chunk,
long tickSpeed
) {
// reuse the random number one time
long a;
if (cacheIdx == 0) {
a = cache;
cacheIdx = 1;
} else if (cacheIdx == 1) {
a = cache >>> 32;
cacheIdx = 2;
} else {
a = cache = rand.next();
cacheIdx = 0;
}
// 25% chance tick
if ((a & MASK_ONE_FOURTH) != 0L) {
int a = randomSource.nextInt();
if ((a & MASK_ONE_FOURTH) != 0) {
return;
}
// tick speed mul 4
tickSpeed = tickSpeed * 4;
long chance = chunk.leaf$randomTickChance();
// the chunk not exists random tickable block
if (chance == 0L && (chance = recompute(chunk, tickSpeed)) == 0) {
if (chance == 0L && (chance = recompute(chunk, tickSpeed)) == 0L) {
return;
}
// this is correct, don't modify
//
// when chance eq 0.1
// - skip: 0.1 >= 0.1..1.0
// - tick: 0.1 < 0.0..0.1
//
// (chance not newest)
if (chance >= (a & MASK)) {
if (chance >= (long) (a & MASK) || (chance = recompute(chunk, tickSpeed)) == 0L) {
return;
}
// recompute tickable block and chance.
//
// chance for next randomTickChunk
// tickingCount used this tick
//
// chance != 0
//
// always tick block when chance > 1
if ((chance = recompute(chunk, tickSpeed)) == 0) {
return;
}
long tickingCount = chunk.leaf$countTickingBlocks();
// tick one block base on chance
// fairly pick a random tickable block
// vanilla may do more tick
// recompute computed chance for that part
// so the tick count should same as vanilla
int randPos = (int) ((rand.next() & Integer.MAX_VALUE) % tickingCount);
OptionalLong pos = chunk.leaf$tickingPos(randPos);
// always true
int tickingCount = chunk.leaf$countTickingBlocks();
OptionalLong pos = chunk.leaf$tickingPos(randomSource.nextInt(tickingCount));
if (pos.isPresent()) {
tickPos.add(pos.getAsLong());
}
// chance less than one
// most case
if (chance < SCALE) {
return;
}
// attempt to do more tick
//
// chance == 1.5
// - loop 1: 50% tick
// - loop 2: never
//
// chance == 2.5
// - loop 1: always
// - loop 2: 50%
// - loop 3: never
chance -= SCALE;
long last = rand.next() & MASK;
while (last < chance) {
randPos = (int) ((rand.next() & Integer.MAX_VALUE) % tickingCount);
pos = chunk.leaf$tickingPos(randPos);
// always true
if (pos.isPresent()) {
tickPos.add(pos.getAsLong());
}
if (chance > SCALE) {
chance -= SCALE;
}
}
private final static class WyRand implements BitRandomSource {
private long state;
private static final long WY0 = 0x2d35_8dcc_aa6c_78a5L;
private static final long WY1 = 0x8bb8_4b93_962e_acc9L;
private static final int BITS = 64;
public WyRand(long seed) {
this.state = seed;
}
@Override
public int next(int bits) {
return (int)(this.next() >>> (BITS - bits));
}
@Override
public @NotNull RandomSource fork() {
return new WyRand(next());
}
@Override
public @NotNull PositionalRandomFactory forkPositional() {
throw new UnsupportedOperationException("forkPositional");
}
@Override
public void setSeed(long seed) {
this.state = seed;
}
public int nextInt() {
return (int) (next() & Integer.MAX_VALUE);
}
@Override
public double nextGaussian() {
throw new UnsupportedOperationException("nextGaussian");
}
public long next() {
long seed = this.state;
seed += WY0;
long aLow = seed & 0xFFFFFFFFL;
long aHigh = seed >>> 32;
long bLow = (seed ^ WY1) & 0xFFFFFFFFL;
long bHigh = (seed ^ WY1) >>> 32;
long loLo = aLow * bLow;
long hiLo = aHigh * bLow;
long loHi = aLow * bHigh;
long hiHi = aHigh * bHigh;
long mid1 = (loLo >>> 32) + (hiLo & 0xFFFFFFFFL) + (loHi & 0xFFFFFFFFL);
long mid2 = (hiLo >>> 32) + (loHi >>> 32) + (mid1 >>> 32);
this.state = seed;
return ((loLo & 0xFFFFFFFFL) | (mid1 << 32)) ^ hiHi + (mid2 & 0xFFFFFFFFL);
long last = randomSource.nextInt() & MASK;
while (last < chance) {
pos = chunk.leaf$tickingPos(randomSource.nextInt(tickingCount));
if (pos.isPresent()) {
tickPos.add(pos.getAsLong());
}
chance -= SCALE;
}
}
}
}