From 9417d6ffdc8d5d6ba7307fb57da2254b9a14cdcb Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 01:03:00 +0700 Subject: [PATCH 01/10] Use more robust 64-bit LCG for seeding CMWC internal state --- .../ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt index 7ec103ac8..d37b80c50 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt @@ -24,12 +24,12 @@ class CMWCRandom(seed: Long = System.nanoTime()) : RandomGenerator, RandomSource this.seed = seed carry = Integer.remainderUnsigned(seed.toInt(), CMWC_CARRY_MAX) - // init state with regular LCG produced values - state[0] = seed.toInt() - state[1] = seed.shr(32).toInt() + var lcg = seed - for (i in 2 until state.size) { - state[i] = 69069 * state[i - 2] + 362437 + // init state with regular LCG produced values + for (i in 1 until state.size) { + lcg = lcg * 6364136223846793005 + 1442695040888963407 + state[i] = lcg.ushr(32).toInt() } stateIndex = state.size - 1 From d326e45b3201ebee33c736e9899bd13e7159cbda Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 07:58:48 +0700 Subject: [PATCH 02/10] Initialize carry using lcg instead of modulo divide seed --- .../kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt index d37b80c50..bad5a002d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt @@ -22,8 +22,6 @@ class CMWCRandom(seed: Long = System.nanoTime()) : RandomGenerator, RandomSource override fun setSeed(seed: Long) { this.seed = seed - carry = Integer.remainderUnsigned(seed.toInt(), CMWC_CARRY_MAX) - var lcg = seed // init state with regular LCG produced values @@ -32,6 +30,11 @@ class CMWCRandom(seed: Long = System.nanoTime()) : RandomGenerator, RandomSource state[i] = lcg.ushr(32).toInt() } + do { + lcg = lcg * 6364136223846793005 + 1442695040888963407 + carry = lcg.ushr(32).toInt() + } while(carry !in 0 until CMWC_CARRY_MAX) + stateIndex = state.size - 1 gaussian.reset() } From e03d9b1a742a0ff36526fc21ce2241a131321bf7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 08:36:24 +0700 Subject: [PATCH 03/10] Provide LCG64 implementation as separate class --- .../mc/otm/core/util/CMWCRandom.kt | 8 +- .../mc/otm/core/util/LCG64Random.kt | 86 +++++++++++++++++++ 2 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt index bad5a002d..e21285761 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt @@ -22,17 +22,15 @@ class CMWCRandom(seed: Long = System.nanoTime()) : RandomGenerator, RandomSource override fun setSeed(seed: Long) { this.seed = seed - var lcg = seed + val rng = LCG64Random(seed) // init state with regular LCG produced values for (i in 1 until state.size) { - lcg = lcg * 6364136223846793005 + 1442695040888963407 - state[i] = lcg.ushr(32).toInt() + state[i] = rng.nextInt() } do { - lcg = lcg * 6364136223846793005 + 1442695040888963407 - carry = lcg.ushr(32).toInt() + carry = rng.nextInt() } while(carry !in 0 until CMWC_CARRY_MAX) stateIndex = state.size - 1 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt new file mode 100644 index 000000000..271b8a6a9 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt @@ -0,0 +1,86 @@ +package ru.dbotthepony.mc.otm.core.util + +import net.minecraft.util.Mth +import net.minecraft.util.RandomSource +import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian +import net.minecraft.world.level.levelgen.PositionalRandomFactory +import java.lang.StringBuilder +import java.util.random.RandomGenerator + +// different from LegacyRandomSource minecraft uses in meaning that this class use different constants +// and always use upper 32 bits instead of implementing BitRandomSource +// AND it uses all bits from provided seed +class LCG64Random(private var seed: Long = System.nanoTime()) : RandomGenerator, RandomSource { + private val gaussian = MarsagliaPolarGaussian(this) + + override fun setSeed(seed: Long) { + this.seed = seed + gaussian.reset() + } + + override fun nextInt(): Int { + this.seed = MULTIPLIER * this.seed + INCREMENT + return this.seed.ushr(32).toInt() + } + + override fun nextLong(): Long { + val a = nextInt().toLong() and 0xFFFFFFFFL + val b = nextInt().toLong() and 0xFFFFFFFFL + return a.shl(32) or b + } + + override fun nextInt(bound: Int): Int { + return super.nextInt(bound) + } + + override fun nextInt(origin: Int, bound: Int): Int { + return super.nextInt(origin, bound) + } + + override fun nextBoolean(): Boolean { + return super.nextBoolean() + } + + override fun nextFloat(): Float { + return super.nextFloat() + } + + override fun nextDouble(): Double { + return super.nextDouble() + } + + override fun nextGaussian(): Double { + return gaussian.nextGaussian() + } + + override fun fork(): RandomSource { + return LCG64Random(nextLong()) + } + + override fun forkPositional(): PositionalRandomFactory { + return Positional(nextLong()) + } + + class Positional(val seed: Long) : PositionalRandomFactory { + override fun at(x: Int, y: Int, z: Int): RandomSource { + return LCG64Random(Mth.getSeed(x, y, z).xor(seed)) + } + + override fun fromHashOf(name: String): RandomSource { + return LCG64Random(name.hashCode().toLong().xor(seed)) + } + + override fun fromSeed(seed: Long): RandomSource { + return LCG64Random(seed) + } + + override fun parityConfigString(builder: StringBuilder) { + throw UnsupportedOperationException() + } + } + + companion object { + const val MULTIPLIER = 6364136223846793005 + const val INCREMENT = 1442695040888963407 + } +} From 6c087a278d7aa0b391bea0c0c938e984b7fae8dc Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 08:38:07 +0700 Subject: [PATCH 04/10] Don't store seed since it is of no use --- src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt index e21285761..a41a68b54 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt @@ -13,15 +13,11 @@ class CMWCRandom(seed: Long = System.nanoTime()) : RandomGenerator, RandomSource private var stateIndex = 0 private val gaussian = MarsagliaPolarGaussian(this) - var seed: Long = seed - private set - init { setSeed(seed) } override fun setSeed(seed: Long) { - this.seed = seed val rng = LCG64Random(seed) // init state with regular LCG produced values From 49f76c7bddad53dda407c3dfd577eafacdaa7061 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 09:06:44 +0700 Subject: [PATCH 05/10] Provide Xoshiro256StarStar random --- .../mc/otm/core/util/Xoshiro256SSRandom.kt | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt new file mode 100644 index 000000000..e14e7ed02 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt @@ -0,0 +1,110 @@ +package ru.dbotthepony.mc.otm.core.util + +import it.unimi.dsi.fastutil.HashCommon +import net.minecraft.util.Mth +import net.minecraft.util.RandomSource +import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian +import net.minecraft.world.level.levelgen.PositionalRandomFactory +import java.lang.StringBuilder +import java.util.random.RandomGenerator + +class Xoshiro256SSRandom( + private var s0: Long, + private var s1: Long, + private var s2: Long, + private var s3: Long, +) : RandomGenerator, RandomSource { + private val gaussian = MarsagliaPolarGaussian(this) + + constructor(seed: Long = System.nanoTime()) : this(1L, 2L, 3L, 4L) { + setSeed(seed) + } + + override fun setSeed(seed: Long) { + val rng = LCG64Random(seed) + s0 = rng.nextLong() + s1 = rng.nextLong() + s2 = rng.nextLong() + s3 = rng.nextLong() + gaussian.reset() + } + + override fun nextInt(): Int { + // sample upper bits + return nextLong().ushr(32).toInt() + } + + override fun nextLong(): Long { + val result = (s1 * 5).rotateLeft(7) * 9 + val t = s1.shl(17) + s2 = s2.xor(s0) + s3 = s3.xor(s1) + s1 = s1.xor(s2) + s0 = s0.xor(s3) + s2 = s2.xor(t) + s3 = s3.rotateLeft(45) + return result + } + + override fun nextInt(bound: Int): Int { + return super.nextInt(bound) + } + + override fun nextInt(origin: Int, bound: Int): Int { + return super.nextInt(origin, bound) + } + + override fun nextBoolean(): Boolean { + return super.nextBoolean() + } + + override fun nextFloat(): Float { + return super.nextFloat() + } + + override fun nextDouble(): Double { + return super.nextDouble() + } + + override fun nextGaussian(): Double { + return gaussian.nextGaussian() + } + + override fun fork(): RandomSource { + return Xoshiro256SSRandom(nextLong(), nextLong(), nextLong(), nextLong()) + } + + override fun forkPositional(): PositionalRandomFactory { + return Positional(nextLong(), nextLong(), nextLong(), nextLong()) + } + + class Positional( + val s0: Long, + val s1: Long, + val s2: Long, + val s3: Long, + ) : PositionalRandomFactory { + override fun at(x: Int, y: Int, z: Int): RandomSource { + val rng = LCG64Random(Mth.getSeed(x, y, z)) + + return Xoshiro256SSRandom( + s0.rotateLeft(11).xor(rng.nextLong()), + s1.rotateLeft(22).xor(rng.nextLong()), + s2.rotateLeft(33).xor(rng.nextLong()), + s3.rotateLeft(44).xor(rng.nextLong()), + ) + } + + override fun fromHashOf(name: String): RandomSource { + return Xoshiro256SSRandom(s0, HashCommon.murmurHash3(name.hashCode().toLong()).xor(s1), s2, s3) + } + + override fun fromSeed(seed: Long): RandomSource { + return Xoshiro256SSRandom(seed) + } + + override fun parityConfigString(builder: StringBuilder) { + throw UnsupportedOperationException() + } + } +} From f19804dd4a661cf762e179257152beb71e08013d Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 09:08:33 +0700 Subject: [PATCH 06/10] Provide better random seeds for random number generators --- .../kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt | 3 ++- .../kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt | 3 ++- .../ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt index a41a68b54..767637340 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt @@ -4,10 +4,11 @@ import net.minecraft.util.Mth import net.minecraft.util.RandomSource import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.PositionalRandomFactory +import net.minecraft.world.level.levelgen.RandomSupport import java.lang.StringBuilder import java.util.random.RandomGenerator -class CMWCRandom(seed: Long = System.nanoTime()) : RandomGenerator, RandomSource { +class CMWCRandom(seed: Long = RandomSupport.generateUniqueSeed()) : RandomGenerator, RandomSource { private val state = IntArray(CMWC_STATE_SIZE) private var carry = 0 private var stateIndex = 0 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt index 271b8a6a9..7cac69c0d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt @@ -4,13 +4,14 @@ import net.minecraft.util.Mth import net.minecraft.util.RandomSource import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.PositionalRandomFactory +import net.minecraft.world.level.levelgen.RandomSupport import java.lang.StringBuilder import java.util.random.RandomGenerator // different from LegacyRandomSource minecraft uses in meaning that this class use different constants // and always use upper 32 bits instead of implementing BitRandomSource // AND it uses all bits from provided seed -class LCG64Random(private var seed: Long = System.nanoTime()) : RandomGenerator, RandomSource { +class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) : RandomGenerator, RandomSource { private val gaussian = MarsagliaPolarGaussian(this) override fun setSeed(seed: Long) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt index e14e7ed02..472c89b27 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt @@ -5,6 +5,7 @@ import net.minecraft.util.Mth import net.minecraft.util.RandomSource import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.PositionalRandomFactory +import net.minecraft.world.level.levelgen.RandomSupport import java.lang.StringBuilder import java.util.random.RandomGenerator @@ -16,10 +17,12 @@ class Xoshiro256SSRandom( ) : RandomGenerator, RandomSource { private val gaussian = MarsagliaPolarGaussian(this) - constructor(seed: Long = System.nanoTime()) : this(1L, 2L, 3L, 4L) { + constructor(seed: Long) : this(1L, 2L, 3L, 4L) { setSeed(seed) } + constructor() : this(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed()) + override fun setSeed(seed: Long) { val rng = LCG64Random(seed) s0 = rng.nextLong() From 1a52864c4e97493444835cdc605f3f6f9c935d02 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 09:31:28 +0700 Subject: [PATCH 07/10] Throw an exception when xoshiro seed is completely zero --- .../dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt index 472c89b27..8f368e7e6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt @@ -17,6 +17,15 @@ class Xoshiro256SSRandom( ) : RandomGenerator, RandomSource { private val gaussian = MarsagliaPolarGaussian(this) + init { + require( + s0 != 0L || + s1 != 0L || + s2 != 0L || + s3 != 0L + ) { "Xoshiro can't operate with seed being entirely zero" } + } + constructor(seed: Long) : this(1L, 2L, 3L, 4L) { setSeed(seed) } From b8291c7e1c060f4995e005ec769e5905e3703c31 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 09:34:14 +0700 Subject: [PATCH 08/10] Proper Xoshiro256 initialization with 256 bit seed --- .../mc/otm/core/util/Xoshiro256SSRandom.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt index 8f368e7e6..492db9761 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt @@ -9,11 +9,12 @@ import net.minecraft.world.level.levelgen.RandomSupport import java.lang.StringBuilder import java.util.random.RandomGenerator -class Xoshiro256SSRandom( +class Xoshiro256SSRandom private constructor( private var s0: Long, private var s1: Long, private var s2: Long, private var s3: Long, + marker: Nothing? ) : RandomGenerator, RandomSource { private val gaussian = MarsagliaPolarGaussian(this) @@ -26,11 +27,17 @@ class Xoshiro256SSRandom( ) { "Xoshiro can't operate with seed being entirely zero" } } - constructor(seed: Long) : this(1L, 2L, 3L, 4L) { + constructor(s0: Long, s1: Long, s2: Long, s3: Long) : this(s0, s1, s2, s3, null) { + // discard some values so generator can get going if provided seed was "weak" + for (i in 0 until 32) + nextLong() + } + + constructor(seed: Long) : this(1L, 2L, 3L, 4L, null) { setSeed(seed) } - constructor() : this(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed()) + constructor() : this(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), null) override fun setSeed(seed: Long) { val rng = LCG64Random(seed) From 95f1a304c981aa642b88a76077a245db1d6e9927 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 09:41:53 +0700 Subject: [PATCH 09/10] Provide docs for random number generators --- .../ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt | 3 +++ .../ru/dbotthepony/mc/otm/core/util/LCG64Random.kt | 14 +++++++++++--- .../mc/otm/core/util/Xoshiro256SSRandom.kt | 3 +++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt index 767637340..16d885b7e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt @@ -8,6 +8,9 @@ import net.minecraft.world.level.levelgen.RandomSupport import java.lang.StringBuilder import java.util.random.RandomGenerator +/** + * Random number generator with insane period of at least 2^511 + */ class CMWCRandom(seed: Long = RandomSupport.generateUniqueSeed()) : RandomGenerator, RandomSource { private val state = IntArray(CMWC_STATE_SIZE) private var carry = 0 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt index 7cac69c0d..d6edf5afc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt @@ -2,15 +2,23 @@ package ru.dbotthepony.mc.otm.core.util import net.minecraft.util.Mth import net.minecraft.util.RandomSource +import net.minecraft.world.level.levelgen.LegacyRandomSource import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.PositionalRandomFactory import net.minecraft.world.level.levelgen.RandomSupport import java.lang.StringBuilder import java.util.random.RandomGenerator -// different from LegacyRandomSource minecraft uses in meaning that this class use different constants -// and always use upper 32 bits instead of implementing BitRandomSource -// AND it uses all bits from provided seed +/** + * Simple and insanely fast random number generator, which can be used for seeding (initializing internal state) of other number generators. + * + * While can be used on its own, it probably shouldn't. + * + * Differs from [LegacyRandomSource] (also LCG, created by [RandomSource.create]) Minecraft uses in: + * * Different constants (with supposedly/expected better statistical properties) + * * Always use upper 32 bits instead of implementing BitRandomSource and sampling some upper bits + * * Uses all bits from provided seed + */ class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) : RandomGenerator, RandomSource { private val gaussian = MarsagliaPolarGaussian(this) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt index 492db9761..99438ed72 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt @@ -9,6 +9,9 @@ import net.minecraft.world.level.levelgen.RandomSupport import java.lang.StringBuilder import java.util.random.RandomGenerator +/** + * Excellent number generator with guaranteed period of 2^255 + */ class Xoshiro256SSRandom private constructor( private var s0: Long, private var s1: Long, From 991314c07b7d1f4fcb016c8ef971775f971a5434 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 09:44:02 +0700 Subject: [PATCH 10/10] Use Xoshiro256SSRandom instead of CMWC for OTM provided level random --- src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java index 6ad554f3f..8f60b5a71 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java @@ -5,11 +5,11 @@ import net.minecraft.world.level.Level; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; import ru.dbotthepony.mc.otm.core.IMatteryLevel; -import ru.dbotthepony.mc.otm.core.util.CMWCRandom; +import ru.dbotthepony.mc.otm.core.util.Xoshiro256SSRandom; @Mixin(Level.class) public abstract class LevelMixin implements IMatteryLevel { - public final RandomSource otm_random = new CMWCRandom(); + public final RandomSource otm_random = new Xoshiro256SSRandom(); @Override public @NotNull RandomSource getOtmRandom() {