From 74311098084ad50121a08ac8c1b43c8b48d35261 Mon Sep 17 00:00:00 2001 From: thajohns Date: Sun, 5 Jul 2020 22:09:01 -0400 Subject: [PATCH] Added new PointWorld types, including a cache --- src/main/java/t/j/dual/CachedPointWorld.java | 49 ++++++++++++++++++ src/main/java/t/j/dual/GridCache.java | 50 +++++++++++++++++++ src/main/java/t/j/dual/PointWorld.java | 19 +++++-- src/main/java/t/j/dual/RandomPointWorld.java | 21 ++++++-- .../java/t/j/dual/RecelledPointWorld.java | 39 +++++++++++++++ src/main/java/t/j/dual/ScaledPointWorld.java | 45 +++++++++++++++++ src/main/java/t/j/dual/Utilities.java | 12 +++++ .../java/t/j/dual/WorldProviderPeace.java | 45 ++++++++++------- 8 files changed, 252 insertions(+), 28 deletions(-) create mode 100644 src/main/java/t/j/dual/CachedPointWorld.java create mode 100644 src/main/java/t/j/dual/GridCache.java create mode 100644 src/main/java/t/j/dual/RecelledPointWorld.java create mode 100644 src/main/java/t/j/dual/ScaledPointWorld.java diff --git a/src/main/java/t/j/dual/CachedPointWorld.java b/src/main/java/t/j/dual/CachedPointWorld.java new file mode 100644 index 0000000..38dcf3b --- /dev/null +++ b/src/main/java/t/j/dual/CachedPointWorld.java @@ -0,0 +1,49 @@ +package t.j.dual; + +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.WeakHashMap; + +import net.minecraft.util.math.*; + +import t.j.dual.PointWorld; +import t.j.dual.GridCache; + +public class CachedPointWorld implements PointWorld { + PointWorld pworld; + GridCache> cache; + float mean; + Vec3d cellsize; + + public CachedPointWorld(PointWorld pworld) { + this.pworld = pworld; + this.cellsize = pworld.getCellSize(); + this.cache = new GridCache>((cell) -> pworld.pointsInCell(cell)); + } + + public float getMeanPointsPerCell() { + return mean; + } + + // TODO: maybe cache? + public Vec3d getCellOrigin(Vec3i cell) { + return pworld.getCellOrigin(cell); + } + + public Vec3d getCellSize() { + return cellsize; + } + + public ArrayList cache(Vec3i cell) { + return cache.cache(cell); + } + + public void expunge(Vec3i cell) { + cache.expunge(cell); + } + + public ArrayList pointsInCell(Vec3i cell) { + return cache.get(cell); + } +} + diff --git a/src/main/java/t/j/dual/GridCache.java b/src/main/java/t/j/dual/GridCache.java new file mode 100644 index 0000000..bff5a9c --- /dev/null +++ b/src/main/java/t/j/dual/GridCache.java @@ -0,0 +1,50 @@ +package t.j.dual; + +import java.lang.ref.SoftReference; +import java.util.WeakHashMap; +import java.util.function.Function; + +import net.minecraft.util.math.*; + +import t.j.dual.Utilities; + +public class GridCache { + Function source; + WeakHashMap>> cacheMap; + + class CacheEntry { + public Vec3i keyRef; + public T value; + + public CacheEntry(Vec3i keyRef, T value) { + this.keyRef = keyRef; + this.value = value; + } + } + + public GridCache(Function source) { + this.source = source; + this.cacheMap = new WeakHashMap>>(); + } + + public T cache(Vec3i cell) { + T toCache = source.apply(cell); + cacheMap.put(cell, new SoftReference>(new CacheEntry(cell, toCache))); + return toCache; + } + + public void expunge(Vec3i cell) { + cacheMap.remove(cell); + } + + public T get(Vec3i cell) { + SoftReference> softRef = cacheMap.get(cell); + if (softRef != null) { + CacheEntry entry = softRef.get(); + if (entry != null) { + return entry.value; + } + } + return cache(cell); + } +} diff --git a/src/main/java/t/j/dual/PointWorld.java b/src/main/java/t/j/dual/PointWorld.java index 16c618d..b5b963e 100644 --- a/src/main/java/t/j/dual/PointWorld.java +++ b/src/main/java/t/j/dual/PointWorld.java @@ -2,20 +2,29 @@ package t.j.dual; import java.util.Random; import java.util.ArrayList; +import java.util.stream.Collectors; import net.minecraft.util.math.*; +import t.j.dual.Utilities; + interface PointWorld { - public Vec3d[] pointsInCell(Vec3i cell); + public ArrayList pointsInCell(Vec3i cell); + + public float getMeanPointsPerCell(); + + public Vec3d getCellOrigin(Vec3i cell); + + public Vec3d getCellSize(); - default public ArrayList pointsInAABB(Vec3d origin, Vec3d remote) { + default public ArrayList pointsInAABB(Vec3d uOrigin, Vec3d uRemote) { + Vec3d origin = Utilities.ewDiv(uOrigin, this.getCellSize()); + Vec3d remote = Utilities.ewDiv(uRemote, this.getCellSize()); ArrayList points = new ArrayList(); for (int x = (int) Math.floor(origin.x); x < (int) Math.ceil(remote.x); x++) { for (int y = (int) Math.floor(origin.y); y < (int) Math.ceil(remote.y); y++) { for (int z = (int) Math.floor(origin.z); z < (int) Math.ceil(remote.z); z++) { - for (Vec3d point : pointsInCell(new Vec3i(x, y, z))) { - points.add(point); - } + points.addAll(pointsInCell(new Vec3i(x, y, z)).stream().filter((p) -> Utilities.inBoundingBox(p, uOrigin, uRemote)).collect(Collectors.toList())); } } } diff --git a/src/main/java/t/j/dual/RandomPointWorld.java b/src/main/java/t/j/dual/RandomPointWorld.java index 912db5e..bdaf383 100644 --- a/src/main/java/t/j/dual/RandomPointWorld.java +++ b/src/main/java/t/j/dual/RandomPointWorld.java @@ -8,6 +8,7 @@ import t.j.dual.PointWorld; class RandomPointWorld implements PointWorld { long seed; + final static float lambda = 1.0f; Random random; public RandomPointWorld(Random random, long seed) { @@ -15,14 +16,26 @@ class RandomPointWorld implements PointWorld { this.random = random; } - public Vec3d[] pointsInCell(Vec3i cell) { + public float getMeanPointsPerCell() { + return lambda; + } + + public Vec3d getCellOrigin(Vec3i cell) { + return new Vec3d(cell); + } + + public Vec3d getCellSize() { + return new Vec3d(1.0, 1.0, 1.0); + } + + public ArrayList pointsInCell(Vec3i cell) { random.setSeed(seed ^ cell.getX()); random.setSeed(random.nextLong() ^ cell.getY()); random.setSeed(random.nextLong() ^ cell.getZ()); - int nPoints = Utilities.drawPoisson(random, 1.0f); - Vec3d[] points = new Vec3d[nPoints]; + int nPoints = Utilities.drawPoisson(random, lambda); + ArrayList points = new ArrayList(nPoints); for (int i = 0; i < nPoints; i++) { - points[i] = new Vec3d(cell.getX() + random.nextDouble(), cell.getY() + random.nextDouble(), cell.getZ() + random.nextDouble()); + points.add(new Vec3d(cell.getX() + random.nextDouble(), cell.getY() + random.nextDouble(), cell.getZ() + random.nextDouble())); } return points; } diff --git a/src/main/java/t/j/dual/RecelledPointWorld.java b/src/main/java/t/j/dual/RecelledPointWorld.java new file mode 100644 index 0000000..ebe48b4 --- /dev/null +++ b/src/main/java/t/j/dual/RecelledPointWorld.java @@ -0,0 +1,39 @@ +package t.j.dual; + +import net.minecraft.util.math.*; +import java.util.Random; +import java.util.ArrayList; + +import t.j.dual.PointWorld; + +class RecelledPointWorld implements PointWorld { + PointWorld pworld; + Vec3d cellsize; + float mean; + + public RecelledPointWorld(PointWorld pworld, Vec3d cellsize) { + this.pworld = pworld; + this.cellsize = cellsize; + this.mean = pworld.getMeanPointsPerCell() * (float) (cellsize.x * cellsize.y * cellsize.z); + } + + public float getMeanPointsPerCell() { + return mean; + } + + public Vec3d getCellOrigin(Vec3i cell) { + return new Vec3d(cell.getX() * cellsize.x, cell.getY() * cellsize.y, cell.getZ() * cellsize.z); + } + + public Vec3d getCellSize() { + return cellsize; + } + + private Vec3d getCellRemote(Vec3i cell) { + return new Vec3d((cell.getX() + 1) * cellsize.x, (cell.getY() + 1) * cellsize.y, (cell.getZ() + 1) * cellsize.z); + } + + public ArrayList pointsInCell(Vec3i cell) { + return pworld.pointsInAABB(getCellOrigin(cell), getCellRemote(cell)); + } +} diff --git a/src/main/java/t/j/dual/ScaledPointWorld.java b/src/main/java/t/j/dual/ScaledPointWorld.java new file mode 100644 index 0000000..56316e4 --- /dev/null +++ b/src/main/java/t/j/dual/ScaledPointWorld.java @@ -0,0 +1,45 @@ +package t.j.dual; + +import net.minecraft.util.math.*; +import java.util.Random; +import java.util.ArrayList; + +import t.j.dual.PointWorld; +import t.j.dual.Utilities; + +class ScaledPointWorld implements PointWorld { + PointWorld pworld; + Vec3d scale; + Vec3d iscale; + Vec3d cellsize; + float mean; + + public ScaledPointWorld(PointWorld pworld, Vec3d scale) { + this.pworld = pworld; + this.scale = scale; + this.iscale = new Vec3d(1.0 / scale.x, 1.0 / scale.y, 1.0 / scale.z); + this.cellsize = Utilities.ewMult(pworld.getCellSize(), scale); + this.mean = pworld.getMeanPointsPerCell(); + } + + public float getMeanPointsPerCell() { + return mean; + } + + public Vec3d getCellOrigin(Vec3i cell) { + return Utilities.ewMult(pworld.getCellOrigin(cell), scale); + } + + public Vec3d getCellSize() { + return cellsize; + } + + public ArrayList pointsInCell(Vec3i cell) { + ArrayList unscaled = pworld.pointsInCell(cell); + ArrayList scaled = new ArrayList(unscaled.size()); + for (Vec3d point : unscaled) { + scaled.add(Utilities.ewMult(point, scale)); + } + return scaled; + } +} diff --git a/src/main/java/t/j/dual/Utilities.java b/src/main/java/t/j/dual/Utilities.java index 69da1bb..23d9e76 100644 --- a/src/main/java/t/j/dual/Utilities.java +++ b/src/main/java/t/j/dual/Utilities.java @@ -25,6 +25,18 @@ class Utilities { origin.z < point.z && point.z < remote.z; } + public static Vec3d ewMult(Vec3d a, Vec3d b) { + return new Vec3d(a.x * b.x, a.y * b.y, a.z * b.z); + } + + public static Vec3d ewDiv(Vec3d a, Vec3d b) { + return new Vec3d(a.x / b.x, a.y / b.y, a.z / b.z); + } + + public static Vec3d ewInv(Vec3d b) { + return new Vec3d(1.0 / b.x, 1.0 / b.y, 1.0 / b.z); + } + public static class LFSRRandom extends Random { private long seed; diff --git a/src/main/java/t/j/dual/WorldProviderPeace.java b/src/main/java/t/j/dual/WorldProviderPeace.java index bd39365..42f30e8 100644 --- a/src/main/java/t/j/dual/WorldProviderPeace.java +++ b/src/main/java/t/j/dual/WorldProviderPeace.java @@ -46,39 +46,43 @@ class BedrockChunkGenerator implements IChunkGenerator { World world; Random random; PointWorld pointworld; + static final Vec3d pointScale = new Vec3d(3, 3, 3); + static final Vec3d pointMapFactor = Utilities.ewInv(pointScale).scale(16); public BedrockChunkGenerator(World w) { world = w; this.random = new Utilities.LFSRRandom(0); - this.pointworld = new RandomPointWorld(random, world.getSeed()); + this.pointworld = new ScaledPointWorld(new RecelledPointWorld(new CachedPointWorld(new RandomPointWorld(random, world.getSeed())), pointMapFactor), pointScale); } public Chunk generateChunk(int X, int Z) { - WorldProviderPeace.logger.info("bedrock: " + X + " " + Z); ChunkPrimer primer = new ChunkPrimer(); - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - primer.setBlockState(x, 0, z, Blocks.BEDROCK.getDefaultState()); - } - } if (((X ^ Z) & 3) >= 0) { - double scale = 8; - double perchunk = 16 / scale; WorldProviderPeace.logger.info("points:" + X + " " + Z); - List points = pointworld.pointsInAABB(new Vec3d(perchunk * X, 0, perchunk * Z), new Vec3d(perchunk * X + perchunk, perchunk * 16, perchunk * Z + perchunk)); + List points = pointworld.pointsInAABB(new Vec3d(X * 16, 0, Z * 16), new Vec3d(X * 16 + 16, 256, Z * 16 + 16)); WorldProviderPeace.logger.info("blocks: " + X + " " + Z); int i = 0; - int totalz = 0; for (Vec3d point: points) { - i++; - int x = (int) (scale * (point.x - perchunk * X)); - int y = (int) (scale * point.y); - int z = (int) (scale * (point.z - perchunk * Z)); - totalz += z; - primer.setBlockState(x, y, z, Blocks.STONE.getDefaultState()); + IBlockState block; + if (point.y > 250) { + block = Blocks.GRASS.getDefaultState(); + } else if (point.y > 240) { + block = Blocks.DIRT.getDefaultState(); + } else { + block = Blocks.STONE.getDefaultState(); + } + int x = (int) Math.floor(point.x) - X * 16; + int y = (int) Math.floor(point.y); + int z = (int) Math.floor(point.z) - Z * 16; + primer.setBlockState(x, y, z, block); } WorldProviderPeace.logger.info("(generated " + i + " blocks): " + X + " " + Z); - WorldProviderPeace.logger.info("mean z: " + totalz / (double) i); + } + WorldProviderPeace.logger.info("bedrock: " + X + " " + Z); + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + primer.setBlockState(x, 0, z, Blocks.BEDROCK.getDefaultState()); + } } WorldProviderPeace.logger.info("chunk: " + X + " " + Z); primer.setBlockState(0, 255, 0, Blocks.GOLD_BLOCK.getDefaultState()); @@ -92,6 +96,7 @@ class BedrockChunkGenerator implements IChunkGenerator { } public boolean generateStructures(Chunk chunkIn, int x, int z) { + WorldProviderPeace.logger.info("generateStructures() called: " + x + " " + z); return true; } @@ -108,9 +113,11 @@ class BedrockChunkGenerator implements IChunkGenerator { } public void populate(int x, int z) { + WorldProviderPeace.logger.info("populate() called: " + x + " " + z); } - public void recreateStructures(Chunk chunkIn, int x, int y) { + public void recreateStructures(Chunk chunkIn, int x, int z) { + WorldProviderPeace.logger.info("recreateStructures() called: " + x + " " + z); } private float[] verticalWeightMap(int x, int z) {