This commit is contained in:
Daniel Mills 2019-10-12 22:54:56 -04:00
parent da464f99d4
commit 0a7214a39b
12 changed files with 696 additions and 162 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
/target/ /target/
lib/

View File

@ -68,6 +68,10 @@
<id>spigot-repo</id> <id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository> </repository>
<repository>
<id>volmit</id>
<url>http://nexus.volmit.com/content/repositories/volmit</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
@ -98,6 +102,13 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>cb</groupId>
<artifactId>craftbukkit-1.12.2</artifactId>
<version>1</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/craftbukkit-1.12.2.jar</systemPath>
</dependency>
</dependencies> </dependencies>
<properties> <properties>
<development.location>${user.home}\Documents\development\server\plugins\${project.name}.jar</development.location> <development.location>${user.home}\Documents\development\server\plugins\${project.name}.jar</development.location>

11
pom.xml
View File

@ -76,6 +76,10 @@
<id>spigot-repo</id> <id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository> </repository>
<repository>
<id>volmit</id>
<url>http://nexus.volmit.com/content/repositories/volmit</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
@ -89,5 +93,12 @@
<version>1.12.2-R0.1-SNAPSHOT</version> <version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<artifactId>craftbukkit-1.12.2</artifactId>
<groupId>cb</groupId>
<version>1</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/craftbukkit-1.12.2.jar</systemPath>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,17 +1,33 @@
package ninja.bytecode.iris; package ninja.bytecode.iris;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import ninja.bytecode.shuriken.execution.TaskExecutor; import ninja.bytecode.shuriken.execution.TaskExecutor;
public class Iris extends JavaPlugin public class Iris extends JavaPlugin implements Listener
{ {
public static TaskExecutor executor; public static TaskExecutor executor;
public void onEnable() public void onEnable()
{ {
executor = new TaskExecutor(-1, Thread.MIN_PRIORITY, "Iris Generator"); executor = new TaskExecutor(1, Thread.MIN_PRIORITY, "Iris Generator");
getServer().getPluginManager().registerEvents((Listener) this, this);
}
public void onDisable()
{
executor.close();
} }
@Override @Override
@ -19,4 +35,23 @@ public class Iris extends JavaPlugin
{ {
return new IrisGenerator(); return new IrisGenerator();
} }
@EventHandler
public void on(PlayerCommandPreprocessEvent e)
{
if(e.getMessage().toLowerCase().equals("/iris"))
{
World ww = Bukkit.createWorld(new WorldCreator("iris-worlds/" + UUID.randomUUID().toString())
.generator(new IrisGenerator())
.seed(0));
ww.setSpawnFlags(false, false);
ww.setAutoSave(false);
ww.setKeepSpawnInMemory(false);
ww.setSpawnLocation(0, 256, 0);
e.getPlayer().teleport(new Location(ww, 0, 256, 0));
e.getPlayer().setFlying(true);
e.getPlayer().setGameMode(GameMode.CREATIVE);
e.setCancelled(true);
}
}
} }

View File

