From 0ef0eb3c32349d25ec3165e66f7bd5b416fb3dfe Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 31 May 2016 19:18:21 +1000 Subject: [PATCH] Use the same random number generation algorithm as java. --- ClassicalSharp/Generator/Noise.cs | 6 +-- .../Generator/NotchyGenerator.Utils.cs | 37 +++++++++++++++- ClassicalSharp/Generator/NotchyGenerator.cs | 42 +++++++++---------- 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/ClassicalSharp/Generator/Noise.cs b/ClassicalSharp/Generator/Noise.cs index cbc9a9dfa..5d8852cd9 100644 --- a/ClassicalSharp/Generator/Noise.cs +++ b/ClassicalSharp/Generator/Noise.cs @@ -14,13 +14,13 @@ namespace ClassicalSharp.Generator { public sealed class ImprovedNoise : Noise { - public ImprovedNoise( Random rnd ) { + public ImprovedNoise( JavaRandom rnd ) { // shuffle randomly using fisher-yates for( int i = 0; i < 256; i++ ) p[i] = (byte)i; for( int i = 0; i < 256; i++ ) { - int j = rnd.Next( i, 256 ); + int j = (rnd.Next( 256 - i ) + i); // [i, 256) byte temp = p[i]; p[i] = p[j]; p[j] = temp; } for( int i = 0; i < 256; i++ ) @@ -59,7 +59,7 @@ namespace ClassicalSharp.Generator { public sealed class OctaveNoise : Noise { readonly ImprovedNoise[] baseNoise; - public OctaveNoise( int octaves, Random rnd ) { + public OctaveNoise( int octaves, JavaRandom rnd ) { baseNoise = new ImprovedNoise[octaves]; for( int i = 0; i < octaves; i++ ) baseNoise[i] = new ImprovedNoise( rnd ); diff --git a/ClassicalSharp/Generator/NotchyGenerator.Utils.cs b/ClassicalSharp/Generator/NotchyGenerator.Utils.cs index f8c1c2869..018f29e83 100644 --- a/ClassicalSharp/Generator/NotchyGenerator.Utils.cs +++ b/ClassicalSharp/Generator/NotchyGenerator.Utils.cs @@ -52,7 +52,7 @@ namespace ClassicalSharp.Generator { } } - sealed class FastIntStack { + sealed class FastIntStack { public int[] Values; public int Size; @@ -75,4 +75,39 @@ namespace ClassicalSharp.Generator { } } } + + // Based on https://docs.oracle.com/javase/7/docs/api/java/util/Random.html + public sealed class JavaRandom { + + long seed; + const long value = 0x5DEECE66DL; + const long mask = (1L << 48) - 1; + + public JavaRandom( int seed ) { + this.seed = (seed ^ value) & mask; + } + + int Raw( int bits ) { + seed = (seed * value + 0xBL) & mask; + return (int)((ulong)seed >> (48 - bits)); + } + + public int Next() { return Raw( 32 ); } + + public int Next( int n ) { + if( (n & -n) == n ) // i.e., n is a power of 2 + return (int)((n * (long)Raw( 31 )) >> 31); + + int bits, val; + do { + bits = Raw( 31 ); + val = bits % n; + } while( bits - val + (n - 1) < 0 ); + return val; + } + + public float NextFloat() { + return Raw( 24 ) / ((float)(1 << 24)); + } + } } \ No newline at end of file diff --git a/ClassicalSharp/Generator/NotchyGenerator.cs b/ClassicalSharp/Generator/NotchyGenerator.cs index c55ed13ad..c123434e9 100644 --- a/ClassicalSharp/Generator/NotchyGenerator.cs +++ b/ClassicalSharp/Generator/NotchyGenerator.cs @@ -14,7 +14,7 @@ namespace ClassicalSharp.Generator { int waterLevel, oneY; byte[] blocks; short[] heightmap; - Random rnd; + JavaRandom rnd; public override string GeneratorName { get { return "Vanilla classic"; } } @@ -25,7 +25,7 @@ namespace ClassicalSharp.Generator { oneY = width * length; waterLevel = height / 2; blocks = new byte[width * height * length]; - rnd = new Random( seed ); + rnd = new JavaRandom( seed ); CreateHeightmap(); CreateStrata(); @@ -108,10 +108,10 @@ namespace ClassicalSharp.Generator { double caveY = rnd.Next( height ); double caveZ = rnd.Next( length ); - int caveLen = (int)(rnd.NextDouble() * rnd.NextDouble() * 200); - double theta = rnd.NextDouble() * 2 * Math.PI, deltaTheta = 0; - double phi = rnd.NextDouble() * 2 * Math.PI, deltaPhi = 0; - double caveRadius = rnd.NextDouble() * rnd.NextDouble(); + int caveLen = (int)(rnd.NextFloat() * rnd.NextFloat() * 200); + double theta = rnd.NextFloat() * 2 * Math.PI, deltaTheta = 0; + double phi = rnd.NextFloat() * 2 * Math.PI, deltaPhi = 0; + double caveRadius = rnd.NextFloat() * rnd.NextFloat(); for( int j = 0; j < caveLen; j++ ) { caveX += Math.Sin( theta ) * Math.Cos( phi ); @@ -119,10 +119,10 @@ namespace ClassicalSharp.Generator { caveZ += Math.Sin( phi ); theta = theta + deltaTheta * 0.2; - deltaTheta = deltaTheta * 0.9 + rnd.NextDouble() - rnd.NextDouble(); + deltaTheta = deltaTheta * 0.9 + rnd.NextFloat() - rnd.NextFloat(); phi = phi / 2 + deltaPhi / 4; - deltaPhi = deltaPhi * 0.75 + rnd.NextDouble() - rnd.NextDouble(); - if( rnd.NextDouble() < 0.25 ) continue; + deltaPhi = deltaPhi * 0.75 + rnd.NextFloat() - rnd.NextFloat(); + if( rnd.NextFloat() < 0.25 ) continue; int cenX = (int)(caveX + (rnd.Next( 4 ) - 2) * 0.2); int cenY = (int)(caveY + (rnd.Next( 4 ) - 2) * 0.2); @@ -145,9 +145,9 @@ namespace ClassicalSharp.Generator { double veinY = rnd.Next( height ); double veinZ = rnd.Next( length ); - int veinLen = (int)(rnd.NextDouble() * rnd.NextDouble() * 75 * abundance); - double theta = rnd.NextDouble() * 2 * Math.PI, deltaTheta = 0; - double phi = rnd.NextDouble() * 2 * Math.PI, deltaPhi = 0; + int veinLen = (int)(rnd.NextFloat() * rnd.NextFloat() * 75 * abundance); + double theta = rnd.NextFloat() * 2 * Math.PI, deltaTheta = 0; + double phi = rnd.NextFloat() * 2 * Math.PI, deltaPhi = 0; for( int j = 0; j < veinLen; j++ ) { veinX += Math.Sin( theta ) * Math.Cos( phi ); @@ -155,9 +155,9 @@ namespace ClassicalSharp.Generator { veinZ += Math.Sin( phi ); theta = deltaTheta * 0.2; - deltaTheta = deltaTheta * 0.9 + rnd.NextDouble() - rnd.NextDouble(); + deltaTheta = deltaTheta * 0.9 + rnd.NextFloat() - rnd.NextFloat(); phi = phi / 2 + deltaPhi / 4; - deltaPhi = deltaPhi * 0.9 + rnd.NextDouble() - rnd.NextDouble(); + deltaPhi = deltaPhi * 0.9 + rnd.NextFloat() - rnd.NextFloat(); float radius = abundance * (float)Math.Sin( j * Math.PI / veinLen ) + 1; FillOblateSpheroid( (int)veinX, (int)veinY, (int)veinZ, radius, block ); @@ -195,7 +195,7 @@ namespace ClassicalSharp.Generator { for( int i = 0; i < numSources; i++ ) { CurrentProgress = (float)i / numSources; int x = rnd.Next( width ), z = rnd.Next( length ); - int y = waterLevel - rnd.Next( 1, 3 ); + int y = waterLevel - (rnd.Next( 2 ) + 1); FloodFill( (y * length + z) * width + x, (byte)Block.Water ); } } @@ -207,7 +207,7 @@ namespace ClassicalSharp.Generator { for( int i = 0; i < numSources; i++ ) { CurrentProgress = (float)i / numSources; int x = rnd.Next( width ), z = rnd.Next( length ); - int y = (int)((waterLevel - 3) * rnd.NextDouble() * rnd.NextDouble()); + int y = (int)((waterLevel - 3) * rnd.NextFloat() * rnd.NextFloat()); FloodFill( (y * length + z) * width + x, (byte)Block.Lava ); } } @@ -244,7 +244,7 @@ namespace ClassicalSharp.Generator { for( int i = 0; i < numPatches; i++ ) { CurrentProgress = (float)i / numPatches; - byte type = (byte)((byte)Block.Dandelion + rnd.Next( 0, 2 ) ); + byte type = (byte)((byte)Block.Dandelion + rnd.Next( 2 ) ); int patchX = rnd.Next( width ), patchZ = rnd.Next( length ); for( int j = 0; j < 10; j++ ) { int flowerX = patchX, flowerZ = patchZ; @@ -269,7 +269,7 @@ namespace ClassicalSharp.Generator { for( int i = 0; i < numPatches; i++ ) { CurrentProgress = (float)i / numPatches; - byte type = (byte)((byte)Block.BrownMushroom + rnd.Next( 0, 2 ) ); + byte type = (byte)((byte)Block.BrownMushroom + rnd.Next( 2 ) ); int patchX = rnd.Next( width ); int patchY = rnd.Next( height ); int patchZ = rnd.Next( length ); @@ -307,7 +307,7 @@ namespace ClassicalSharp.Generator { treeX += rnd.Next( 6 ) - rnd.Next( 6 ); treeZ += rnd.Next( 6 ) - rnd.Next( 6 ); if( treeX < 0 || treeZ < 0 || treeX >= width || - treeZ >= length || rnd.NextDouble() >= 0.25 ) + treeZ >= length || rnd.NextFloat() >= 0.25 ) continue; int treeY = heightmap[treeZ * width + treeX] + 1; @@ -359,7 +359,7 @@ namespace ClassicalSharp.Generator { index = (y * length + z) * width + x; if( Math.Abs( xx ) == 2 && Math.Abs( zz ) == 2 ) { - if( rnd.NextDouble() >= 0.5 ) + if( rnd.NextFloat() >= 0.5 ) blocks[index] = (byte)Block.Leaves; } else { blocks[index] = (byte)Block.Leaves; @@ -377,7 +377,7 @@ namespace ClassicalSharp.Generator { if( xx == 0 || zz == 0 ) { blocks[index] = (byte)Block.Leaves; - } else if( y == bottomY && rnd.NextDouble() >= 0.5 ) { + } else if( y == bottomY && rnd.NextFloat() >= 0.5 ) { blocks[index] = (byte)Block.Leaves; } }