diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java b/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java index b71051472..ee2c9bf2d 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java @@ -35,6 +35,7 @@ import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.MantleChunk; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.Matter; +import com.volmit.iris.util.noise.CNG; import lombok.Data; import org.bukkit.block.data.BlockData; import org.bukkit.util.Vector; @@ -71,6 +72,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { private static Set getBallooned(Set vset, double radius) { Set returnset = new HashSet<>(); int ceilrad = (int) Math.ceil(radius); + double r2 = Math.pow(radius, 2); for (IrisPosition v : vset) { int tipx = v.getX(); @@ -80,7 +82,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) { for (int loopy = tipy - ceilrad; loopy <= tipy + ceilrad; loopy++) { for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) { - if (hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= radius) { + if (hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= r2) { returnset.add(new IrisPosition(loopx, loopy, loopz)); } } @@ -113,7 +115,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { for (double d : pars) { sum += Math.pow(d, 2); } - return Math.sqrt(sum); + return sum; } private static double lengthSq(double x, double y, double z) { @@ -453,6 +455,62 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { * @param the type of data to apply to the mantle */ public void setLineConsumer(List vectors, double radius, boolean filled, Function3 data) { + Set vset = cleanup(vectors); + vset = getBallooned(vset, radius); + + if (!filled) { + vset = getHollowed(vset); + } + + setConsumer(vset, data); + } + + /** + * Set lines for points + * + * @param vectors the points + * @param radius the radius + * @param filled hollow or filled? + * @param data the data to set + * @param the type of data to apply to the mantle + */ + public void setNoiseMasked(List vectors, double radius, double threshold, CNG shape, Set masks, boolean filled, Function3 data) { + Set vset = cleanup(vectors); + vset = masks == null ? getBallooned(vset, radius) : getMasked(vset, masks, radius); + vset.removeIf(p -> shape.noise(p.getX(), p.getY(), p.getZ()) < threshold); + + if (!filled) { + vset = getHollowed(vset); + } + + setConsumer(vset, data); + } + + private static Set getMasked(Set vectors, Set masks, double radius) { + Set vset = new KSet<>(); + int ceil = (int) Math.ceil(radius); + double r2 = Math.pow(radius, 2); + + for (IrisPosition v : vectors) { + int tipX = v.getX(); + int tipY = v.getY(); + int tipZ = v.getZ(); + + for (int x = -ceil; x <= ceil; x++) { + for (int y = -ceil; y <= ceil; y++) { + for (int z = -ceil; z <= ceil; z++) { + if (hypot(x, y, z) > r2 || !masks.contains(new IrisPosition(x, y, z))) + continue; + vset.add(new IrisPosition(tipX + x, tipY + y, tipZ + z)); + } + } + } + } + + return vset; + } + + private static Set cleanup(List vectors) { Set vset = new KSet<>(); for (int i = 0; vectors.size() != 0 && i < vectors.size() - 1; i++) { @@ -504,13 +562,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { } } - vset = getBallooned(vset, radius); - - if (!filled) { - vset = getHollowed(vset); - } - - setConsumer(vset, data); + return vset; } /** diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java index 1da8b1a31..8287db8c4 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java @@ -62,31 +62,31 @@ public class IrisCarving { @BlockCoordinates public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int depth) { - doCarving(writer, rng, engine, x, y, z, depth, -1); + doCarving(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, depth, -1); } @BlockCoordinates - public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { + public void doCarving(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) { int nextRecursion = recursion + 1; if (caves.isNotEmpty()) { for (IrisCavePlacer i : caves) { if (recursion > i.getMaxRecursion()) continue; - i.generateCave(writer, rng, engine, x, y, z, nextRecursion, waterHint); + i.generateCave(writer, rng, base, engine, x, y, z, nextRecursion, waterHint); } } if (ravines.isNotEmpty()) { for (IrisRavinePlacer i : ravines) { if (recursion > i.getMaxRecursion()) continue; - i.generateRavine(writer, rng, engine, x, y, z, nextRecursion, waterHint); + i.generateRavine(writer, rng, base, engine, x, y, z, nextRecursion, waterHint); } } if (spheres.isNotEmpty()) { for (IrisSphere i : spheres) { if (rng.nextInt(i.getRarity()) == 0) { - i.generate(rng, engine, writer, x, y, z); + i.generate(base, engine, writer, x, y, z); } } } @@ -94,7 +94,7 @@ public class IrisCarving { if (elipsoids.isNotEmpty()) { for (IrisElipsoid i : elipsoids) { if (rng.nextInt(i.getRarity()) == 0) { - i.generate(rng, engine, writer, x, y, z); + i.generate(base, engine, writer, x, y, z); } } } @@ -102,7 +102,7 @@ public class IrisCarving { if (pyramids.isNotEmpty()) { for (IrisPyramid i : pyramids) { if (rng.nextInt(i.getRarity()) == 0) { - i.generate(rng, engine, writer, x, y, z); + i.generate(base, engine, writer, x, y, z); } } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java index 22a45ccc4..b780d257d 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java @@ -25,9 +25,11 @@ import com.volmit.iris.engine.mantle.MantleWriter; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.RegistryListResource; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.MatterCavern; +import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.plugin.VolmitSender; import lombok.AllArgsConstructor; import lombok.Data; @@ -55,6 +57,9 @@ public class IrisCave extends IrisRegistrant { @Desc("Limit the worm from ever getting higher or lower than this range") private IrisRange verticalRange = new IrisRange(3, 255); + @Desc("Shape of the caves") + private IrisCaveShape shape = new IrisCaveShape(); + @Override public String getFolderName() { return "caves"; @@ -66,12 +71,12 @@ public class IrisCave extends IrisRegistrant { } public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) { - generate(writer, rng, engine, x, y, z, 0, -1, true); + generate(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1, true); } - public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint, boolean breakSurface) { - double girth = getWorm().getGirth().get(rng, x, z, engine.getData()); - KList points = getWorm().generate(rng, engine.getData(), writer, verticalRange, x, y, z, breakSurface, girth + 9); + public void generate(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint, boolean breakSurface) { + double girth = getWorm().getGirth().get(base.nextParallelRNG(465156), x, z, engine.getData()); + KList points = getWorm().generate(base.nextParallelRNG(784684), engine.getData(), writer, verticalRange, x, y, z, breakSurface, girth + 9); int highestWater = Math.max(waterHint, -1); if (highestWater == -1) { @@ -87,17 +92,19 @@ public class IrisCave extends IrisRegistrant { } - int h = Math.min(Math.max(highestWater, waterHint), engine.getDimension().getFluidHeight()); + int h = Math.min(highestWater, engine.getDimension().getFluidHeight()); for (IrisPosition i : points) { - fork.doCarving(writer, rng, engine, i.getX(), i.getY(), i.getZ(), recursion, h); + fork.doCarving(writer, rng, base, engine, i.getX(), i.getY(), i.getZ(), recursion, h); } MatterCavern c = new MatterCavern(true, customBiome, (byte) 0); MatterCavern w = new MatterCavern(true, customBiome, (byte) 1); - writer.setLineConsumer(points, - girth, true, + CNG cng = shape.getNoise(base.nextParallelRNG(8131545), engine); + KSet mask = shape.getMasked(rng, engine); + writer.setNoiseMasked(points, + girth, cng.noise(x, y, z), cng, mask, true, (xf, yf, zf) -> yf <= h ? w : c); } @@ -107,6 +114,6 @@ public class IrisCave extends IrisRegistrant { } public int getMaxSize(IrisData data, int depth) { - return getWorm().getMaxDistance() + fork.getMaxRange(data, depth); + return (int) (Math.ceil(getWorm().getGirth().getMax() * 2) + getWorm().getMaxDistance() + fork.getMaxRange(data, depth)); } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java index c56a53d69..ccdcaafb9 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java @@ -64,10 +64,10 @@ public class IrisCavePlacer implements IRare { } public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) { - generateCave(mantle, rng, engine, x, y, z, 0, -1); + generateCave(mantle, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1); } - public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { + public void generateCave(MantleWriter mantle, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) { if (fail.get()) { return; } @@ -86,13 +86,13 @@ public class IrisCavePlacer implements IRare { } if (y == -1) { - int h = (int) caveStartHeight.get(rng, x, z, data); + int h = (int) caveStartHeight.get(base, x, z, data); int ma = breakSurface ? h : (int) (engine.getComplex().getHeightStream().get(x, z) - 9); y = Math.min(h, ma); } try { - cave.generate(mantle, rng, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), recursion, waterHint, breakSurface); + cave.generate(mantle, rng, base, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), recursion, waterHint, breakSurface); } catch (Throwable e) { e.printStackTrace(); fail.set(true); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java new file mode 100644 index 000000000..4972ce516 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java @@ -0,0 +1,76 @@ +package com.volmit.iris.engine.object; + +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.annotations.Desc; +import com.volmit.iris.engine.object.annotations.RegistryListResource; +import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.math.M; +import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.noise.CNG; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Snippet("cave-shape") +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Desc("Cave Shape") +@Data +public class IrisCaveShape { + private transient final KMap> cache = new KMap<>(); + + @Desc("Noise used for the shape of the cave") + private IrisGeneratorStyle noise = new IrisGeneratorStyle(); + @RegistryListResource(IrisObject.class) + @Desc("Object used as mask for the shape of the cave") + private String object = null; + @Desc("Rotation to apply to objects before using them as mask") + private IrisObjectRotation objectRotation = new IrisObjectRotation(); + + public CNG getNoise(RNG rng, Engine engine) { + return noise.create(rng, engine.getData()); + } + + public KSet getMasked(RNG rng, Engine engine) { + if (object == null) return null; + return cache.computeIfAbsent(randomRotation(rng), pos -> { + var rotated = new KSet(); + engine.getData().getObjectLoader().load(object).getBlocks().forEach((vector, data) -> { + if (data.getMaterial().isAir()) return; + rotated.add(new IrisPosition(objectRotation.rotate(vector, pos.getX(), pos.getY(), pos.getZ()))); + }); + return rotated; + }); + } + + private IrisPosition randomRotation(RNG rng) { + if (objectRotation == null || !objectRotation.canRotate()) + return new IrisPosition(0,0,0); + return new IrisPosition( + randomDegree(rng, objectRotation.getXAxis()), + randomDegree(rng, objectRotation.getYAxis()), + randomDegree(rng, objectRotation.getZAxis()) + ); + } + + private int randomDegree(RNG rng, IrisAxisRotationClamp clamp) { + if (!clamp.isEnabled()) return 0; + if (clamp.isLocked()) return (int) clamp.getMax(); + double interval = clamp.getInterval(); + if (interval < 1) interval = 1; + + double min = clamp.getMin(), max = clamp.getMax(); + double value = (interval * (Math.ceil(Math.abs(rng.d(0, 360) / interval)))) % 360D; + if (clamp.isUnlimited()) return (int) value; + + if (min > max) { + max = clamp.getMin(); + min = clamp.getMax(); + } + return (int) (double) M.clip(value, min, max); + } +} diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java b/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java index 3edd37c29..b7c453bd6 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java @@ -93,13 +93,13 @@ public class IrisRavine extends IrisRegistrant { } public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) { - generate(writer, rng, engine, x, y, z, 0, -1); + generate(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1); } - public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { - KList pos = getWorm().generate(rng, engine.getData(), writer, null, x, y, z, true, 0); - CNG dg = depthStyle.getGenerator().createNoCache(rng, engine.getData()); - CNG bw = baseWidthStyle.getGenerator().createNoCache(rng, engine.getData()); + public void generate(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) { + KList pos = getWorm().generate(base.nextParallelRNG(879615), engine.getData(), writer, null, x, y, z, true, 0); + CNG dg = depthStyle.getGenerator().create(base.nextParallelRNG(7894156), engine.getData()); + CNG bw = baseWidthStyle.getGenerator().create(base.nextParallelRNG(15315456), engine.getData()); int highestWater = Math.max(waterHint, -1); boolean water = false; @@ -134,7 +134,7 @@ public class IrisRavine extends IrisRegistrant { int width = (int) Math.round(bw.fitDouble(baseWidthStyle.getMin(), baseWidthStyle.getMax(), p.getX(), p.getZ())); int surface = (int) Math.round(rsurface - depth * 0.45); - fork.doCarving(writer, rng, engine, p.getX(), rng.i(surface - depth, surface), p.getZ(), recursion, Math.max(highestWater, waterHint)); + fork.doCarving(writer, rng, base, engine, p.getX(), rng.i(surface - depth, surface), p.getZ(), recursion, highestWater); for (int i = surface + depth; i >= surface; i--) { if (i % ribThickness == 0) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java b/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java index fa65c5c79..ed9c01841 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java @@ -60,10 +60,10 @@ public class IrisRavinePlacer implements IRare { } public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) { - generateRavine(mantle, rng, engine, x, y, z, 0, -1); + generateRavine(mantle, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1); } - public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { + public void generateRavine(MantleWriter mantle, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) { if (fail.get()) { return; } @@ -84,7 +84,7 @@ public class IrisRavinePlacer implements IRare { try { int xx = x + rng.nextInt(15); int zz = z + rng.nextInt(15); - ravine.generate(mantle, rng, engine, xx, y, zz, recursion, waterHint); + ravine.generate(mantle, rng, base, engine, xx, y, zz, recursion, waterHint); } catch (Throwable e) { e.printStackTrace(); fail.set(true); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisWorm.java b/core/src/main/java/com/volmit/iris/engine/object/IrisWorm.java index b50f9d3be..e83fead07 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisWorm.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisWorm.java @@ -71,9 +71,9 @@ public class IrisWorm { IrisPosition start = new IrisPosition(x, y, z); KList pos = new KList<>(); KSet check = allowLoops ? null : new KSet<>(); - CNG gx = xStyle.getGenerator().createNoCache(new RNG(rng.lmax()), data); - CNG gy = yStyle.getGenerator().createNoCache(new RNG(rng.lmax()), data); - CNG gz = zStyle.getGenerator().createNoCache(new RNG(rng.lmax()), data); + CNG gx = xStyle.getGenerator().create(rng.nextParallelRNG(14567), data); + CNG gy = yStyle.getGenerator().create(rng.nextParallelRNG(64789), data); + CNG gz = zStyle.getGenerator().create(rng.nextParallelRNG(34790), data); while (itr-- > 0) { IrisPosition current = new IrisPosition(Math.round(cx), Math.round(cy), Math.round(cz)); diff --git a/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java b/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java index ae4fd1701..1c50d8c98 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java @@ -27,6 +27,7 @@ import com.volmit.iris.util.matter.IrisMatter; import com.volmit.iris.util.matter.Matter; import com.volmit.iris.util.matter.MatterSlice; import lombok.Getter; +import lombok.SneakyThrows; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; @@ -111,9 +112,11 @@ public class MantleChunk { } } - public void close() throws InterruptedException { + @SneakyThrows + public void close() { closed.set(true); ref.acquire(Integer.MAX_VALUE); + ref.release(Integer.MAX_VALUE); } public boolean inUse() { @@ -123,6 +126,10 @@ public class MantleChunk { public MantleChunk use() { if (closed.get()) throw new IllegalStateException("Chunk is closed!"); ref.acquireUninterruptibly(); + if (closed.get()) { + ref.release(); + throw new IllegalStateException("Chunk is closed!"); + } return this; } @@ -213,6 +220,7 @@ public class MantleChunk { * @throws IOException shit happens */ public void write(DataOutputStream dos) throws IOException { + close(); dos.writeByte(x); dos.writeByte(z); dos.writeByte(sections.length());