package ru.dbotthepony.mc.prng; 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 org.jetbrains.annotations.NotNull; import java.util.random.RandomGenerator; public final class GJRAND64RandomSource implements RandomGenerator, RandomSource { private long s0; private long s1; private long s2; private long s3; private final MarsagliaPolarGaussian gaussian = new MarsagliaPolarGaussian(this); public GJRAND64RandomSource() { reinitialize(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed()); } public GJRAND64RandomSource(long seed) { reinitialize(seed); } public GJRAND64RandomSource(long seed0, long seed1) { reinitialize(seed0, seed1); } private void reinitialize(long seed) { reinitialize(seed, 0L); } private void reinitialize(long seed0, long seed1) { s0 = seed0; s1 = seed1; s2 = 2000001L; s3 = 0L; } @Override public @NotNull RandomSource fork() { return new GJRAND64RandomSource(nextLong(), nextLong()); } @Override public @NotNull PositionalRandomFactory forkPositional() { return new Positional(nextLong(), nextLong()); } @Override public void setSeed(long l) { reinitialize(l); gaussian.reset(); } @Override public int nextInt() { return RandomGenerator.super.nextInt(); } @Override public int nextInt(int bound) { return RandomGenerator.super.nextInt(bound); } @Override public int nextInt(int origin, int bound) { return RandomGenerator.super.nextInt(origin, bound); } @Override public float nextFloat() { return RandomGenerator.super.nextFloat(); } @Override public boolean nextBoolean() { return RandomGenerator.super.nextBoolean(); } @Override public double nextDouble() { return RandomGenerator.super.nextDouble(); } @Override public double nextGaussian() { return gaussian.nextGaussian(); } @Override public long nextLong() { s1 += s2; s0 = Long.rotateLeft(s0, 32); s2 ^= s1; s3 += 0x55aa96a5L; s0 += s1; s2 = Long.rotateLeft(s2, 23); s1 ^= s0; s0 += s2; s1 = Long.rotateLeft(s1, 19); s2 += s0; s1 += s3; return s0; } public static class Positional implements PositionalRandomFactory { private final long seed0; private final long seed1; public Positional(long seed0, long seed1) { this.seed0 = seed0; this.seed1 = seed1; } @Override public @NotNull RandomSource fromHashOf(@NotNull String s) { long seed = HashCommon.murmurHash3((long) s.hashCode() & 0xFFFFFFFFL); return new GJRAND64RandomSource(seed0 ^ Long.rotateLeft(seed, 32), seed1 ^ seed); } @Override public @NotNull RandomSource fromSeed(long l) { return new GJRAND64RandomSource(l); } @Override public @NotNull RandomSource at(int x, int y, int z) { long seed = Mth.getSeed(x, y, z); return new GJRAND64RandomSource(seed0 ^ Long.rotateLeft(seed, 32), seed1 ^ seed); } @Override public void parityConfigString(@NotNull StringBuilder stringBuilder) { throw new UnsupportedOperationException(); } } }