@ -5,7 +5,9 @@ import java.util.Random;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import ninja.bytecode.shuriken.math.CNG; import ninja.bytecode.iris.gen.GenLayerBase;
import ninja.bytecode.iris.gen.IGenLayer;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.math.M; import ninja.bytecode.shuriken.math.M;
import ninja.bytecode.shuriken.math.RNG; import ninja.bytecode.shuriken.math.RNG;
@ -23,149 +25,45 @@ public class IrisGenerator extends ParallelChunkGenerator
}; };
private static final MB[] rock = {new MB(Material.STONE), new MB(Material.STONE, 5), new MB(Material.COBBLESTONE), private static final MB[] rock = {new MB(Material.STONE), new MB(Material.STONE, 5), new MB(Material.COBBLESTONE),
}; };
private double[][][] scatterCache; private GList<IGenLayer> genLayers;
private CNG gen;
private CNG fracture;
private CNG basegen;
private CNG faultline;
private RNG rng;
@Override @Override
public void onInit(World world, Random random) public void onInit(World world, Random random)
{ {
//@builder RNG rng = new RNG(world.getSeed());
rng = new RNG(world.getSeed()); genLayers = new GList<>();
CNG scatter = new CNG(rng.nextRNG(), 1, 1) genLayers.add(new GenLayerBase(world, random, rng));
.scale(10); System.out.print("Gend");
basegen = new CNG(rng.nextRNG(), 0.46, 3)
.scale(0.00295)
.fractureWith(new CNG(rng.nextRNG(), 1, 2)
.scale(0.025), 70);
gen = new CNG(rng.nextRNG(), 0.19D, 4)
.scale(0.012)
.amp(0.5)
.freq(1.1)
.fractureWith(new CNG(rng.nextRNG(), 1, 2)
.scale(0.018)
.fractureWith(new CNG(rng.nextRNG(), 1, 1)
.scale(0.15), 24), 44);
fracture = new CNG(rng.nextRNG(), 0.6D, 4)
.scale(0.118);
faultline = new CNG(rng.nextRNG(), 1D, 1)
.scale(0.005)
.child(new CNG(rng.nextRNG(), 1D, 1)
.scale(0.012))
.injectWith(CNG.MULTIPLY)
.fractureWith(new CNG(rng.nextRNG(), 1, 1)
.scale(0.07), 200);
//@done
scatterCache = new double[16][][];
for(int i = 0; i < 16; i++)
{
scatterCache[i] = new double[16][];
for(int j = 0; j < 16; j++)
{
scatterCache[i][j] = new double[16];
for(int k = 0; k < 16; k++)
{
scatterCache[i][j][k] = scatter.noise(i, j, k);
}
}
}
}
@Override
public void genColumn(int wx, int wz, int x, int z)
{
int height = getHeight(wx, wz);
MB mb = rock[0];
for(int i = 0; i < Math.max(height, 63); i++)
{
int surfdepth = i < height ? height - i : 0;
double scatter = scatterCache[x][z][i % 16];
if(i == 0)
{
mb = bedrock;
}
else
{
if(scatter > 0.4 && i == 2)
{
mb = bedrock;
}
if(scatter > 0.6 && i == 1)
{
mb = bedrock;
}
if(i > height)
{
mb = water;
}
else if(i == height)
{
mb = pick(sand, scatter);
}
else if(i == height + 1 + scatter)
{
mb = pick(sandygrass, scatter);
}
else if(i == height - 1)
{
mb = grass;
}
else if(i > height - ((scatter * 2) + 1))
{
mb = pick(earth, scatter);
}
else
{
mb = pick(rock, scatter);
}
if(mb.data < 0)
{
mb = new MB(mb.material, pick(Math.abs(mb.data), scatter));
}
}
setBlock(x, i, z, mb.material, mb.data);
}
} }
public int getHeight(double dx, double dz) public int getHeight(double dx, double dz)
{ {
double fnoise = fracture.noise(dx, dz); double noise = 0.5;
double fault = faultline.noise(dx, dz);
dx += (fnoise * 12); for(IGenLayer i : genLayers)
dz -= (fnoise * 12); {
double base = basegen.noise(dx, dz); noise = i.generateLayer(noise, dx, dz);
double noise = base + gen.noise(dx, dz); }
double n = noise * 250; double n = noise * 250;
n = n > 255 ? 255 : n; n = n > 255 ? 255 : n;
n = n < 0 ? 0 : n; n = n < 0 ? 0 : n;
if(n > 75 && fault > 0.35)
{
n += (fault * (n / 19.5));
}
return (int) n; return (int) n;
} }
@Override
public void genColumn(final int wx, final int wz)
{
int height = getHeight(wx, wz);
MB mb = rock[0];
for(int i = 0; i < height; i++)
{
setBlock(wx, i, wz, mb.material, mb.data);
}
}
public int pick(int max, double noise) public int pick(int max, double noise)
{ {
return (int) (noise * max); return (int) (noise * max);

View File

@ -6,6 +6,7 @@ import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import ninja.bytecode.iris.atomics.AtomicChunkData;
import ninja.bytecode.shuriken.Shuriken; import ninja.bytecode.shuriken.Shuriken;
import ninja.bytecode.shuriken.execution.ChronoLatch; import ninja.bytecode.shuriken.execution.ChronoLatch;
import ninja.bytecode.shuriken.execution.J; import ninja.bytecode.shuriken.execution.J;
@ -18,53 +19,65 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
private int j; private int j;
private int wx; private int wx;
private int wz; private int wz;
private ChunkData data; private AtomicChunkData data;
private TaskGroup tg; private TaskGroup tg;
private boolean ready = false; private boolean ready = false;
private ChronoLatch cl = new ChronoLatch(5000); private ChronoLatch cl = new ChronoLatch(1000);
public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome) public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome)
{ {
Shuriken.profiler.start("chunkgen-" + world.getName()); Shuriken.profiler.start("chunkgen-" + world.getName());
data = new AtomicChunkData(world);
if(!ready)
try
{ {
onInit(world, random); if(!ready)
ready = true;
}
data = createChunkData(world);
tg = Iris.executor.startWork();
for(i = 0; i < 16; i++)
{
wx = (x * 16) + i;
for(j = 0; j < 16; j++)
{ {
wz = (z * 16) + j; onInit(world, random);
int a = wx; ready = true;
int b = wz; }
int c = i;
int d = j; tg = Iris.executor.startWork();
tg.queue(() -> genColumn(a, b, c, d));
for(i = 0; i < 16; i++)
{
wx = (x * 16) + i;
for(j = 0; j < 16; j++)
{
wz = (z * 16) + j;
int a = wx;
int b = wz;
tg.queue(() -> genColumn(a, b));
}
}
tg.execute();
Shuriken.profiler.stop("chunkgen-" + world.getName());
if(cl.flip())
{
J.a(() -> System.out.print("Gen: " + F.duration(Shuriken.profiler.getResult("chunkgen-" + world.getName()).getAverage(), 2)));
} }
} }
tg.execute(); catch(Throwable e)
Shuriken.profiler.stop("chunkgen-" + world.getName());
if(cl.flip())
{ {
J.a(() -> System.out.print("Gen: " + F.duration(Shuriken.profiler.getResult("chunkgen-" + world.getName()).getAverage(), 2))); for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 16; j++)
{
data.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA);
}
}
} }
return data; return data.toChunkData();
} }
public abstract void onInit(World world, Random random); public abstract void onInit(World world, Random random);
public abstract void genColumn(int wx, int wz, int x, int z); public abstract void genColumn(int wx, int wz);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
protected void setBlock(int x, int y, int z, Material b) protected void setBlock(int x, int y, int z, Material b)
@ -83,7 +96,6 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
setBlock(x, y, z, b, (byte) 0); setBlock(x, y, z, b, (byte) 0);
} }
@SuppressWarnings("deprecation")
protected void setBlock(int x, int y, int z, int b, byte d) protected void setBlock(int x, int y, int z, int b, byte d)
{ {
data.setBlock(x, y, z, b, d); data.setBlock(x, y, z, b, d);

View File

@ -0,0 +1,83 @@
package ninja.bytecode.iris.atomics;
import java.io.Serializable;
import java.lang.reflect.Field;
import sun.misc.Unsafe;
@SuppressWarnings("restriction")
public class AtomicCharArray implements Serializable
{
private static final long serialVersionUID = 2862133569453604235L;
private static final Unsafe unsafe;
private static final int base;
private static final int shift;
volatile char[] array;
public AtomicCharArray(int var1)
{
this.array = new char[var1];
}
private long checkedByteOffset(int var1)
{
if(var1 >= 0 && var1 < this.array.length)
{
return byteOffset(var1);
}
else
{
throw new IndexOutOfBoundsException("index " + var1);
}
}
public final char get(int var1)
{
return this.getRaw(this.checkedByteOffset(var1));
}
private char getRaw(long var1)
{
return unsafe.getCharVolatile(this.array, var1);
}
public final void set(int var1, char var2)
{
unsafe.putCharVolatile(this.array, this.checkedByteOffset(var1), var2);
}
private static long byteOffset(int var0)
{
return ((long) var0 << shift) + (long) base;
}
static
{
Field f;
Unsafe o = null;
try
{
f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
o = (Unsafe) f.get(null);
}
catch(Throwable e)
{
e.printStackTrace();
}
unsafe = o;
base = unsafe.arrayBaseOffset(int[].class);
int var0 = unsafe.arrayIndexScale(int[].class);
if((var0 & var0 - 1) != 0)
{
throw new Error("data type scale not a power of two");
}
else
{
shift = 31 - Integer.numberOfLeadingZeros(var0);
}
}
}

View File

@ -0,0 +1,359 @@
package ninja.bytecode.iris.atomics;
import java.lang.reflect.Field;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_12_R1.generator.CraftChunkData;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.ChunkGenerator.ChunkData;
import org.bukkit.material.MaterialData;
public final class AtomicChunkData implements ChunkGenerator.ChunkData
{
private static final Field t;
private static final int h = 0x1000;
private final int maxHeight;
private volatile char[] s0;
private volatile char[] s1;
private volatile char[] s2;
private volatile char[] s3;
private volatile char[] s4;
private volatile char[] s5;
private volatile char[] s6;
private volatile char[] s7;
private volatile char[] s8;
private volatile char[] s9;
private volatile char[] sA;
private volatile char[] sB;
private volatile char[] sC;
private volatile char[] sD;
private volatile char[] sE;
private volatile char[] sF;
private volatile char[][] m;
private World w;
public AtomicChunkData(World world)
{
this.maxHeight = world.getMaxHeight();
this.w = world;
}
@Override
public int getMaxHeight()
{
return maxHeight;
}
@SuppressWarnings("deprecation")
@Override
public void setBlock(int x, int y, int z, Material material)
{
setBlock(x, y, z, material.getId());
}
@SuppressWarnings("deprecation")
@Override
public void setBlock(int x, int y, int z, MaterialData material)
{
setBlock(x, y, z, material.getItemTypeId(), material.getData());
}
@SuppressWarnings("deprecation")
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, Material material)
{
setRegion(xMin, yMin, zMin, xMax, yMax, zMax, material.getId());
}
@SuppressWarnings("deprecation")
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, MaterialData material)
{
setRegion(xMin, yMin, zMin, xMax, yMax, zMax, material.getItemTypeId(), material.getData());
}
@SuppressWarnings("deprecation")
@Override
public Material getType(int x, int y, int z)
{
return Material.getMaterial(getTypeId(x, y, z));
}
@SuppressWarnings("deprecation")
@Override
public MaterialData getTypeAndData(int x, int y, int z)
{
return getType(x, y, z).getNewData(getData(x, y, z));
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, int blockId)
{
setRegion(xMin, yMin, zMin, xMax, yMax, zMax, blockId, (byte) 0);
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, int blockId, int data)
{
throw new UnsupportedOperationException("AtomicChunkData does not support setting regions");
}
@Override
public void setBlock(int x, int y, int z, int blockId)
{
setBlock(x, y, z, blockId, (byte) 0);
}
@Override
public void setBlock(int x, int y, int z, int blockId, byte data)
{
setBlock(x, y, z, (char) (blockId << 4 | data));
}
@Override
public int getTypeId(int x, int y, int z)
{
if(x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf))
{
return 0;
}
char[] section = getChunkSection(y, false);
if(section == null)
{
return 0;
}
else
{
return section[(y & 0xf) << 8 | z << 4 | x] >> 4;
}
}
@Override
public byte getData(int x, int y, int z)
{
if(x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf))
{
return (byte) 0;
}
char[] section = getChunkSection(y, false);
if(section == null)
{
return (byte) 0;
}
else
{
return (byte) (section[(y & 0xf) << 8 | z << 4 | x] & 0xf);
}
}
private void setBlock(int x, int y, int z, char type)
{
if(x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf))
{
return;
}
getChunkSection(y, true)[(y & 0xf) << 8 | z << 4 | x] = type;
}
private char[] getChunkSection(int y, boolean c)
{
//@done
int s = y >> 4;
if(s == 0)
{
if(c && s0 == null)
{
s0 = new char[h];
}
return s0;
}
else if(s == 1)
{
if(c && s1 == null)
{
s1 = new char[h];
}
return s1;
}
else if(s == 2)
{
if(c && s2 == null)
{
s2 = new char[h];
}
return s2;
}
else if(s == 3)
{
if(c && s3 == null)
{
s3 = new char[h];
}
return s3;
}
else if(s == 4)
{
if(c && s4 == null)
{
s4 = new char[h];
}
return s4;
}
else if(s == 5)
{
if(c && s5 == null)
{
s5 = new char[h];
}
return s5;
}
else if(s == 6)
{
if(c && s6 == null)
{
s6 = new char[h];
}
return s6;
}
else if(s == 7)
{
if(c && s7 == null)
{
s7 = new char[h];
}
return s7;
}
else if(s == 8)
{
if(c && s8 == null)
{
s8 = new char[h];
}
return s8;
}
else if(s == 9)
{
if(c && s9 == null)
{
s9 = new char[h];
}
return s9;
}
else if(s == 10)
{
if(c && sA == null)
{
sA = new char[h];
}
return sA;
}
else if(s == 11)
{
if(c && sB == null)
{
sB = new char[h];
}
return sB;
}
else if(s == 12)
{
if(c && sC == null)
{
sC = new char[h];
}
return sC;
}
else if(s == 13)
{
if(c && sD == null)
{
sD = new char[h];
}
return sD;
}
else if(s == 14)
{
if(c && sE == null)
{
sE = new char[h];
}
return sE;
}
else if(s == 15)
{
if(c && sF == null)
{
sF = new char[h];
}
return sF;
}
else
{
System.out.print("CANT FIND SECTION: " + s);
}
return null;
//@done
}
public ChunkData toChunkData()
{
ChunkData c = new CraftChunkData(w);
try
{
m = (char[][]) t.get(c);
m[0] = s0;
m[1] = s1;
m[2] = s2;
m[3] = s3;
m[4] = s4;
m[5] = s5;
m[6] = s6;
m[7] = s7;
m[8] = s8;
m[9] = s9;
m[10] = sA;
m[11] = sB;
m[12] = sC;
m[13] = sD;
m[14] = sE;
m[15] = sF;
}
catch(IllegalArgumentException | IllegalAccessException e)
{
e.printStackTrace();
}
return c;
}
static
{
Field x = null;
try
{
x = CraftChunkData.class.getDeclaredField("sections");
x.setAccessible(true);
}
catch(Throwable e)
{
e.printStackTrace();
}
t = x;
}
}

View File

@ -0,0 +1,27 @@
package ninja.bytecode.iris.gen;
import java.util.Random;
import org.bukkit.World;
import ninja.bytecode.shuriken.math.RNG;
public class GenLayer implements IGenLayer
{
protected RNG rng;
protected World world;
protected Random random;
public GenLayer(World world, Random random, RNG rng)
{
this.world = world;
this.random = random;
this.rng = rng;
}
@Override
public double generateLayer(double noise, double dx, double dz)
{
return 0;
}
}

View File

@ -0,0 +1,72 @@
package ninja.bytecode.iris.gen;
import java.util.Random;
import org.bukkit.World;
import ninja.bytecode.shuriken.math.CNG;
import ninja.bytecode.shuriken.math.RNG;
public class GenLayerBase extends GenLayer
{
private double[][][] scatterCache;
private CNG gen;
private CNG fracture;
private CNG basegen;
public GenLayerBase(World world, Random random, RNG rng)
{
//@builder
super(world, random, rng);
scatterCache = new double[16][][];
CNG scatter = new CNG(rng.nextRNG(), 1, 1)
.scale(10);
basegen = new CNG(rng.nextRNG(), 0.46, 3)
.scale(0.00295)
.fractureWith(new CNG(rng.nextRNG(), 1, 2)
.scale(0.025), 70);
gen = new CNG(rng.nextRNG(), 0.19D, 4)
.scale(0.012)
.amp(0.5)
.freq(1.1)
.fractureWith(new CNG(rng.nextRNG(), 1, 2)
.scale(0.018)
.fractureWith(new CNG(rng.nextRNG(), 1, 1)
.scale(0.15), 24), 44);
fracture = new CNG(rng.nextRNG(), 0.6D, 4)
.scale(0.118);
// faultline = new CNG(rng.nextRNG(), 1D, 1)
// .scale(0.005)
// .child(new CNG(rng.nextRNG(), 1D, 1)
// .scale(0.012))
// .injectWith(CNG.MULTIPLY)
// .fractureWith(new CNG(rng.nextRNG(), 1, 1)
// .scale(0.07), 200);
//@done
for(int i = 0; i < 16; i++)
{
scatterCache[i] = new double[16][];
for(int j = 0; j < 16; j++)
{
scatterCache[i][j] = new double[16];
for(int k = 0; k < 16; k++)
{
scatterCache[i][j][k] = scatter.noise(i, j, k);
}
}
}
}
@Override
public double generateLayer(double noise, double dx, double dz)
{
super.generateLayer(noise, dx, dz);
double fnoise = fracture.noise(dx, dz);
double fx = dx + (fnoise * 12);
double fz = dz - (fnoise * 12);
return basegen.noise(fx, fz) + gen.noise(fx, fz);
}
}

View File

@ -0,0 +1,18 @@
package ninja.bytecode.iris.gen;
import java.util.Random;
import org.bukkit.World;
import ninja.bytecode.shuriken.math.RNG;
public class GenLayerFracture extends GenLayer
{
public GenLayerFracture(World world, Random random, RNG rng)
{
super(world, random, rng);
// TODO Auto-generated constructor stub
}
}

View File

@ -0,0 +1,6 @@
package ninja.bytecode.iris.gen;
public interface IGenLayer
{
public double generateLayer(double noise, double dx, double dz);
}