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 + } +}