From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Wed, 5 Jan 2022 12:25:37 -0500 Subject: [PATCH] Use XoRoShiRoRandom Original code by Titaniumtown, licensed under GNU General Public License v3.0 You can find the original code on https://gitlab.com/Titaniumtown/JettPack diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java index 20cfe7b9b7127ddeb97aa91d759fc17b4a548eaf..34665a768285fd99e49d57d3879deb1fe3c7df32 100644 --- a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java +++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java @@ -13,7 +13,7 @@ import java.util.UUID; public class PaperLootableInventoryData { - private static final Random RANDOM = new Random(); + private static final Random RANDOM = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack private long lastFill = -1; private long nextRefill = -1; diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 663ab7f3c2e7514c211f01114aa8869f24615da0..5830bda766ea88bb45096d900afe76600ce2f9e0 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -415,7 +415,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { }; this.status = new ServerStatus(); - this.random = new Random(); + this.random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack this.port = -1; this.levels = Maps.newLinkedHashMap(); // CraftBukkit - keep order, k+v already use identity methods this.running = true; diff --git a/src/main/java/net/minecraft/server/commands/SpreadPlayersCommand.java b/src/main/java/net/minecraft/server/commands/SpreadPlayersCommand.java index 62f26f5d3ef5546f26424185e378fea64c08ce2f..54559b015813ca1c5dae9cb229a4a63f3bc3d47a 100644 --- a/src/main/java/net/minecraft/server/commands/SpreadPlayersCommand.java +++ b/src/main/java/net/minecraft/server/commands/SpreadPlayersCommand.java @@ -55,7 +55,7 @@ public class SpreadPlayersCommand { } private static int spreadPlayers(CommandSourceStack source, Vec2 center, float spreadDistance, float maxRange, int maxY, boolean respectTeams, Collection players) throws CommandSyntaxException { - Random random = new Random(); + Random random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack double d0 = (double) (center.x - maxRange); double d1 = (double) (center.y - maxRange); double d2 = (double) (center.x + maxRange); diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 7b23535a680d2a8534dcb8dd87770f66fb982c13..5e9c7f428e4a0d920569c2a02e999da910fc9397 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -368,7 +368,7 @@ public class ServerPlayer extends Player { long l = k * k; int i1 = l > 2147483647L ? Integer.MAX_VALUE : (int) l; int j1 = this.getCoprime(i1); - int k1 = (new Random()).nextInt(i1); + int k1 = (wtf.etil.mirai.server.util.XoRoShiRoRandom()).nextInt(i1); // JettPack for (int l1 = 0; l1 < i1; ++l1) { int i2 = (k1 + j1 * l1) % i1; @@ -405,7 +405,7 @@ public class ServerPlayer extends Player { long l = k * k; int i1 = l > 2147483647L ? Integer.MAX_VALUE : (int) l; int j1 = this.getCoprime(i1); - int k1 = (new Random()).nextInt(i1); + int k1 = (wtf.etil.mirai.server.util.XoRoShiRoRandom()).nextInt(i1); // JettPack for (int l1 = 0; l1 < i1; ++l1) { int i2 = (k1 + j1 * l1) % i1; diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java index 462d8c36166c63a4dc8fa74ac7f82859e6f4b83a..1be5ae3162f2e2b5a48310c162edf8bdc8a08c2b 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -52,7 +52,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener private static final AtomicInteger UNIQUE_THREAD_ID = new AtomicInteger(0); static final Logger LOGGER = LogManager.getLogger(); private static final int MAX_TICKS_BEFORE_LOGIN = 600; - private static final Random RANDOM = new Random(); + private static final Random RANDOM = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack private final byte[] nonce = new byte[4]; final MinecraftServer server; public final Connection connection; diff --git a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java index 25ae440839f1d286550a77d0a4c61e1dc02b369d..f42bce03c21309efbb208be21263b6c09927ed6c 100644 --- a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java +++ b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java @@ -348,7 +348,7 @@ public class QueryThreadGs4 extends GenericThread { this.identBytes[2] = bs[5]; this.identBytes[3] = bs[6]; this.ident = new String(this.identBytes, StandardCharsets.UTF_8); - this.challenge = (new Random()).nextInt(16777216); + this.challenge = (wtf.etil.mirai.server.util.XoRoShiRoRandom()).nextInt(16777216); // JettPack this.challengeBytes = String.format("\t%s%d\u0000", this.ident, this.challenge).getBytes(StandardCharsets.UTF_8); } diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java index 204ca4fbd89bdadd902529f1f191df46fce3cace..fa0845fffc358ae11dc81e6119afce8ffdc78571 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java @@ -13,7 +13,7 @@ import java.util.stream.Stream; public class ShufflingList { public final List> entries; // Paper - public - private final Random random = new Random(); + private final Random random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack private final boolean isUnsafe; // Paper public ShufflingList() { diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java index f3b8e253a5bfc3f68121dbe656ae7e2ac0f0eb1c..4b7dd3f2157d0f78bc35ec865555682d0f61445f 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java @@ -8,7 +8,7 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.targeting.TargetingConditions; public abstract class Sensor { - private static final Random RANDOM = new Random(); + private static final Random RANDOM = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack private static final int DEFAULT_SCAN_RATE = 20; protected static final int TARGETING_RANGE = 16; private static final TargetingConditions TARGET_CONDITIONS = TargetingConditions.forNonCombat().range(16.0D); diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java index 323eea2bccacfcc85849b5d82c2b30d991e0c0d8..20668da3594346511b065146a2b7478c98283b9b 100644 --- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java @@ -35,7 +35,7 @@ public class WanderingTraderSpawner implements CustomSpawner { private static final int SPAWN_CHANCE_INCREASE = 25; private static final int SPAWN_ONE_IN_X_CHANCE = 10; private static final int NUMBER_OF_SPAWN_ATTEMPTS = 10; - private final Random random = new Random(); + private final Random random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack private final ServerLevelData serverLevelData; private int tickDelay; private int spawnDelay; diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java index 2015223c1703935faef52a8b88263ab3f1fbe92a..e34b4036a8a2efadd18f62c5037b75f6b59c53e0 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java +++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java @@ -76,7 +76,7 @@ public class FishingHook extends Projectile { private FishingHook(EntityType type, Level world, int luckOfTheSeaLevel, int lureLevel) { super(type, world); - this.syncronizedRandom = new Random(); + this.syncronizedRandom = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack this.openWater = true; this.currentState = FishingHook.FishHookState.FLYING; this.noCulling = true; diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java index 7131226de05bc57830f7a68ba545ebfd19d33a59..9c14b6049f3b8109c42d3c8825c87ae43f981938 100644 --- a/src/main/java/net/minecraft/world/entity/raid/Raid.java +++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java @@ -110,7 +110,7 @@ public class Raid { public Raid(int id, ServerLevel world, BlockPos pos) { this.raidEvent = new ServerBossEvent(Raid.RAID_NAME_COMPONENT, BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.NOTCHED_10); - this.random = new Random(); + this.random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack this.waveSpawnPos = Optional.empty(); this.id = id; this.level = world; @@ -124,7 +124,7 @@ public class Raid { public Raid(ServerLevel world, CompoundTag nbt) { this.raidEvent = new ServerBossEvent(Raid.RAID_NAME_COMPONENT, BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.NOTCHED_10); - this.random = new Random(); + this.random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack this.waveSpawnPos = Optional.empty(); this.level = world; this.id = nbt.getInt("Id"); diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java index d75f14e23d94deee2b6af20c8af3bcd42c1fbbc3..7c21d59bb9052d2e2c690f31a24277066c20f9b7 100644 --- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java +++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java @@ -68,7 +68,7 @@ public class EnchantmentMenu extends AbstractContainerMenu { } // CraftBukkit end }; - this.random = new Random(); + this.random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack this.enchantmentSeed = DataSlot.standalone(); this.costs = new int[3]; this.enchantClue = new int[]{-1, -1, -1}; diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java index 03726227fdd60e9cf77213d50184abff438e01ef..8220cb49c2d4d46120615b298ce36d10b29dba6d 100644 --- a/src/main/java/net/minecraft/world/level/BaseSpawner.java +++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java @@ -41,7 +41,7 @@ public abstract class BaseSpawner { public int maxNearbyEntities = 6; public int requiredPlayerRange = 16; public int spawnRange = 4; - private final Random random = new Random(); + private final Random random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack private int tickDelay = 0; // Paper public BaseSpawner() {} diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java index 97f99a06b8954b08af9f4156abe8abdad359349a..e0e27004d67fd759903645cff8a491e5516aeea8 100644 --- a/src/main/java/net/minecraft/world/level/Explosion.java +++ b/src/main/java/net/minecraft/world/level/Explosion.java @@ -89,7 +89,7 @@ public class Explosion { } public Explosion(Level world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Explosion.BlockInteraction destructionType) { - this.random = new Random(); + this.random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack this.toBlow = Lists.newArrayList(); this.hitPlayers = Maps.newHashMap(); this.level = world; diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 96c6ef03a64e425472c64884c91ac4951950362b..1b6fc6511c32e6509f773d5259e7a07c3b8e79bf 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -123,13 +123,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public final Thread thread; private final boolean isDebug; private int skyDarken; - protected int randValue = (new Random()).nextInt(); + protected int randValue = (new wtf.etil.mirai.server.util.XoRoShiRoRandom()).nextInt(); // JettPack protected final int addend = 1013904223; protected float oRainLevel; public float rainLevel; protected float oThunderLevel; public float thunderLevel; - public final Random random = new Random(); + public final Random random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack private final DimensionType dimensionType; public final WritableLevelData levelData; private final Supplier profiler; diff --git a/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java index f74c5bb8e1ba42c77c59d481b871fd992483b128..5552b6ff8f673fb6846c730fed060ea5abf51867 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java @@ -21,7 +21,7 @@ import org.bukkit.entity.HumanEntity; public class DispenserBlockEntity extends RandomizableContainerBlockEntity { - private static final Random RANDOM = new Random(); + private static final Random RANDOM = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack public static final int CONTAINER_SIZE = 9; private NonNullList items; diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootContext.java b/src/main/java/net/minecraft/world/level/storage/loot/LootContext.java index d33af84300db18ea2b71dba2c9ed43390a293500..e60d244c44396ec09ecff889d8b9543b7224ce1b 100644 --- a/src/main/java/net/minecraft/world/level/storage/loot/LootContext.java +++ b/src/main/java/net/minecraft/world/level/storage/loot/LootContext.java @@ -201,7 +201,7 @@ public class LootContext { } else { Random random = this.random; if (random == null) { - random = new Random(); + random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack } MinecraftServer minecraftServer = this.level.getServer(); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index c28f7074a07051ea9aee5dc67dfef9193426a42d..7ca746e36a98e0b7d7e47c68962975242c4dd070 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -229,7 +229,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { } // Paper end - private static final Random rand = new Random(); + private static final Random rand = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack public CraftWorld(ServerLevel world, ChunkGenerator gen, BiomeProvider biomeProvider, Environment env) { this.world = world; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java index be86114eac3975b82ca74d4d6ed3f0402a642e8a..9120c11c2c37252c41835536d581d51f8e9f9ef7 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java @@ -13,7 +13,7 @@ import org.bukkit.inventory.meta.FireworkMeta; public class CraftFirework extends CraftProjectile implements Firework { - private final Random random = new Random(); + private final Random random = new wtf.etil.mirai.server.util.XoRoShiRoRandom(); // JettPack private final CraftItemStack item; public CraftFirework(CraftServer server, FireworkRocketEntity entity) { diff --git a/src/main/java/wtf/etil/mirai/server/util/SplitMixRandom.java b/src/main/java/wtf/etil/mirai/server/util/SplitMixRandom.java new file mode 100644 index 0000000000000000000000000000000000000000..57fe47e8d93e61c457f888559bbc7e840e0461ca --- /dev/null +++ b/src/main/java/wtf/etil/mirai/server/util/SplitMixRandom.java @@ -0,0 +1,38 @@ +package wtf.etil.mirai.server.util; + +import it.unimi.dsi.fastutil.HashCommon; + +/* +Note, this implementation was taken from sodium under the LGPLv3 License: https://github.com/CaffeineMC/sodium-fabric/blob/6390562feee9537461a7822b43d2f87691378e55/src/main/java/me/jellysquid/mods/sodium/client/util/rand/XoRoShiRoRandom.java +SplitMixRandom implementation from DSI Utilities, adopted in a minimal implementation to not import Apache Commons. + +http://xoshiro.di.unimi.it/ +*/ +public class SplitMixRandom { + private static final long PHI = 0x9E3779B97F4A7C15L; + + private long x; + + public SplitMixRandom(final long seed) { + this.setSeed(seed); + } + + private static long staffordMix13(long z) { + z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L; + z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL; + + return z ^ (z >>> 31); + } + + public long nextLong() { + return staffordMix13(this.x += PHI); + } + + public void setSeed(final long seed) { + this.x = HashCommon.murmurHash3(seed); + } + + public void setState(final long state) { + this.x = state; + } +} \ No newline at end of file diff --git a/src/main/java/wtf/etil/mirai/server/util/XoRoShiRoRandom.java b/src/main/java/wtf/etil/mirai/server/util/XoRoShiRoRandom.java new file mode 100644 index 0000000000000000000000000000000000000000..c880f054d784e5e20ee656c81b1c4e55cb9e76d2 --- /dev/null +++ b/src/main/java/wtf/etil/mirai/server/util/XoRoShiRoRandom.java @@ -0,0 +1,154 @@ +package wtf.etil.mirai.server.util; + +import java.util.Random; + +/* +Note, this implementation was taken from sodium under the LGPLv3 License: https://github.com/CaffeineMC/sodium-fabric/blob/6390562feee9537461a7822b43d2f87691378e55/src/main/java/me/jellysquid/mods/sodium/client/util/rand/XoRoShiRoRandom.java + +XoRoShiRo128** implementation from DSI Utilities, adopted in a minimal implementation to not import Apache Commons. + +http://xoshiro.di.unimi.it/ +*/ +public class XoRoShiRoRandom extends Random { + private static final long serialVersionUID = 1L; + + private SplitMixRandom mixer; + private long seed = Long.MIN_VALUE; + private long p0, p1; // The initialization words for the current seed + private long s0, s1; // The current random words + private boolean hasSavedState; // True if we can be quickly reseed by using resetting the words + + private static final SplitMixRandom seedUniquifier = new SplitMixRandom(System.nanoTime()); + + public static long randomSeed() { + final long x; + + synchronized (XoRoShiRoRandom.seedUniquifier) { + x = XoRoShiRoRandom.seedUniquifier.nextLong(); + } + + return x ^ System.nanoTime(); + } + + public XoRoShiRoRandom() { + this(XoRoShiRoRandom.randomSeed()); + } + + public XoRoShiRoRandom(final long seed) { + this.setSeed(seed); + } + + @Override + public long nextLong() { + final long s0 = this.s0; + + long s1 = this.s1; + + final long result = s0 + s1; + + s1 ^= s0; + + this.s0 = Long.rotateLeft(s0, 24) ^ s1 ^ s1 << 16; + this.s1 = Long.rotateLeft(s1, 37); + + return result; + } + + @Override + public int nextInt() { + return (int) this.nextLong(); + } + + @Override + public int nextInt(final int n) { + return (int) this.nextLong(n); + } + + @Override + public long nextLong(final long n) { + if (n <= 0) { + throw new IllegalArgumentException("illegal bound " + n + " (must be positive)"); + } + + long t = this.nextLong(); + + final long nMinus1 = n - 1; + + // Shortcut for powers of two--high bits + if ((n & nMinus1) == 0) { + return (t >>> Long.numberOfLeadingZeros(nMinus1)) & nMinus1; + } + + // Rejection-based algorithm to get uniform integers in the general case + long u = t >>> 1; + + while (u + nMinus1 - (t = u % n) < 0) { + u = this.nextLong() >>> 1; + } + + return t; + + } + + @Override + public double nextDouble() { + return Double.longBitsToDouble(0x3FFL << 52 | this.nextLong() >>> 12) - 1.0; + } + + @Override + public float nextFloat() { + return (this.nextLong() >>> 40) * 0x1.0p-24f; + } + + @Override + public boolean nextBoolean() { + return this.nextLong() < 0; + } + + @Override + public void nextBytes(final byte[] bytes) { + int i = bytes.length, n; + + while (i != 0) { + n = Math.min(i, 8); + + for (long bits = this.nextLong(); n-- != 0; bits >>= 8) { + bytes[--i] = (byte) bits; + } + } + } + + @Override + public void setSeed(final long seed) { + // Restore the previous initial state if the seed hasn't changed + // Setting and mixing the seed is expensive, so this saves some CPU cycles + if (this.hasSavedState && this.seed == seed) { + this.s0 = this.p0; + this.s1 = this.p1; + } else { + SplitMixRandom mixer = this.mixer; + + // Avoid allocations of SplitMixRandom + if (mixer == null) { + mixer = this.mixer = new SplitMixRandom(seed); + } else { + mixer.setSeed(seed); + } + + this.s0 = mixer.nextLong(); + this.s1 = mixer.nextLong(); + + this.p0 = this.s0; + this.p1 = this.s1; + + this.seed = seed; + this.hasSavedState = true; + } + } + + public XoRoShiRoRandom setSeedAndReturn(final long seed) { + this.setSeed(seed); + + return this; + } +} \ No newline at end of file