// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT // Based on: // https://github.com/UnknownShadow200/ClassicalSharp/wiki/Minecraft-Classic-map-generation-algorithm // Thanks to Jerralish for originally reverse engineering classic's algorithm, then preparing a high level overview of the algorithm. // I believe this process adheres to clean room reverse engineering. using System; using System.Collections.Generic; namespace ClassicalSharp.Generator { public sealed partial class NotchyGenerator { void FillOblateSpheroid( int x, int y, int z, float radius, byte block ) { int xStart = Utils.Floor( Math.Max( x - radius, 0 ) ); int xEnd = Utils.Floor( Math.Min( x + radius, width - 1 ) ); int yStart = Utils.Floor( Math.Max( y - radius, 0 ) ); int yEnd = Utils.Floor( Math.Min( y + radius, height - 1 ) ); int zStart = Utils.Floor( Math.Max( z - radius, 0 ) ); int zEnd = Utils.Floor( Math.Min( z + radius, length - 1 ) ); float radiusSq = radius * radius; for( int yy = yStart; yy <= yEnd; yy++ ) for( int zz = zStart; zz <= zEnd; zz++ ) for( int xx = xStart; xx <= xEnd; xx++ ) { int dx = xx - x, dy = yy - y, dz = zz - z; if( (dx * dx + 2 * dy * dy + dz * dz) < radiusSq ) { int index = (yy * length + zz) * width + xx; if( blocks[index] == Block.Stone ) blocks[index] = block; } } } void FloodFill( int startIndex, byte block ) { FastIntStack stack = new FastIntStack( 4 ); stack.Push( startIndex ); while( stack.Size > 0 ) { int index = stack.Pop(); if( blocks[index] != 0 ) continue; blocks[index] = block; int x = index % width; int y = index / oneY; int z = (index / width) % length; if( x > 0 ) stack.Push( index - 1 ); if( x < width - 1 ) stack.Push( index + 1 ); if( z > 0 ) stack.Push( index - width ); if( z < length - 1 ) stack.Push( index + width ); if( y > 0 ) stack.Push( index - oneY ); } } sealed class FastIntStack { public int[] Values; public int Size; public FastIntStack( int capacity ) { Values = new int[capacity]; Size = 0; } public int Pop() { return Values[--Size]; } public void Push( int item ) { if( Size == Values.Length ) { int[] array = new int[Values.Length * 2]; Buffer.BlockCopy( Values, 0, array, 0, Size * sizeof(int) ); Values = array; } Values[Size++] = item; } } } // 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 min, int max ) { return min + Next( max - min ); } 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)); } } }