From a802edc375810030dd297cb9bdb6e4ee098d7061 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 23 Jun 2025 17:16:45 +0200 Subject: [PATCH] add some options for customizing caves --- .../iris/engine/mantle/MantleWriter.java | 70 ++++++++++++++++--- .../volmit/iris/engine/object/IrisCave.java | 11 ++- .../iris/engine/object/IrisCaveShape.java | 52 ++++++++++++++ .../volmit/iris/util/mantle/MantleChunk.java | 10 ++- 4 files changed, 131 insertions(+), 12 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java 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/IrisCave.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java index 22a45ccc4..db953f1a0 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"; @@ -96,8 +101,10 @@ public class IrisCave extends IrisRegistrant { 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(rng, 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); } 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..f5001befb --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java @@ -0,0 +1,52 @@ +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.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(new IrisPosition( + rng.i(0, 360), + rng.i(0, 360), + rng.i(0, 360)), + 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; + }); + } +} 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());