From 85e7505d30763b6f838d0c0b454d7d12fb36f459 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 10 Mar 2025 18:54:04 +0700 Subject: [PATCH] Initial implementation --- .../mc/prng/GJRAND64RandomSource.java | 142 ++++++++++++++++++ .../mc/prng/mixin/RandomSourceMixin.java | 19 +++ src/main/resources/better_random.mixins.json | 11 ++ .../templates/META-INF/neoforge.mods.toml | 4 +- 4 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ru/dbotthepony/mc/prng/GJRAND64RandomSource.java create mode 100644 src/main/java/ru/dbotthepony/mc/prng/mixin/RandomSourceMixin.java create mode 100644 src/main/resources/better_random.mixins.json diff --git a/src/main/java/ru/dbotthepony/mc/prng/GJRAND64RandomSource.java b/src/main/java/ru/dbotthepony/mc/prng/GJRAND64RandomSource.java new file mode 100644 index 0000000..60669ca --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/prng/GJRAND64RandomSource.java @@ -0,0 +1,142 @@ +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(); + } + } +} diff --git a/src/main/java/ru/dbotthepony/mc/prng/mixin/RandomSourceMixin.java b/src/main/java/ru/dbotthepony/mc/prng/mixin/RandomSourceMixin.java new file mode 100644 index 0000000..14100ce --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/prng/mixin/RandomSourceMixin.java @@ -0,0 +1,19 @@ +package ru.dbotthepony.mc.prng.mixin; + +import net.minecraft.util.RandomSource; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.prng.GJRAND64RandomSource; + +@Mixin(RandomSource.class) +public interface RandomSourceMixin { + @Overwrite + static RandomSource create() { + return new GJRAND64RandomSource(); + } + + @Overwrite + static RandomSource create(long seed) { + return new GJRAND64RandomSource(seed); + } +} diff --git a/src/main/resources/better_random.mixins.json b/src/main/resources/better_random.mixins.json new file mode 100644 index 0000000..2b0a98c --- /dev/null +++ b/src/main/resources/better_random.mixins.json @@ -0,0 +1,11 @@ + +{ + "required": true, + "package": "ru.dbotthepony.mc.prng.mixin", + "compatibilityLevel": "JAVA_21", + "minVersion": "0.8", + "mixins": [ + "RandomSourceMixin" + ], + "client": [] +} diff --git a/src/main/templates/META-INF/neoforge.mods.toml b/src/main/templates/META-INF/neoforge.mods.toml index 1b9f6e9..64b908f 100644 --- a/src/main/templates/META-INF/neoforge.mods.toml +++ b/src/main/templates/META-INF/neoforge.mods.toml @@ -47,8 +47,8 @@ authors="${mod_authors}" #optional description='''${mod_description}''' # The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded. -#[[mixins]] -#config="${mod_id}.mixins.json" +[[mixins]] +config="${mod_id}.mixins.json" # The [[accessTransformers]] block allows you to declare where your AT file is. # If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg