Use custom random in block random ticking
The CAS performed by the regular random appears expensive. These changes drop my server tick time locally @ tickSpeed = 10,000 from 53ms to 37ms.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
package ca.spottedleaf.moonrise.common.util;
|
||||
|
||||
import net.minecraft.world.level.levelgen.LegacyRandomSource;
|
||||
|
||||
/**
|
||||
* Avoid costly CAS of superclass
|
||||
*/
|
||||
public final class SimpleRandom extends LegacyRandomSource {
|
||||
|
||||
private static final long MULTIPLIER = 25214903917L;
|
||||
private static final long ADDEND = 11L;
|
||||
private static final int BITS = 48;
|
||||
private static final long MASK = (1L << BITS) - 1;
|
||||
|
||||
private long value;
|
||||
|
||||
public SimpleRandom(final long seed) {
|
||||
super(0L);
|
||||
this.value = seed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSeed(final long seed) {
|
||||
this.value = (seed ^ MULTIPLIER) & MASK;
|
||||
}
|
||||
|
||||
private long advanceSeed() {
|
||||
return this.value = ((this.value * MULTIPLIER) + ADDEND) & MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int next(final int bits) {
|
||||
return (int)(this.advanceSeed() >>> (BITS - bits));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextInt() {
|
||||
final long seed = this.advanceSeed();
|
||||
return (int)(seed >>> (BITS - Integer.SIZE));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int nextInt(final int bound) {
|
||||
if (bound <= 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
|
||||
final long value = this.advanceSeed() >>> (BITS - Integer.SIZE);
|
||||
return (int)((value * bound) >>> Integer.SIZE);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.mixin.random_ticking;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.list.IntList;
|
||||
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
|
||||
import ca.spottedleaf.moonrise.common.util.SimpleRandom;
|
||||
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
@@ -38,6 +39,24 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel {
|
||||
@Unique
|
||||
private static final LevelChunkSection[] EMPTY_SECTION_ARRAY = new LevelChunkSection[0];
|
||||
|
||||
@Unique
|
||||
private final SimpleRandom simpleRandom = new SimpleRandom(0L);
|
||||
|
||||
/**
|
||||
* @reason Use faster random
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "tickChunk",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/util/RandomSource;nextInt(I)I"
|
||||
)
|
||||
)
|
||||
private int nextInt(final RandomSource instance, final int bound) {
|
||||
return this.simpleRandom.nextInt(bound);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Optimise random ticking so that it will not retrieve BlockStates unnecessarily, as well as
|
||||
* optionally avoiding double ticking fluid blocks.
|
||||
@@ -55,7 +74,7 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel {
|
||||
@Local(ordinal = 0, argsOnly = true) final int tickSpeed) {
|
||||
final LevelChunkSection[] sections = chunk.getSections();
|
||||
final int minSection = WorldUtil.getMinSection((ServerLevel)(Object)this);
|
||||
final RandomSource random = this.random;
|
||||
final SimpleRandom simpleRandom = this.simpleRandom;
|
||||
final boolean tickFluids = !MoonriseCommon.getConfig().bugFixes.fixMC224294;
|
||||
|
||||
final ChunkPos cpos = chunk.getPos();
|
||||
@@ -74,7 +93,7 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel {
|
||||
|
||||
for (int i = 0; i < tickSpeed; ++i) {
|
||||
final int tickingBlocks = tickList.size();
|
||||
final int index = random.nextInt() & ((16 * 16 * 16) - 1);
|
||||
final int index = simpleRandom.nextInt() & ((16 * 16 * 16) - 1);
|
||||
|
||||
if (index >= tickingBlocks) {
|
||||
// most of the time we fall here
|
||||
@@ -87,11 +106,11 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel {
|
||||
// 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)) & 15) | offsetY, ((location >>> 4) & 15) | offsetZ);
|
||||
|
||||
state.randomTick((ServerLevel)(Object)this, pos, random);
|
||||
state.randomTick((ServerLevel)(Object)this, pos, simpleRandom);
|
||||
if (tickFluids) {
|
||||
final FluidState fluidState = state.getFluidState();
|
||||
if (fluidState.isRandomlyTicking()) {
|
||||
fluidState.randomTick((ServerLevel)(Object)this, pos, random);
|
||||
fluidState.randomTick((ServerLevel)(Object)this, pos, simpleRandom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user