diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/FastRNG.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/FastRNG.java index f45592ea..8ea8ce11 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/FastRNG.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/FastRNG.java @@ -17,6 +17,7 @@ public class FastRNG extends ConfigModules { public static String randomGenerator = "Xoroshiro128PlusPlus"; public static boolean warnForSlimeChunk = true; public static boolean useLegacyForSlimeChunk = false; + public static boolean useDirectImpl = false; public static boolean worldgenEnabled() {return enabled && enableForWorldgen;} // Helper function @@ -58,6 +59,14 @@ public class FastRNG extends ConfigModules { to follow vanilla behavior.""", """ 是否使用原版随机生成器来生成史莱姆区块.""")); + useDirectImpl = config.getBoolean(getBasePath() + ".use-direct-implementation", useDirectImpl, + config.pickStringRegionBased( + """ + Use direct random implementation instead of delegating to Java's RandomGenerator. + This may improve performance but potentially changes RNG behavior.""", + """ + 使用直接随机实现而不是委托给Java的RandomGenerator. + 这可能会提高性能,但可能会改变RNG行为。""")); if (enabled) { try { diff --git a/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java b/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java index 84b48703..9bd0150c 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/util/math/random/FasterRandomSource.java @@ -21,17 +21,20 @@ public class FasterRandomSource implements BitRandomSource { private static final RandomGeneratorFactory RANDOM_GENERATOR_FACTORY = RandomGeneratorFactory.of(FastRNG.randomGenerator); private static final boolean isSplittableGenerator = RANDOM_GENERATOR_FACTORY.isSplittable(); private long seed; + private boolean useDirectImpl; private RandomGenerator randomGenerator; public static final FasterRandomSource SHARED_INSTANCE = new FasterRandomSource(ThreadLocalRandom.current().nextLong()); public FasterRandomSource(long seed) { this.seed = seed; this.randomGenerator = RANDOM_GENERATOR_FACTORY.create(seed); + this.useDirectImpl = FastRNG.useDirectImpl; // Get the value from config } private FasterRandomSource(long seed, RandomGenerator.SplittableGenerator randomGenerator) { this.seed = seed; this.randomGenerator = randomGenerator; + this.useDirectImpl = FastRNG.useDirectImpl; } @Override @@ -55,8 +58,13 @@ public class FasterRandomSource implements BitRandomSource { @Override public final int next(int bits) { - // >>> instead of Mojang's >> fixes MC-239059 - return (int) ((seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> INT_BITS - bits); + if (useDirectImpl) { + // Direct + return (int) ((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits)); + } else { + // old + return (int) ((seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits)); + } } public static class FasterRandomSourcePositionalRandomFactory implements PositionalRandomFactory { @@ -93,36 +101,71 @@ public class FasterRandomSource implements BitRandomSource { @Override public final int nextInt() { - return randomGenerator.nextInt(); + if (useDirectImpl) { + return (int) (((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> 16) ^ + ((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> 32)); + } else { + return randomGenerator.nextInt(); + } } @Override public final int nextInt(int bound) { - return randomGenerator.nextInt(bound); + if (useDirectImpl && bound > 0) { + if ((bound & -bound) == bound) { + return (int) ((bound * (long) next(31)) >> 31); + } + int bits, val; + do { + bits = next(31); + val = bits % bound; + } while (bits - val + (bound - 1) < 0); + return val; + } else { + return randomGenerator.nextInt(bound); + } } @Override public final long nextLong() { - return randomGenerator.nextLong(); + if (useDirectImpl) { + return ((long) next(32) << 32) + next(32); + } else { + return randomGenerator.nextLong(); + } } @Override public final boolean nextBoolean() { - return randomGenerator.nextBoolean(); + if (useDirectImpl) { + return next(1) != 0; + } else { + return randomGenerator.nextBoolean(); + } } @Override public final float nextFloat() { - return randomGenerator.nextFloat(); + if (useDirectImpl) { + return next(24) / ((float) (1 << 24)); + } else { + return randomGenerator.nextFloat(); + } } @Override public final double nextDouble() { - return randomGenerator.nextDouble(); + if (useDirectImpl) { + return (((long) next(26) << 27) + next(27)) / (double) (1L << 53); + } else { + return randomGenerator.nextDouble(); + } } @Override public final double nextGaussian() { + // delegate Gaussian distribution to RandomGenerator + // as direct implementation would be complex (i aint doin allat) return randomGenerator.nextGaussian(); } }