472 lines
18 KiB
Diff
472 lines
18 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: AlphaKR93 <dev@alpha93.kr>
|
|
Date: Sat, 25 Mar 2023 21:50:25 +0900
|
|
Subject: [PATCH] Apply faster random
|
|
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
|
|
index 5408cbc21fc7577a6100b5a1ca0463e899d2df8b..4f264e098e7907c397f09ee23a579ed7da494edc 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
|
|
@@ -16,7 +16,7 @@ import java.util.UUID;
|
|
|
|
public class PaperLootableInventoryData {
|
|
|
|
- private static final Random RANDOM = new Random();
|
|
+ private static final Random RANDOM = Boolean.getBoolean("Plazma.doNotUseFasterRandom") ? new Random() : new org.plazmamc.plazma.Random(); // Plazma
|
|
|
|
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 0acbaa18a61d1cfdb894c6c756d2b9bdc3599b82..93ff3ef401d4212cede5290990528988c7ca3a0c 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -691,7 +691,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
ChunkPos chunkcoordintpair = new ChunkPos(chunkproviderserver.randomState().sampler().findSpawnPosition());
|
|
// CraftBukkit start
|
|
if (world.generator != null) {
|
|
- Random rand = new Random(world.getSeed());
|
|
+ Random rand = Boolean.getBoolean("Plazma.doNotUseFasterRandom") ? new Random() : new org.plazmamc.plazma.Random(); rand.setSeed(world.getSeed()); // Plazma
|
|
org.bukkit.Location spawn = world.generator.getFixedSpawnLocation(world.getWorld(), rand);
|
|
|
|
if (spawn != null) {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
index 1392e483c363e25d1f16465d876cb7d7c70afa68..f4b99ffec5c84a5fa1f90060ec15d09b08239d49 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 = Boolean.getBoolean("Plazma.doNotUseFasterRandom") ? new Random() : new org.plazmamc.plazma.Random(); // Plazma
|
|
|
|
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 68c5af9b67a2834ee6e2f80ceefa19c3a982b8ed..7cd8a12ad560626ad3965bd46a5a71168ce6bf80 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java
|
|
@@ -14,7 +14,7 @@ import org.bukkit.inventory.meta.FireworkMeta;
|
|
|
|
public class CraftFirework extends CraftProjectile implements Firework {
|
|
|
|
- private final Random random = new Random();
|
|
+ private final Random random = Boolean.getBoolean("Plazma.doNotUseFasterRandom") ? new Random() : new org.plazmamc.plazma.Random(); // Plazma
|
|
//private CraftItemStack item; // Paper - Remove usage, not accurate representation of current item.
|
|
|
|
public CraftFirework(CraftServer server, FireworkRocketEntity entity) {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
|
|
index c3972ba41ad61af4c423e6f942ac984dc61716f0..f7b53cf1161e53d49ec2b72fed2473c1814159cd 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
|
|
@@ -48,7 +48,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
|
|
private final net.minecraft.world.level.chunk.ChunkGenerator delegate;
|
|
private final ChunkGenerator generator;
|
|
private final ServerLevel world;
|
|
- private final Random random = new Random();
|
|
+ private final Random random = Boolean.getBoolean("Plazma.doNotUseFasterRandom") ? new Random() : new org.plazmamc.plazma.Random(); // Plazma
|
|
private boolean newApi;
|
|
private boolean implementBaseHeight = true;
|
|
|
|
diff --git a/src/main/java/org/plazmamc/plazma/Random.java b/src/main/java/org/plazmamc/plazma/Random.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..e72e96be3938bdcc1ae1aa94f7465f644e1b3e16
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/plazmamc/plazma/Random.java
|
|
@@ -0,0 +1,394 @@
|
|
+package org.plazmamc.plazma;
|
|
+
|
|
+/**
|
|
+ + This is a faster implementation of java.util.Random
|
|
+ + Code from <a href="https://gist.github.com/Xyene/4637619">...</a> by Xyene
|
|
+ + Licensed unser GNU LGPL v3.0
|
|
+ + <p>
|
|
+ * A random number generator based on the simple and fast xor-shift pseudo
|
|
+ * random number generator (RNG) specified in:
|
|
+ * Marsaglia, George. (2003). Xorshift RNGs.
|
|
+ * <a href="http://www.jstatsoft.org/v08/i14/xorshift.pdf">...</a>
|
|
+ * Translated from:
|
|
+ * <a href="http://www.codeproject.com/Articles/9187/A-fast-equivalent-for-System-Random">...</a>.
|
|
+ */
|
|
+@SuppressWarnings("SuspiciousNameCombination")
|
|
+public class Random extends java.util.Random {
|
|
+ final double REAL_UNIT_INT = 1.0 / (0x7FFFFFFFL);
|
|
+ final double REAL_UNIT_UINT = 1.0 / (0xFFFFFFFFL);
|
|
+ final long Y = 842502087L, Z = 3579807591L, W = 273326509L;
|
|
+ long x, y, z, w;
|
|
+
|
|
+ public Random() {
|
|
+ seed((int) System.currentTimeMillis());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setSeed(long seed) {
|
|
+ seed((int) seed);
|
|
+ }
|
|
+
|
|
+ public void seed(int seed) {
|
|
+ // The only stipulation stated for the xorshift RNG is that at least one of
|
|
+ // the seeds x,y,z,w is non-zero. We fulfill that requirement by only allowing
|
|
+ // resetting of the x seed
|
|
+ x = seed;
|
|
+ y = Y;
|
|
+ z = Z;
|
|
+ w = W;
|
|
+ }
|
|
+
|
|
+ long boolBuffer;
|
|
+ int boolBufferBits = 0;
|
|
+
|
|
+ @Override
|
|
+ public boolean nextBoolean() {
|
|
+ if (boolBufferBits == 0) {
|
|
+ boolBuffer = nextUInt();
|
|
+ boolBufferBits = 32;
|
|
+ }
|
|
+ boolBuffer >>= 1;
|
|
+ boolean bit = (boolBuffer & 1) == 0;
|
|
+ --boolBufferBits;
|
|
+ return bit;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void nextBytes(byte[] buffer) {
|
|
+ // Fill up the bulk of the buffer in chunks of 4 bytes at a time.
|
|
+ long x = this.x, y = this.y, z = this.z, w = this.w;
|
|
+ int i = 0;
|
|
+ long t;
|
|
+ for (int bound = buffer.length - 3; i < bound; ) {
|
|
+ // Generate 4 bytes.
|
|
+ // Increased performance is achieved by generating 4 random bytes per loop.
|
|
+ // Also note that no mask needs to be applied to zero out the higher order bytes before
|
|
+ // casting because the cast ignores thos bytes. Thanks to Stefan Trosch黷z for pointing this out.
|
|
+ t = (x ^ (x << 11));
|
|
+ x = y;
|
|
+ y = z;
|
|
+ z = w;
|
|
+ w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
|
|
+
|
|
+ buffer[i++] = (byte) w;
|
|
+ buffer[i++] = (byte) (w >> 8);
|
|
+ buffer[i++] = (byte) (w >> 16);
|
|
+ buffer[i++] = (byte) (w >> 24);
|
|
+ }
|
|
+
|
|
+ // Fill up any remaining bytes in the buffer.
|
|
+ if (i < buffer.length) {
|
|
+ // Generate 4 bytes.
|
|
+ t = (x ^ (x << 11));
|
|
+ x = y;
|
|
+ y = z;
|
|
+ z = w;
|
|
+ w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
|
|
+
|
|
+ buffer[i++] = (byte) w;
|
|
+ if (i < buffer.length) {
|
|
+ buffer[i++] = (byte) (w >> 8);
|
|
+ if (i < buffer.length) {
|
|
+ buffer[i++] = (byte) (w >> 16);
|
|
+ if (i < buffer.length) {
|
|
+ buffer[i] = (byte) (w >> 24);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ this.x = x;
|
|
+ this.y = y;
|
|
+ this.z = z;
|
|
+ this.w = w;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public double nextDouble() {
|
|
+ long t = (x ^ (x << 11));
|
|
+ x = y;
|
|
+ y = z;
|
|
+ z = w;
|
|
+
|
|
+ // Here we can gain a 2x speed improvement by generating a value that can be cast to
|
|
+ // an int instead of the more easily available uint. If we then explicitly cast to an
|
|
+ // int the compiler will then cast the int to a double to perform the multiplication,
|
|
+ // this final cast is a lot faster than casting from a uint to a double. The extra cast
|
|
+ // to an int is very fast (the allocated bits remain the same) and so the overall effect
|
|
+ // of the extra cast is a significant performance improvement.
|
|
+ //
|
|
+ // Also note that the loss of one bit of precision is equivalent to what occurs within
|
|
+ // System.Random.
|
|
+ return (REAL_UNIT_INT * (int) (0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)))));
|
|
+ }
|
|
+
|
|
+ public double random() {
|
|
+ return nextDouble();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float nextFloat() {
|
|
+ return (float) nextDouble();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int nextInt() {
|
|
+ long t = (x ^ (x << 11));
|
|
+ x = y;
|
|
+ y = z;
|
|
+ z = w;
|
|
+ return (int) (0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int nextInt(int upperBound) {
|
|
+ if (upperBound < 0)
|
|
+ throw new IllegalArgumentException("upperBound must be >=0");
|
|
+
|
|
+ long t = (x ^ (x << 11));
|
|
+ x = y;
|
|
+ y = z;
|
|
+ z = w;
|
|
+
|
|
+ return (int) ((REAL_UNIT_INT * (int) (0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))))) * upperBound);
|
|
+ }
|
|
+
|
|
+ public int nextInt(int lowerBound, int upperBound) {
|
|
+ if (lowerBound > upperBound)
|
|
+ throw new IllegalArgumentException("upperBound must be >=lowerBound");
|
|
+
|
|
+ long t = (x ^ (x << 11));
|
|
+ x = y;
|
|
+ y = z;
|
|
+ z = w;
|
|
+
|
|
+ // The explicit int cast before the first multiplication gives better performance.
|
|
+ // See comments in NextDouble.
|
|
+ int range = upperBound - lowerBound;
|
|
+ if (range < 0) {
|
|
+ // If range is <0 then an overflow has occured and must resort to using long integer arithmetic instead (slower).
|
|
+ // We also must use all 32 bits of precision, instead of the normal 31, which again is slower.
|
|
+ return lowerBound + (int) ((REAL_UNIT_UINT * (double) (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)))) * (double) ((long) upperBound - (long) lowerBound));
|
|
+ }
|
|
+ // 31 bits of precision will suffice if range<=int.MaxValue. This allows us to cast to an int and gain
|
|
+ // a little more performance.
|
|
+ return lowerBound + (int) ((REAL_UNIT_INT * (double) (int) (0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))))) * (double) range);
|
|
+ }
|
|
+
|
|
+ public long nextUInt() {
|
|
+ long t = (x ^ (x << 11));
|
|
+ x = y;
|
|
+ y = z;
|
|
+ z = w;
|
|
+ return (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))) & (0xFFFFFFFFL);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long nextLong() {
|
|
+ return nextUInt() << 32 + nextUInt();
|
|
+ }
|
|
+
|
|
+ double gaussNext;
|
|
+ boolean hasGaussNext;
|
|
+ final double TWOPI = Math.PI * 2;
|
|
+
|
|
+ /**
|
|
+ * Get a random number in the range [min, max) or [min, max] depending on rounding.
|
|
+ *
|
|
+ * @param min Low bound
|
|
+ * @param max High bound
|
|
+ * @return A uniformly distributed double
|
|
+ */
|
|
+ public double uniform(double min, double max) {
|
|
+ return min + (max - min) * nextDouble();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Triangular distribution.
|
|
+ * <p/>
|
|
+ * Continuous distribution bounded by given lower and upper limits,
|
|
+ * and having a given mode value in-between.
|
|
+ * http://en.wikipedia.org/wiki/Triangular_distribution
|
|
+ *
|
|
+ * @param low Low bound
|
|
+ * @param high High bound
|
|
+ * @param mode Mode
|
|
+ * @return A number from the triangular distribution specified
|
|
+ */
|
|
+ public double triangular(int low, int high, int mode) {
|
|
+ double u = nextDouble();
|
|
+ double c = (mode - low) / (high - low);
|
|
+ if (u > c) {
|
|
+ u = 1.0 - u;
|
|
+ c = 1.0 - c;
|
|
+ int k = low;
|
|
+ low = high;
|
|
+ high = k;
|
|
+ }
|
|
+ return low + (high - low) * Math.sqrt(u * c);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gaussian distribution, mean is 0 and standard deviation is 1.
|
|
+ * <p/>
|
|
+ * mu is the mean, and sigma is the standard deviation.
|
|
+ *
|
|
+ * @return A double in Gaussian distribution
|
|
+ */
|
|
+ public double gauss() {
|
|
+ return nextGaussian();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gaussian distribution, with user-specified mean and standard deviation.
|
|
+ * <p/>
|
|
+ * mu is the mean, and sigma is the standard deviation.
|
|
+ *
|
|
+ * @return A double in Gaussian distribution
|
|
+ */
|
|
+ public double gauss(double mu, double sigma) {
|
|
+ return mu + sigma * nextGaussian();
|
|
+ }
|
|
+
|
|
+ public double gaussUnsigned(double mu, double sigma) {
|
|
+ double out = gauss(mu, sigma);
|
|
+ return out > 1 ? out : 1;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Log normal distribution.
|
|
+ * <p/>
|
|
+ * If you take the natural logarithm of this distribution, you'll get a
|
|
+ * normal distribution with mean mu and standard deviation sigma.
|
|
+ * mu can have any value, and sigma must be greater than zero.
|
|
+ *
|
|
+ * @param mu Mean
|
|
+ * @param sigma Standard deviation
|
|
+ * @return A number from the log normal distribution specified
|
|
+ */
|
|
+ public double logNormal(double mu, double sigma) {
|
|
+ return Math.exp(gauss(mu, sigma));
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Exponential distribution.
|
|
+ * <p/>
|
|
+ * lambda is 1.0 divided by the desired mean. It should be
|
|
+ * nonzero. Returned values range from 0 to positive infinity
|
|
+ * if lambda is positive, and from negative infinity to 0
|
|
+ * if lambda is negative.
|
|
+ *
|
|
+ * @param lambda A non-zero value
|
|
+ */
|
|
+ public double exponential(double lambda) {
|
|
+ return -Math.log(1.0 - random()) / lambda;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Circular data distribution.
|
|
+ * <p/>
|
|
+ * If kappa is equal to zero, this distribution reduces
|
|
+ * to a uniform random angle over the range 0 to 2*pi.
|
|
+ *
|
|
+ * @param mu the mean angle, expressed in radians between 0 and 2*pi.
|
|
+ * @param kappa the concentration parameter, which must be greater than or
|
|
+ * equal to zero.
|
|
+ * @return A number from the circular data distribution specified
|
|
+ */
|
|
+ public double circularData(double mu, double kappa) {
|
|
+ if (kappa <= 1e-6)
|
|
+ return TWOPI * nextDouble();
|
|
+
|
|
+ double a = 1.0 + Math.sqrt(1.0 + 4.0 * kappa * kappa);
|
|
+ double b = (a - Math.sqrt(2.0 * a)) / (2.0 * kappa);
|
|
+ double r = (1.0 + b * b) / (2.0 * b);
|
|
+ double u1, u2, u3, f, c, z, theta = 0;
|
|
+
|
|
+ while (true) {
|
|
+ u1 = nextDouble();
|
|
+
|
|
+ z = Math.cos(Math.PI * u1);
|
|
+ f = (1.0 + r * z) / (r + z);
|
|
+ c = kappa * (r - f);
|
|
+
|
|
+ u2 = nextDouble();
|
|
+
|
|
+ if (u2 < c * (2.0 - c) || u2 <= c * Math.exp(1.0 - c))
|
|
+ break;
|
|
+
|
|
+ u3 = nextDouble();
|
|
+ if (u3 > 0.5)
|
|
+ theta = (mu % TWOPI) + Math.acos(f);
|
|
+ else
|
|
+ theta = (mu % TWOPI) - Math.acos(f);
|
|
+ }
|
|
+ return theta;
|
|
+ }
|
|
+
|
|
+
|
|
+ final double LOG4 = Math.log(4);
|
|
+ final double SG_MAGICCONST = 1.0 + Math.log(4.5);
|
|
+
|
|
+ /**
|
|
+ * Gamma distribution. Not the gamma function!
|
|
+ * Conditions on the parameters are alpha > 0 and beta > 0.
|
|
+ * <p/>
|
|
+ * The probability distribution function is:
|
|
+ * pdf(x) = (x ** (alpha - 1) * math.exp(-x / beta)) / (math.gamma(alpha) * beta ** alpha)
|
|
+ *
|
|
+ * @param alpha Alpha
|
|
+ * @param beta Beta
|
|
+ * @return A number from the gamma distribution specified
|
|
+ */
|
|
+ public double gamma(double alpha, double beta) {
|
|
+ if (alpha <= 0.0 || beta <= 0.0)
|
|
+ throw new IllegalArgumentException("alpha and beta must be > 0.0");
|
|
+
|
|
+ if (alpha > 1.0) {
|
|
+ double ainv = Math.sqrt(2.0 * alpha - 1.0);
|
|
+ double bbb = alpha - LOG4;
|
|
+ double ccc = alpha + ainv;
|
|
+ double u1, u2, v, x, z, r;
|
|
+
|
|
+ while (true) {
|
|
+ u1 = random();
|
|
+ if (!(1e-7 < u1 && u1 < .9999999))
|
|
+ continue;
|
|
+ u2 = 1.0 - random();
|
|
+ v = Math.log(u1 / (1.0 - u1)) / ainv;
|
|
+ x = alpha * Math.exp(v);
|
|
+ z = u1 * u1 * u2;
|
|
+ r = bbb + ccc * v - x;
|
|
+ if (r + SG_MAGICCONST - 4.5 * z >= 0.0 || r >= Math.log(z))
|
|
+ return x * beta;
|
|
+ }
|
|
+ } else if (alpha == 1.0) {
|
|
+ // exponential(1)
|
|
+ double u;
|
|
+ u = random();
|
|
+ while (u <= 1e-7)
|
|
+ u = random();
|
|
+ return -Math.log(u) * beta;
|
|
+ } else {
|
|
+ // alpha is between 0 and 1 (exclusive)
|
|
+ // Uses ALGORITHM GS of Statistical Computing -Kennedy & Gentle
|
|
+
|
|
+ double u, b, p, x, u1;
|
|
+ while (true) {
|
|
+ u = random();
|
|
+ b = (Math.E + alpha) / Math.E;
|
|
+ p = b * u;
|
|
+ if (p <= 1.0)
|
|
+ x = Math.pow(p, (1.0 / alpha));
|
|
+ else
|
|
+ x = -Math.log((b - p) / alpha);
|
|
+ u1 = random();
|
|
+ if (p > 1.0) {
|
|
+ if (u1 <= Math.pow(x, (alpha - 1.0)))
|
|
+ break;
|
|
+ } else if (u1 <= Math.exp(-x))
|
|
+ break;
|
|
+ }
|
|
+ return x * beta;
|
|
+ }
|
|
+ }
|
|
+}
|