Merge branch 'prng' into 1.21
This commit is contained in:
commit
828c80dfd4
@ -5,11 +5,11 @@ import net.minecraft.world.level.Level;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import ru.dbotthepony.mc.otm.core.IMatteryLevel;
|
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)
|
@Mixin(Level.class)
|
||||||
public abstract class LevelMixin implements IMatteryLevel {
|
public abstract class LevelMixin implements IMatteryLevel {
|
||||||
public final RandomSource otm_random = new CMWCRandom();
|
public final RandomSource otm_random = new Xoshiro256SSRandom();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull RandomSource getOtmRandom() {
|
public @NotNull RandomSource getOtmRandom() {
|
||||||
|
@ -4,34 +4,35 @@ import net.minecraft.util.Mth
|
|||||||
import net.minecraft.util.RandomSource
|
import net.minecraft.util.RandomSource
|
||||||
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian
|
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian
|
||||||
import net.minecraft.world.level.levelgen.PositionalRandomFactory
|
import net.minecraft.world.level.levelgen.PositionalRandomFactory
|
||||||
|
import net.minecraft.world.level.levelgen.RandomSupport
|
||||||
import java.lang.StringBuilder
|
import java.lang.StringBuilder
|
||||||
import java.util.random.RandomGenerator
|
import java.util.random.RandomGenerator
|
||||||
|
|
||||||
class CMWCRandom(seed: Long = System.nanoTime()) : RandomGenerator, RandomSource {
|
/**
|
||||||
|
* 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 val state = IntArray(CMWC_STATE_SIZE)
|
||||||
private var carry = 0
|
private var carry = 0
|
||||||
private var stateIndex = 0
|
private var stateIndex = 0
|
||||||
private val gaussian = MarsagliaPolarGaussian(this)
|
private val gaussian = MarsagliaPolarGaussian(this)
|
||||||
|
|
||||||
var seed: Long = seed
|
|
||||||
private set
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setSeed(seed)
|
setSeed(seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setSeed(seed: Long) {
|
override fun setSeed(seed: Long) {
|
||||||
this.seed = seed
|
val rng = LCG64Random(seed)
|
||||||
carry = Integer.remainderUnsigned(seed.toInt(), CMWC_CARRY_MAX)
|
|
||||||
|
|
||||||
// init state with regular LCG produced values
|
// init state with regular LCG produced values
|
||||||
state[0] = seed.toInt()
|
for (i in 1 until state.size) {
|
||||||
state[1] = seed.shr(32).toInt()
|
state[i] = rng.nextInt()
|
||||||
|
|
||||||
for (i in 2 until state.size) {
|
|
||||||
state[i] = 69069 * state[i - 2] + 362437
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
carry = rng.nextInt()
|
||||||
|
} while(carry !in 0 until CMWC_CARRY_MAX)
|
||||||
|
|
||||||
stateIndex = state.size - 1
|
stateIndex = state.size - 1
|
||||||
gaussian.reset()
|
gaussian.reset()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,95 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
|
||||||
|
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<RandomGenerator>.nextInt(bound)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nextInt(origin: Int, bound: Int): Int {
|
||||||
|
return super<RandomGenerator>.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
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
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 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,
|
||||||
|
private var s2: Long,
|
||||||
|
private var s3: Long,
|
||||||
|
marker: Nothing?
|
||||||
|
) : 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(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(), null)
|
||||||
|
|
||||||
|
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<RandomGenerator>.nextInt(bound)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nextInt(origin: Int, bound: Int): Int {
|
||||||
|
return super<RandomGenerator>.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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user