From a802edc375810030dd297cb9bdb6e4ee098d7061 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 23 Jun 2025 17:16:45 +0200 Subject: [PATCH 01/36] 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()); From cca0bed482c9d4eff8710a050b311ff1e16da089 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 24 Jun 2025 16:53:26 +0200 Subject: [PATCH 02/36] fix cave max size calculation --- core/src/main/java/com/volmit/iris/engine/object/IrisCave.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 db953f1a0..bcfd2a05c 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 @@ -114,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)); } } From cf8243a0008db153b8f92dd270c058f2be969437 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 24 Jun 2025 19:37:37 +0200 Subject: [PATCH 03/36] make caves more deterministic --- .../com/volmit/iris/engine/object/IrisCarving.java | 14 +++++++------- .../com/volmit/iris/engine/object/IrisCave.java | 14 +++++++------- .../volmit/iris/engine/object/IrisCavePlacer.java | 8 ++++---- .../com/volmit/iris/engine/object/IrisRavine.java | 12 ++++++------ .../iris/engine/object/IrisRavinePlacer.java | 6 +++--- .../com/volmit/iris/engine/object/IrisWorm.java | 6 +++--- 6 files changed, 30 insertions(+), 30 deletions(-) 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 bcfd2a05c..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 @@ -71,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) { @@ -92,16 +92,16 @@ 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); - CNG cng = shape.getNoise(rng, engine); + 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, 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/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)); From cc49b0f54086f613c9628d6ff842575854525f3b Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 9 Jul 2025 17:37:58 +0200 Subject: [PATCH 04/36] hopefully fix eta --- .../volmit/iris/core/pregenerator/IrisPregenerator.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java index dbd734a56..e90307dc9 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java @@ -153,12 +153,11 @@ public class IrisPregenerator { } private long computeETA() { - double d = (long) (totalChunks.get() > 1024 ? // Generated chunks exceed 1/8th of total? + double d = (long) (generated.get() > 1024 ? // Generated chunks exceed 1/8th of total? // If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers) - ((totalChunks.get() - generated.get() - cached.get()) * ((double) (M.ms() - startTime.get()) / ((double) generated.get() - cached.get()))) : + ((totalChunks.get() - generated.get()) * ((double) (M.ms() - startTime.get()) / (double) generated.get())) : // If no, use quick function (which is less accurate over time but responds better to the initial delay) - ((totalChunks.get() - generated.get() - cached.get()) / chunksPerSecond.getAverage()) * 1000 - ); + ((totalChunks.get() - generated.get()) / chunksPerSecond.getAverage()) * 1000); return Double.isFinite(d) && d != INVALID ? (long) d : 0; } From 94c578249033e4758b8d1a6e04850d5a8a58850c Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 9 Jul 2025 18:49:55 +0200 Subject: [PATCH 05/36] move loading message to debug --- core/src/main/java/com/volmit/iris/Iris.java | 13 ++--- .../com/volmit/iris/core/IrisSettings.java | 2 + .../com/volmit/iris/util/misc/SlimJar.java | 58 +++++++++++++++++++ gradle/libs.versions.toml | 2 +- 4 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/misc/SlimJar.java diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 7b9c53f4c..be5854cf7 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -52,6 +52,7 @@ import com.volmit.iris.util.io.JarScanner; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.misc.Bindings; +import com.volmit.iris.util.misc.SlimJar; import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.IrisService; @@ -60,7 +61,6 @@ import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Queue; import com.volmit.iris.util.scheduling.ShurikenQueue; -import io.github.slimjar.app.builder.ApplicationBuilder; import lombok.NonNull; import org.bukkit.*; import org.bukkit.block.data.BlockData; @@ -437,17 +437,12 @@ public class Iris extends VolmitPlugin implements Listener { } public Iris() { - ApplicationBuilder.appending("Iris") - .downloadDirectoryPath(getDataFolder("cache", "libraries").toPath()) - .logger((message, args) -> { - if (!message.startsWith("Loaded library ")) return; - getLogger().info(message.formatted(args)); - }) - .build(); + instance = this; + SlimJar.debug(IrisSettings.get().getSentry().isDebug()); + SlimJar.load(getDataFolder("cache", "libraries")); } private void enable() { - instance = this; services = new KMap<>(); setupAudience(); Bindings.setupSentry(); diff --git a/core/src/main/java/com/volmit/iris/core/IrisSettings.java b/core/src/main/java/com/volmit/iris/core/IrisSettings.java index 30216b29e..faaecc8f0 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -23,6 +23,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONException; import com.volmit.iris.util.json.JSONObject; +import com.volmit.iris.util.misc.SlimJar; import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.plugin.VolmitSender; import lombok.AllArgsConstructor; @@ -86,6 +87,7 @@ public class IrisSettings { Iris.error("Configuration Error in settings.json! " + ee.getClass().getSimpleName() + ": " + ee.getMessage()); } } + SlimJar.debug(settings.general.debug); return settings; } diff --git a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java new file mode 100644 index 000000000..fa79b849d --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -0,0 +1,58 @@ +package com.volmit.iris.util.misc; + +import io.github.slimjar.app.builder.ApplicationBuilder; +import io.github.slimjar.logging.ProcessLogger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class SlimJar { + private static final Logger LOGGER = Logger.getLogger("Iris"); + private static final ReentrantLock lock = new ReentrantLock(); + private static final AtomicBoolean loaded = new AtomicBoolean(); + + public static void debug(boolean debug) { + LOGGER.setLevel(debug ? Level.FINE : Level.INFO); + } + + public static void load(@Nullable File localRepository) { + if (loaded.get()) return; + lock.lock(); + + try { + if (loaded.getAndSet(true)) return; + if (localRepository == null) { + localRepository = new File(".iris/libraries"); + } + + LOGGER.info("Loading libraries..."); + ApplicationBuilder.appending("Iris") + .downloadDirectoryPath(localRepository.toPath()) + .logger(new ProcessLogger() { + @Override + public void info(@NotNull String message, @Nullable Object... args) { + LOGGER.fine(message.formatted(args)); + } + + @Override + public void error(@NotNull String message, @Nullable Object... args) { + LOGGER.severe(message.formatted(args)); + } + + @Override + public void debug(@NotNull String message, @Nullable Object... args) { + LOGGER.fine(message.formatted(args)); + } + }) + .build(); + LOGGER.info("Libraries loaded successfully!"); + } finally { + lock.unlock(); + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 81d36c3ee..bdc075162 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ [versions] # Plugins shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow -slimjar = "2.0.6" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.0.7" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin From 343dc429d5159b7b840736bc1b636ee3398b698e Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 10 Jul 2025 19:20:46 +0200 Subject: [PATCH 06/36] fix null pointer when failing to load a dimension --- .../src/main/java/com/volmit/iris/core/ServerConfigurator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java index ca8b242d2..d249bfbcd 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -44,6 +44,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerArray; import java.util.stream.Stream; @@ -140,6 +141,7 @@ public class ServerConfigurator { var loader = data.getDimensionLoader(); return loader.loadAll(loader.getPossibleKeys()) .stream() + .filter(Objects::nonNull) .map(ServerConfigurator::verifyDataPackInstalled) .toList() .contains(false); @@ -280,6 +282,7 @@ public class ServerConfigurator { var loader = data.getDimensionLoader(); return loader.loadAll(loader.getPossibleKeys()) .stream() + .filter(Objects::nonNull) .peek(this::merge); } From 64bb81626c3ce146021089e27ef713ca53b7b5e4 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 11 Jul 2025 12:54:16 +0200 Subject: [PATCH 07/36] update overworld pack --- build.gradle.kts | 2 +- core/src/main/java/com/volmit/iris/core/nms/INMS.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index fd1f9e400..4def2b348 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,7 +37,7 @@ plugins { } group = "com.volmit" -version = "3.6.11-1.20.1-1.21.5" +version = "3.6.11-1.20.1-1.21.7" apply() diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMS.java b/core/src/main/java/com/volmit/iris/core/nms/INMS.java index 848b08879..8b998147c 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMS.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMS.java @@ -40,6 +40,7 @@ public class INMS { "1.21.7", "v1_21_R5" ); private static final List PACKS = List.of( + new Version(21, 5, "31100"), new Version(21, 4, "31020"), new Version(21, 2, "31000"), new Version(20, 1, "3910") From f6590c26e70e6e259ee3ad51993209b7a7bedf90 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 11 Jul 2025 13:07:20 +0200 Subject: [PATCH 08/36] fix download failing for dimensions with snippets --- .../volmit/iris/core/service/StudioSVC.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/service/StudioSVC.java b/core/src/main/java/com/volmit/iris/core/service/StudioSVC.java index 118a11e13..bf070d063 100644 --- a/core/src/main/java/com/volmit/iris/core/service/StudioSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/StudioSVC.java @@ -18,7 +18,6 @@ package com.volmit.iris.core.service; -import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; @@ -250,30 +249,25 @@ public class StudioSVC implements IrisService { return; } - File dimensions = new File(dir, "dimensions"); + IrisData data = IrisData.get(dir); + String[] dimensions = data.getDimensionLoader().getPossibleKeys(); - if (!(dimensions.exists() && dimensions.isDirectory())) { - sender.sendMessage("Invalid Format. Missing dimensions folder"); - return; - } - - if (dimensions.listFiles() == null) { + if (dimensions == null || dimensions.length == 0) { sender.sendMessage("No dimension file found in the extracted zip file."); sender.sendMessage("Check it is there on GitHub and report this to staff!"); - } else if (dimensions.listFiles().length != 1) { + } else if (dimensions.length != 1) { sender.sendMessage("Dimensions folder must have 1 file in it"); return; } - File dim = dimensions.listFiles()[0]; + IrisDimension d = data.getDimensionLoader().load(dimensions[0]); - if (!dim.isFile()) { + if (d == null) { sender.sendMessage("Invalid dimension (folder) in dimensions folder"); return; } - String key = dim.getName().split("\\Q.\\E")[0]; - IrisDimension d = new Gson().fromJson(IO.readAll(dim), IrisDimension.class); + String key = d.getLoadKey(); sender.sendMessage("Importing " + d.getName() + " (" + key + ")"); File packEntry = new File(packs, key); From a9891e819abce21747047cde2b3469442d24f6c5 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 12 Jul 2025 12:51:04 +0200 Subject: [PATCH 09/36] v+ --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4def2b348..462d697a2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,7 +37,7 @@ plugins { } group = "com.volmit" -version = "3.6.11-1.20.1-1.21.7" +version = "3.7.0-1.20.1-1.21.7" apply() From 9ade90d9cafe36ab41653cf4ebc6d14520bfd901 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 12 Jul 2025 15:51:49 +0200 Subject: [PATCH 10/36] make the mythic mobs link a data provider and make adding custom mob plugins easier --- core/src/main/java/com/volmit/iris/Iris.java | 3 - .../iris/core/link/ExternalDataProvider.java | 59 ++++++- .../volmit/iris/core/link/data/DataType.java | 33 ++++ .../link/{ => data}/EcoItemsDataProvider.java | 44 ++--- .../ExecutableItemsDataProvider.java | 45 ++---- .../{ => data}/HMCLeavesDataProvider.java | 48 ++---- .../{ => data}/ItemAdderDataProvider.java | 152 +++++++++--------- .../{ => data}/KGeneratorsDataProvider.java | 36 ++--- .../link/{ => data}/MMOItemsDataProvider.java | 70 ++++---- .../MythicCrucibleDataProvider.java | 76 ++------- .../MythicMobsDataProvider.java} | 91 +++++------ .../link/{ => data}/NexoDataProvider.java | 85 ++++------ .../iris/core/project/SchemaBuilder.java | 16 +- .../iris/core/service/ExternalDataSVC.java | 89 +++++----- .../volmit/iris/engine/object/IrisEntity.java | 15 +- .../java/com/volmit/iris/util/data/B.java | 5 +- .../com/volmit/iris/util/scheduling/J.java | 15 ++ 17 files changed, 401 insertions(+), 481 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/core/link/data/DataType.java rename core/src/main/java/com/volmit/iris/core/link/{ => data}/EcoItemsDataProvider.java (57%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/ExecutableItemsDataProvider.java (50%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/HMCLeavesDataProvider.java (81%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/ItemAdderDataProvider.java (59%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/KGeneratorsDataProvider.java (73%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/MMOItemsDataProvider.java (64%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/MythicCrucibleDataProvider.java (64%) rename core/src/main/java/com/volmit/iris/core/link/{MythicMobsLink.java => data/MythicMobsDataProvider.java} (54%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/NexoDataProvider.java (63%) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index be5854cf7..f299e4409 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -25,7 +25,6 @@ import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.link.IrisPapiExpansion; import com.volmit.iris.core.link.MultiverseCoreLink; -import com.volmit.iris.core.link.MythicMobsLink; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.v1X.NMSBinding1X; @@ -95,7 +94,6 @@ public class Iris extends VolmitPlugin implements Listener { public static Iris instance; public static Bindings.Adventure audiences; public static MultiverseCoreLink linkMultiverseCore; - public static MythicMobsLink linkMythicMobs; public static IrisCompat compat; public static FileWatcher configWatcher; private static VolmitSender sender; @@ -454,7 +452,6 @@ public class Iris extends VolmitPlugin implements Listener { getSender().setTag(getTag()); IrisSafeguard.splash(true); linkMultiverseCore = new MultiverseCoreLink(); - linkMythicMobs = new MythicMobsLink(); configWatcher = new FileWatcher(getDataFile("settings.json")); services.values().forEach(IrisService::onEnable); services.values().forEach(this::registerListener); diff --git a/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java index 02bf058a8..bbc7e8088 100644 --- a/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java @@ -1,24 +1,33 @@ package com.volmit.iris.core.link; +import com.volmit.iris.core.link.data.DataType; +import com.volmit.iris.core.nms.container.Pair; +import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.data.IrisCustomData; +import com.volmit.iris.util.math.RNG; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; import java.util.MissingResourceException; @Getter @RequiredArgsConstructor -public abstract class ExternalDataProvider { +public abstract class ExternalDataProvider implements Listener { @NonNull private final String pluginId; @@ -53,7 +62,9 @@ public abstract class ExternalDataProvider { * @throws MissingResourceException when the blockId is invalid */ @NotNull - public abstract BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException; + public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { + throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); + } /** * @see ExternalDataProvider#getItemStack(Identifier) @@ -73,7 +84,9 @@ public abstract class ExternalDataProvider { * @throws MissingResourceException when the itemId is invalid */ @NotNull - public abstract ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException; + public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { + throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); + } /** * This method is used for placing blocks that need to use the plugins api @@ -85,9 +98,43 @@ public abstract class ExternalDataProvider { */ public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {} - public abstract @NotNull Identifier[] getBlockTypes(); + /** + * Spawns a mob in the specified location using the given engine and entity identifier. + * + * @param location The location in the world where the mob should spawn. Must not be null. + * @param entityId The identifier of the mob entity to spawn. Must not be null. + * @return The spawned {@link Entity} if successful, or null if the mob could not be spawned. + */ + @Nullable + public Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException { + throw new MissingResourceException("Failed to find Entity!", entityId.namespace(), entityId.key()); + } - public abstract @NotNull Identifier[] getItemTypes(); + public abstract @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType); - public abstract boolean isValidProvider(@NotNull Identifier id, boolean isItem); + public abstract boolean isValidProvider(@NotNull Identifier id, DataType dataType); + + protected static Pair parseYawAndFace(@NotNull Engine engine, @NotNull Block block, @NotNull KMap<@NotNull String, @NotNull String> state) { + float yaw = 0; + BlockFace face = BlockFace.NORTH; + + long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY(); + RNG rng = new RNG(seed); + if ("true".equals(state.get("randomYaw"))) { + yaw = rng.f(0, 360); + } else if (state.containsKey("yaw")) { + yaw = Float.parseFloat(state.get("yaw")); + } + if ("true".equals(state.get("randomFace"))) { + BlockFace[] faces = BlockFace.values(); + face = faces[rng.i(0, faces.length - 1)]; + } else if (state.containsKey("face")) { + face = BlockFace.valueOf(state.get("face").toUpperCase()); + } + if (face == BlockFace.SELF) { + face = BlockFace.NORTH; + } + + return new Pair<>(yaw, face); + } } diff --git a/core/src/main/java/com/volmit/iris/core/link/data/DataType.java b/core/src/main/java/com/volmit/iris/core/link/data/DataType.java new file mode 100644 index 000000000..65edfc2a3 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/link/data/DataType.java @@ -0,0 +1,33 @@ +package com.volmit.iris.core.link.data; + +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; + +import java.util.MissingResourceException; +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +public enum DataType implements BiPredicate { + ITEM, + BLOCK, + ENTITY; + + @Override + public boolean test(ExternalDataProvider dataProvider, Identifier identifier) { + if (!dataProvider.isValidProvider(identifier, this)) return false; + try { + switch (this) { + case ITEM -> dataProvider.getItemStack(identifier); + case BLOCK -> dataProvider.getBlockData(identifier); + case ENTITY -> {} + } + return true; + } catch (MissingResourceException e) { + return false; + } + } + + public Predicate asPredicate(ExternalDataProvider dataProvider) { + return i -> test(dataProvider, i); + } +} diff --git a/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/EcoItemsDataProvider.java similarity index 57% rename from core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/EcoItemsDataProvider.java index 81eb9669a..05e9cd221 100644 --- a/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/EcoItemsDataProvider.java @@ -1,16 +1,18 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; -import com.volmit.iris.util.collection.KList; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.reflect.WrappedField; import com.willfp.ecoitems.items.EcoItem; import com.willfp.ecoitems.items.EcoItems; import org.bukkit.NamespacedKey; -import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; public class EcoItemsDataProvider extends ExternalDataProvider { @@ -34,12 +36,6 @@ public class EcoItemsDataProvider extends ExternalDataProvider { } } - @NotNull - @Override - public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { - throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); - } - @NotNull @Override public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { @@ -48,30 +44,18 @@ public class EcoItemsDataProvider extends ExternalDataProvider { return itemStack.get(item).clone(); } - @NotNull @Override - public Identifier[] getBlockTypes() { - return new Identifier[0]; - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - KList names = new KList<>(); - for (EcoItem item : EcoItems.INSTANCE.values()) { - try { - Identifier key = Identifier.fromNamespacedKey(id.get(item)); - if (getItemStack(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } - - return names.toArray(new Identifier[0]); + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType != DataType.ITEM) return List.of(); + return EcoItems.INSTANCE.values() + .stream() + .map(x -> Identifier.fromNamespacedKey(id.get(x))) + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { - return id.namespace().equalsIgnoreCase("ecoitems") && isItem; + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + return id.namespace().equalsIgnoreCase("ecoitems") && dataType == DataType.ITEM; } } diff --git a/core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/ExecutableItemsDataProvider.java similarity index 50% rename from core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/ExecutableItemsDataProvider.java index 80fc25860..88a2dc943 100644 --- a/core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/ExecutableItemsDataProvider.java @@ -1,13 +1,15 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.ssomar.score.api.executableitems.ExecutableItemsAPI; import com.volmit.iris.Iris; -import com.volmit.iris.util.collection.KList; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.util.collection.KMap; -import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; import java.util.Optional; @@ -21,12 +23,6 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider { Iris.info("Setting up ExecutableItems Link..."); } - @NotNull - @Override - public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { - throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); - } - @NotNull @Override public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { @@ -35,30 +31,19 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider { .orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key())); } - @NotNull @Override - public Identifier[] getBlockTypes() { - return new Identifier[0]; - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - KList names = new KList<>(); - for (String name : ExecutableItemsAPI.getExecutableItemsManager().getExecutableItemIdsList()) { - try { - Identifier key = new Identifier("executable_items", name); - if (getItemStack(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } - - return names.toArray(new Identifier[0]); + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType != DataType.ITEM) return List.of(); + return ExecutableItemsAPI.getExecutableItemsManager() + .getExecutableItemIdsList() + .stream() + .map(name -> new Identifier("executable_items", name)) + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public boolean isValidProvider(@NotNull Identifier key, boolean isItem) { - return key.namespace().equalsIgnoreCase("executable_items") && isItem; + public boolean isValidProvider(@NotNull Identifier key, DataType dataType) { + return key.namespace().equalsIgnoreCase("executable_items") && dataType == DataType.ITEM; } } diff --git a/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/HMCLeavesDataProvider.java similarity index 81% rename from core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/HMCLeavesDataProvider.java index 5f5a358fd..bbf2cd197 100644 --- a/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/HMCLeavesDataProvider.java @@ -1,10 +1,11 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.engine.framework.Engine; -import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.data.IrisCustomData; import com.volmit.iris.util.reflect.WrappedField; @@ -18,6 +19,8 @@ import org.bukkit.block.data.type.Leaves; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.function.Supplier; @@ -89,41 +92,20 @@ public class HMCLeavesDataProvider extends ExternalDataProvider { } } - @NotNull @Override - public Identifier[] getBlockTypes() { - KList names = new KList<>(); - for (String name : blockDataMap.keySet()) { - try { - Identifier key = new Identifier("hmcleaves", name); - if (getBlockData(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } - - return names.toArray(new Identifier[0]); - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - KList names = new KList<>(); - for (String name : itemDataField.keySet()) { - try { - Identifier key = new Identifier("hmcleaves", name); - if (getItemStack(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } - - return names.toArray(new Identifier[0]); + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType == DataType.ENTITY) return List.of(); + return (dataType == DataType.BLOCK ? blockDataMap.keySet() : itemDataField.keySet()) + .stream() + .map(x -> new Identifier("hmcleaves", x)) + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { - return (isItem ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key()); + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; + return (dataType == DataType.ITEM ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key()); } private Map getMap(C config, String name) { diff --git a/core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java similarity index 59% rename from core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java index d7e891da0..c0bf27ef4 100644 --- a/core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java @@ -1,76 +1,76 @@ -package com.volmit.iris.core.link; - -import com.volmit.iris.Iris; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.collection.KMap; -import dev.lone.itemsadder.api.CustomBlock; -import dev.lone.itemsadder.api.CustomStack; -import org.bukkit.block.data.BlockData; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; - -import java.util.MissingResourceException; - -public class ItemAdderDataProvider extends ExternalDataProvider { - - private KList itemNamespaces, blockNamespaces; - - public ItemAdderDataProvider() { - super("ItemsAdder"); - } - - @Override - public void init() { - this.itemNamespaces = new KList<>(); - this.blockNamespaces = new KList<>(); - - for (Identifier i : getItemTypes()) { - itemNamespaces.addIfMissing(i.namespace()); - } - for (Identifier i : getBlockTypes()) { - blockNamespaces.addIfMissing(i.namespace()); - Iris.info("Found ItemAdder Block: " + i); - } - } - - @NotNull - @Override - public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { - return CustomBlock.getBaseBlockData(blockId.toString()); - } - - @NotNull - @Override - public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { - CustomStack stack = CustomStack.getInstance(itemId.toString()); - if (stack == null) { - throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); - } - return stack.getItemStack(); - } - - @NotNull - @Override - public Identifier[] getBlockTypes() { - KList keys = new KList<>(); - for (String s : CustomBlock.getNamespacedIdsInRegistry()) { - keys.add(Identifier.fromString(s)); - } - return keys.toArray(new Identifier[0]); - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - KList keys = new KList<>(); - for (String s : CustomStack.getNamespacedIdsInRegistry()) { - keys.add(Identifier.fromString(s)); - } - return keys.toArray(new Identifier[0]); - } - - @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { - return isItem ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace()); - } -} +package com.volmit.iris.core.link.data; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import dev.lone.itemsadder.api.CustomBlock; +import dev.lone.itemsadder.api.CustomStack; +import org.bukkit.block.data.BlockData; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.MissingResourceException; + +public class ItemAdderDataProvider extends ExternalDataProvider { + + private KList itemNamespaces, blockNamespaces; + + public ItemAdderDataProvider() { + super("ItemsAdder"); + } + + @Override + public void init() { + this.itemNamespaces = new KList<>(); + this.blockNamespaces = new KList<>(); + + for (Identifier i : getTypes(DataType.ITEM)) { + itemNamespaces.addIfMissing(i.namespace()); + } + for (Identifier i : getTypes(DataType.BLOCK)) { + blockNamespaces.addIfMissing(i.namespace()); + Iris.info("Found ItemAdder Block: " + i); + } + } + + @NotNull + @Override + public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { + return CustomBlock.getBaseBlockData(blockId.toString()); + } + + @NotNull + @Override + public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { + CustomStack stack = CustomStack.getInstance(itemId.toString()); + if (stack == null) { + throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); + } + return stack.getItemStack(); + } + + @Override + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + return switch (dataType) { + case ENTITY -> List.of(); + case ITEM -> CustomStack.getNamespacedIdsInRegistry() + .stream() + .map(Identifier::fromString) + .toList(); + case BLOCK -> CustomBlock.getNamespacedIdsInRegistry() + .stream() + .map(Identifier::fromString) + .toList(); + }; + } + + @Override + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; + return dataType == DataType.ITEM ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace()); + } +} diff --git a/core/src/main/java/com/volmit/iris/core/link/KGeneratorsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/KGeneratorsDataProvider.java similarity index 73% rename from core/src/main/java/com/volmit/iris/core/link/KGeneratorsDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/KGeneratorsDataProvider.java index 618fe4ccc..ea4f6e4ef 100644 --- a/core/src/main/java/com/volmit/iris/core/link/KGeneratorsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/KGeneratorsDataProvider.java @@ -1,5 +1,7 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KMap; @@ -14,6 +16,8 @@ import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; public class KGeneratorsDataProvider extends ExternalDataProvider { @@ -54,35 +58,17 @@ public class KGeneratorsDataProvider extends ExternalDataProvider { } @Override - public @NotNull Identifier[] getBlockTypes() { + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType == DataType.ENTITY) return List.of(); return Main.getGenerators().getAll().stream() .map(gen -> new Identifier("kgenerators", gen.getId())) - .filter(i -> { - try { - return getBlockData(i) != null; - } catch (MissingResourceException e) { - return false; - } - }) - .toArray(Identifier[]::new); + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public @NotNull Identifier[] getItemTypes() { - return Main.getGenerators().getAll().stream() - .map(gen -> new Identifier("kgenerators", gen.getId())) - .filter(i -> { - try { - return getItemStack(i) != null; - } catch (MissingResourceException e) { - return false; - } - }) - .toArray(Identifier[]::new); - } - - @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; return "kgenerators".equalsIgnoreCase(id.namespace()); } } diff --git a/core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/MMOItemsDataProvider.java similarity index 64% rename from core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/MMOItemsDataProvider.java index 251665a54..0bf3fc490 100644 --- a/core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/MMOItemsDataProvider.java @@ -1,21 +1,24 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; -import com.volmit.iris.util.collection.KList; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.scheduling.J; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.ItemTier; -import net.Indyuce.mmoitems.api.Type; import net.Indyuce.mmoitems.api.block.CustomBlock; import org.bukkit.Bukkit; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; public class MMOItemsDataProvider extends ExternalDataProvider { @@ -85,52 +88,35 @@ public class MMOItemsDataProvider extends ExternalDataProvider { return item; } - @NotNull @Override - public Identifier[] getBlockTypes() { - KList names = new KList<>(); - for (Integer id : api().getCustomBlocks().getBlockIds()) { - try { - Identifier key = new Identifier("mmoitems", String.valueOf(id)); - if (getBlockData(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } - return names.toArray(new Identifier[0]); - } + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + return switch (dataType) { + case ENTITY -> List.of(); + case BLOCK -> api().getCustomBlocks().getBlockIds().stream().map(id -> new Identifier("mmoitems", String.valueOf(id))) + .filter(dataType.asPredicate(this)) + .toList(); + case ITEM -> { + Supplier> supplier = () -> api().getTypes() + .getAll() + .stream() + .flatMap(type -> api() + .getTemplates() + .getTemplateNames(type) + .stream() + .map(name -> new Identifier("mmoitems_" + type.getId(), name))) + .filter(dataType.asPredicate(this)) + .toList(); - @NotNull - @Override - public Identifier[] getItemTypes() { - KList names = new KList<>(); - Runnable run = () -> { - for (Type type : api().getTypes().getAll()) { - for (String name : api().getTemplates().getTemplateNames(type)) { - try { - Identifier key = new Identifier("mmoitems_" + type.getId(), name); - if (getItemStack(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } + if (Bukkit.isPrimaryThread()) yield supplier.get(); + else yield J.sfut(supplier).join(); } }; - if (Bukkit.isPrimaryThread()) run.run(); - else { - try { - J.sfut(run).get(); - } catch (InterruptedException | ExecutionException e) { - Iris.error("Failed getting MMOItems item types!"); - Iris.reportError(e); - } - } - return names.toArray(new Identifier[0]); } @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { - return isItem ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems"); + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; + return dataType == DataType.ITEM ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems"); } private MMOItems api() { diff --git a/core/src/main/java/com/volmit/iris/core/link/MythicCrucibleDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/MythicCrucibleDataProvider.java similarity index 64% rename from core/src/main/java/com/volmit/iris/core/link/MythicCrucibleDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/MythicCrucibleDataProvider.java index d62462c38..4194f0c16 100644 --- a/core/src/main/java/com/volmit/iris/core/link/MythicCrucibleDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/MythicCrucibleDataProvider.java @@ -16,19 +16,18 @@ * along with this program. If not, see . */ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.service.ExternalDataSVC; -import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.framework.Engine; -import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.IrisCustomData; -import com.volmit.iris.util.math.RNG; import io.lumine.mythic.bukkit.BukkitAdapter; import io.lumine.mythic.bukkit.utils.serialize.Chroma; import io.lumine.mythiccrucible.MythicCrucible; @@ -37,11 +36,11 @@ import io.lumine.mythiccrucible.items.ItemManager; import io.lumine.mythiccrucible.items.blocks.CustomBlockItemContext; import io.lumine.mythiccrucible.items.furniture.FurnitureItemContext; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; import java.util.MissingResourceException; import java.util.Optional; @@ -88,69 +87,27 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider { .generateItemStack(1)); } - @NotNull @Override - public Identifier[] getBlockTypes() { - KList names = new KList<>(); - for (CrucibleItem item : this.itemManager.getItems()) { - if (item.getBlockData() == null) continue; - try { - Identifier key = new Identifier("crucible", item.getInternalName()); - if (getBlockData(key) != null) { - Iris.info("getBlockTypes: Block loaded '" + item.getInternalName() + "'"); - names.add(key); - } - } catch (MissingResourceException ignored) {} - } - return names.toArray(new Identifier[0]); - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - KList names = new KList<>(); - for (CrucibleItem item : this.itemManager.getItems()) { - try { - Identifier key = new Identifier("crucible", item.getInternalName()); - if (getItemStack(key) != null) { - Iris.info("getItemTypes: Item loaded '" + item.getInternalName() + "'"); - names.add(key); - } - } catch (MissingResourceException ignored) {} - } - return names.toArray(new Identifier[0]); + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + return itemManager.getItems() + .stream() + .map(i -> new Identifier("crucible", i.getInternalName())) + .filter(dataType.asPredicate(this)) + .toList(); } @Override public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) { - var pair = ExternalDataSVC.parseState(blockId); - var state = pair.getB(); - blockId = pair.getA(); + var parsedState = ExternalDataSVC.parseState(blockId); + var state = parsedState.getB(); + blockId = parsedState.getA(); Optional item = itemManager.getItem(blockId.key()); if (item.isEmpty()) return; FurnitureItemContext furniture = item.get().getFurnitureData(); if (furniture == null) return; - float yaw = 0; - BlockFace face = BlockFace.NORTH; - long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY(); - RNG rng = new RNG(seed); - if ("true".equals(state.get("randomYaw"))) { - yaw = rng.f(0, 360); - } else if (state.containsKey("yaw")) { - yaw = Float.parseFloat(state.get("yaw")); - } - if ("true".equals(state.get("randomFace"))) { - BlockFace[] faces = BlockFace.values(); - face = faces[rng.i(0, faces.length - 1)]; - } else if (state.containsKey("face")) { - face = BlockFace.valueOf(state.get("face").toUpperCase()); - } - if (face == BlockFace.SELF) { - face = BlockFace.NORTH; - } - + var pair = parseYawAndFace(engine, block, state); BiomeColor type = null; Chroma color = null; try { @@ -161,11 +118,12 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider { if (biomeColor == null) return; color = Chroma.of(biomeColor.getRGB()); } - furniture.place(block, face, yaw, color); + furniture.place(block, pair.getB(), pair.getA(), color); } @Override - public boolean isValidProvider(@NotNull Identifier key, boolean isItem) { + public boolean isValidProvider(@NotNull Identifier key, DataType dataType) { + if (dataType == DataType.ENTITY) return false; return key.namespace().equalsIgnoreCase("crucible"); } } diff --git a/core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java b/core/src/main/java/com/volmit/iris/core/link/data/MythicMobsDataProvider.java similarity index 54% rename from core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java rename to core/src/main/java/com/volmit/iris/core/link/data/MythicMobsDataProvider.java index 052952346..7c08b8e6a 100644 --- a/core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/MythicMobsDataProvider.java @@ -1,25 +1,7 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +package com.volmit.iris.core.link.data; -package com.volmit.iris.core.link; - -import com.google.common.collect.Sets; -import com.volmit.iris.Iris; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.tools.IrisToolbelt; import io.lumine.mythic.api.adapters.AbstractLocation; import io.lumine.mythic.api.config.MythicLineConfig; @@ -30,60 +12,59 @@ import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent; import io.lumine.mythic.core.skills.SkillCondition; import io.lumine.mythic.core.utils.annotations.MythicCondition; import io.lumine.mythic.core.utils.annotations.MythicField; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; -public class MythicMobsLink { - - public MythicMobsLink() { - if (getPlugin() == null) return; - Iris.instance.registerListener(new ConditionListener()); +public class MythicMobsDataProvider extends ExternalDataProvider { + public MythicMobsDataProvider() { + super("MythicMobs"); } - public boolean isEnabled() { - return getPlugin() != null; + @Override + public void init() { } - public Plugin getPlugin() { - return Bukkit.getPluginManager().getPlugin("MythicMobs"); + @Override + public @Nullable Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException { + var mm = MythicBukkit.inst().getMobManager().spawnMob(entityId.key(), location); + if (mm == null) throw new MissingResourceException("Failed to find mob!", entityId.namespace(), entityId.key()); + return mm.getEntity().getBukkitEntity(); } - /** - * Spawn a mythic mob at this location - * - * @param mob The mob - * @param location The location - * @return The mob, or null if it can't be spawned - */ - public @Nullable Entity spawnMob(String mob, Location location) { - return isEnabled() ? MythicBukkit.inst().getMobManager().spawnMob(mob, location).getEntity().getBukkitEntity() : null; + @Override + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType != DataType.ENTITY) return List.of(); + return MythicBukkit.inst() + .getMobManager() + .getMobNames() + .stream() + .map(name -> new Identifier("mythicmobs", name)) + .toList(); } - public Collection getMythicMobTypes() { - return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : List.of(); + @Override + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + return id.namespace().equalsIgnoreCase("mythicmobs") && dataType == DataType.ENTITY; } - private static class ConditionListener implements Listener { - @EventHandler - public void on(MythicConditionLoadEvent event) { - switch (event.getConditionName()) { - case "irisbiome" -> event.register(new IrisBiomeCondition(event.getConditionName(), event.getConfig())); - case "irisregion" -> event.register(new IrisRegionCondition(event.getConditionName(), event.getConfig())); - } + @EventHandler + public void on(MythicConditionLoadEvent event) { + switch (event.getConditionName()) { + case "irisbiome" -> event.register(new IrisBiomeCondition(event.getConditionName(), event.getConfig())); + case "irisregion" -> event.register(new IrisRegionCondition(event.getConditionName(), event.getConfig())); } } @MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes") public static class IrisBiomeCondition extends SkillCondition implements ILocationCondition { @MythicField(name = "biome", aliases = {"b"}, description = "A list of biomes to check") - private Set biomes = Sets.newConcurrentHashSet(); + private Set biomes = ConcurrentHashMap.newKeySet(); @MythicField(name = "surface", aliases = {"s"}, description = "If the biome check should only be performed on the surface") private boolean surface; @@ -107,10 +88,10 @@ public class MythicMobsLink { } } - @MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes") + @MythicCondition(author = "CrazyDev22", name = "irisregion", description = "Tests if the target is within the given list of biomes") public static class IrisRegionCondition extends SkillCondition implements ILocationCondition { @MythicField(name = "region", aliases = {"r"}, description = "A list of regions to check") - private Set regions = Sets.newConcurrentHashSet(); + private Set regions = ConcurrentHashMap.newKeySet(); public IrisRegionCondition(String line, MythicLineConfig mlc) { super(line); diff --git a/core/src/main/java/com/volmit/iris/core/link/NexoDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/NexoDataProvider.java similarity index 63% rename from core/src/main/java/com/volmit/iris/core/link/NexoDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/NexoDataProvider.java index 066fb448b..998fbf06f 100644 --- a/core/src/main/java/com/volmit/iris/core/link/NexoDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/NexoDataProvider.java @@ -1,28 +1,30 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.nexomc.nexo.api.NexoBlocks; import com.nexomc.nexo.api.NexoFurniture; import com.nexomc.nexo.api.NexoItems; import com.nexomc.nexo.items.ItemBuilder; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.service.ExternalDataSVC; -import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.IrisCustomData; -import com.volmit.iris.util.math.RNG; import org.bukkit.Color; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.entity.ItemDisplay; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.inventory.meta.MapMeta; import org.bukkit.inventory.meta.PotionMeta; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; import java.util.concurrent.atomic.AtomicBoolean; @@ -69,9 +71,9 @@ public class NexoDataProvider extends ExternalDataProvider { @Override public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) { - var pair = ExternalDataSVC.parseState(blockId); - var state = pair.getB(); - blockId = pair.getA(); + var statePair = ExternalDataSVC.parseState(blockId); + var state = statePair.getB(); + blockId = statePair.getA(); if (NexoBlocks.isCustomBlock(blockId.key())) { NexoBlocks.place(blockId.key(), block.getLocation()); @@ -81,26 +83,8 @@ public class NexoDataProvider extends ExternalDataProvider { if (!NexoFurniture.isFurniture(blockId.key())) return; - float yaw = 0; - BlockFace face = BlockFace.NORTH; - - long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY(); - RNG rng = new RNG(seed); - if ("true".equals(state.get("randomYaw"))) { - yaw = rng.f(0, 360); - } else if (state.containsKey("yaw")) { - yaw = Float.parseFloat(state.get("yaw")); - } - if ("true".equals(state.get("randomFace"))) { - BlockFace[] faces = BlockFace.values(); - face = faces[rng.i(0, faces.length - 1)]; - } else if (state.containsKey("face")) { - face = BlockFace.valueOf(state.get("face").toUpperCase()); - } - if (face == BlockFace.SELF) { - face = BlockFace.NORTH; - } - ItemDisplay display = NexoFurniture.place(blockId.key(), block.getLocation(), yaw, face); + var pair = parseYawAndFace(engine, block, state); + ItemDisplay display = NexoFurniture.place(blockId.key(), block.getLocation(), pair.getA(), pair.getB()); if (display == null) return; ItemStack itemStack = display.getItemStack(); if (itemStack == null) return; @@ -114,46 +98,31 @@ public class NexoDataProvider extends ExternalDataProvider { var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type); if (biomeColor == null) return; var potionColor = Color.fromARGB(biomeColor.getAlpha(), biomeColor.getRed(), biomeColor.getGreen(), biomeColor.getBlue()); - if (itemStack.getItemMeta() instanceof PotionMeta meta) { - meta.setColor(potionColor); - itemStack.setItemMeta(meta); + var meta = itemStack.getItemMeta(); + switch (meta) { + case LeatherArmorMeta armor -> armor.setColor(potionColor); + case PotionMeta potion -> potion.setColor(potionColor); + case MapMeta map -> map.setColor(potionColor); + case null, default -> {} } + itemStack.setItemMeta(meta); } display.setItemStack(itemStack); } - @NotNull @Override - public Identifier[] getBlockTypes() { - return NexoItems.itemNames().stream() + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType == DataType.ENTITY) return List.of(); + return NexoItems.itemNames() + .stream() .map(i -> new Identifier("nexo", i)) - .filter(i -> { - try { - return getBlockData(i) != null; - } catch (MissingResourceException e) { - return false; - } - }) - .toArray(Identifier[]::new); - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - return NexoItems.itemNames().stream() - .map(i -> new Identifier("nexo", i)) - .filter(i -> { - try { - return getItemStack(i) != null; - } catch (MissingResourceException e) { - return false; - } - }) - .toArray(Identifier[]::new); + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; return "nexo".equalsIgnoreCase(id.namespace()); } diff --git a/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java b/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java index d856d2b8e..50ff64886 100644 --- a/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java +++ b/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java @@ -19,9 +19,12 @@ package com.volmit.iris.core.project; import com.volmit.iris.Iris; +import com.volmit.iris.core.link.Identifier; +import com.volmit.iris.core.link.data.DataType; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.loader.ResourceLoader; +import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -39,7 +42,6 @@ import java.lang.reflect.Modifier; import java.util.List; import java.util.Map; import java.util.function.Function; -import java.util.stream.Collectors; public class SchemaBuilder { private static final String SYMBOL_LIMIT__N = "*"; @@ -266,16 +268,18 @@ public class SchemaBuilder { if (!definitions.containsKey(key)) { JSONObject j = new JSONObject(); - KList list = new KList<>(); - list.addAll(Iris.linkMythicMobs.getMythicMobTypes().stream().map(s -> "MythicMobs:" + s).collect(Collectors.toList())); - //TODO add Citizens stuff here too + KList list = Iris.service(ExternalDataSVC.class) + .getAllIdentifiers(DataType.ENTITY) + .stream() + .map(Identifier::toString) + .collect(KList.collector()); j.put("enum", list.toJSONStringArray()); definitions.put(key, j); } - fancyType = "Mythic Mob Type"; + fancyType = "Custom Mob Type"; prop.put("$ref", "#/definitions/" + key); - description.add(SYMBOL_TYPE__N + " Must be a valid Mythic Mob Type (use ctrl+space for auto complete!) Define mythic mobs with the mythic mobs plugin configuration files."); + description.add(SYMBOL_TYPE__N + " Must be a valid Custom Mob Type (use ctrl+space for auto complete!)"); } else if (k.isAnnotationPresent(RegistryListFont.class)) { String key = "enum-font"; diff --git a/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java b/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java index 4d9596278..69fec1912 100644 --- a/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java @@ -20,16 +20,21 @@ package com.volmit.iris.core.service; import com.volmit.iris.Iris; import com.volmit.iris.core.link.*; +import com.volmit.iris.core.link.data.DataType; import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.io.JarScanner; import com.volmit.iris.util.plugin.IrisService; +import com.volmit.iris.util.scheduling.J; import lombok.Data; import lombok.NonNull; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.inventory.ItemStack; @@ -47,43 +52,12 @@ public class ExternalDataSVC implements IrisService { Iris.info("Loading ExternalDataProvider..."); Bukkit.getPluginManager().registerEvents(this, Iris.instance); - providers.add(new NexoDataProvider()); - if (Bukkit.getPluginManager().getPlugin("Nexo") != null) { - Iris.info("Nexo found, loading NexoDataProvider..."); - } - providers.add(new MythicCrucibleDataProvider()); - if (Bukkit.getPluginManager().getPlugin("MythicCrucible") != null) { - Iris.info("MythicCrucible found, loading MythicCrucibleDataProvider..."); - } - providers.add(new ItemAdderDataProvider()); - if (Bukkit.getPluginManager().getPlugin("ItemAdder") != null) { - Iris.info("ItemAdder found, loading ItemAdderDataProvider..."); - } - providers.add(new ExecutableItemsDataProvider()); - if (Bukkit.getPluginManager().getPlugin("ExecutableItems") != null) { - Iris.info("ExecutableItems found, loading ExecutableItemsDataProvider..."); - } - providers.add(new HMCLeavesDataProvider()); - if (Bukkit.getPluginManager().getPlugin("HMCLeaves") != null) { - Iris.info("BlockAdder found, loading HMCLeavesDataProvider..."); - } - providers.add(new MMOItemsDataProvider()); - if (Bukkit.getPluginManager().getPlugin("MMOItems") != null) { - Iris.info("MMOItems found, loading MMOItemsDataProvider..."); - } - providers.add(new EcoItemsDataProvider()); - if (Bukkit.getPluginManager().getPlugin("EcoItems") != null) { - Iris.info("EcoItems found, loading EcoItemsDataProvider..."); - } - providers.add(new KGeneratorsDataProvider()); - if (Bukkit.getPluginManager().getPlugin("KGenerators") != null) { - Iris.info("KGenerators found, loading KGeneratorsDataProvider..."); - } - + providers.addAll(createProviders()); for (ExternalDataProvider p : providers) { if (p.isReady()) { activeProviders.add(p); p.init(); + Iris.instance.registerListener(p); Iris.info("Enabled ExternalDataProvider for %s.", p.getPluginId()); } } @@ -99,6 +73,7 @@ public class ExternalDataSVC implements IrisService { providers.stream().filter(p -> p.isReady() && p.getPlugin().equals(e.getPlugin())).findFirst().ifPresent(edp -> { activeProviders.add(edp); edp.init(); + Iris.instance.registerListener(edp); Iris.info("Enabled ExternalDataProvider for %s.", edp.getPluginId()); }); } @@ -113,6 +88,7 @@ public class ExternalDataSVC implements IrisService { if (provider.isReady()) { activeProviders.add(provider); provider.init(); + Iris.instance.registerListener(provider); } } @@ -120,7 +96,7 @@ public class ExternalDataSVC implements IrisService { var pair = parseState(key); Identifier mod = pair.getA(); - Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(mod, false)).findFirst(); + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(mod, DataType.BLOCK)).findFirst(); if (provider.isEmpty()) return Optional.empty(); try { @@ -132,7 +108,7 @@ public class ExternalDataSVC implements IrisService { } public Optional getItemStack(Identifier key, KMap customNbt) { - Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, true)).findFirst(); + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.ITEM)).findFirst(); if (provider.isEmpty()) { Iris.warn("No matching Provider found for modded material \"%s\"!", key); return Optional.empty(); @@ -146,7 +122,7 @@ public class ExternalDataSVC implements IrisService { } public void processUpdate(Engine engine, Block block, Identifier blockId) { - Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(blockId, false)).findFirst(); + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(blockId, DataType.BLOCK)).findFirst(); if (provider.isEmpty()) { Iris.warn("No matching Provider found for modded material \"%s\"!", blockId); return; @@ -154,16 +130,24 @@ public class ExternalDataSVC implements IrisService { provider.get().processUpdate(engine, block, blockId); } - public Identifier[] getAllBlockIdentifiers() { - KList names = new KList<>(); - activeProviders.forEach(p -> names.add(p.getBlockTypes())); - return names.toArray(new Identifier[0]); + public Entity spawnMob(Location location, Identifier mobId) { + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(mobId, DataType.ENTITY)).findFirst(); + if (provider.isEmpty()) { + Iris.warn("No matching Provider found for modded mob \"%s\"!", mobId); + return null; + } + try { + return provider.get().spawnMob(location, mobId); + } catch (MissingResourceException e) { + Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]"); + return null; + } } - public Identifier[] getAllItemIdentifiers() { - KList names = new KList<>(); - activeProviders.forEach(p -> names.add(p.getItemTypes())); - return names.toArray(new Identifier[0]); + public Collection getAllIdentifiers(DataType dataType) { + return activeProviders.stream() + .flatMap(p -> p.getTypes(dataType).stream()) + .toList(); } public static Pair> parseState(Identifier key) { @@ -188,4 +172,21 @@ public class ExternalDataSVC implements IrisService { .collect(Collectors.joining(",", key.key() + "[", "]")); return new Identifier(key.namespace(), path); } + + private static KList createProviders() { + JarScanner jar = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.core.link.data"); + J.attempt(jar::scan); + KList providers = new KList<>(); + + for (Class c : jar.getClasses()) { + if (ExternalDataProvider.class.isAssignableFrom(c)) { + try { + ExternalDataProvider p = (ExternalDataProvider) c.getDeclaredConstructor().newInstance(); + if (p.getPlugin() != null) Iris.info(p.getPluginId() + " found, loading " + c.getSimpleName() + "..."); + providers.add(p); + } catch (Throwable ignored) {} + } + } + return providers; + } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java index dfb2508d0..a87c319d0 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java @@ -20,8 +20,10 @@ package com.volmit.iris.engine.object; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; @@ -455,24 +457,13 @@ public class IrisEntity extends IrisRegistrant { } if (isSpecialType()) { - if (specialType.toLowerCase().startsWith("mythicmobs:")) { - return Iris.linkMythicMobs.spawnMob(specialType.substring(11), at); - } else { - Iris.warn("Invalid mob type to spawn: '" + specialType + "'!"); - return null; - } + return Iris.service(ExternalDataSVC.class).spawnMob(at, Identifier.fromString(specialType)); } return INMS.get().spawnEntity(at, getType(), getReason()); } - public boolean isCitizens() { - return false; - - // TODO: return Iris.linkCitizens.supported() && someType is not empty; - } - public boolean isSpecialType() { return specialType != null && !specialType.equals(""); } diff --git a/core/src/main/java/com/volmit/iris/util/data/B.java b/core/src/main/java/com/volmit/iris/util/data/B.java index 1c7a521cb..7e71d39f3 100644 --- a/core/src/main/java/com/volmit/iris/util/data/B.java +++ b/core/src/main/java/com/volmit/iris/util/data/B.java @@ -21,6 +21,7 @@ package com.volmit.iris.util.data; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.link.Identifier; +import com.volmit.iris.core.link.data.DataType; import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -673,7 +674,7 @@ public class B { } } - for (Identifier id : Iris.service(ExternalDataSVC.class).getAllBlockIdentifiers()) + for (Identifier id : Iris.service(ExternalDataSVC.class).getAllIdentifiers(DataType.BLOCK)) bt.add(id.toString()); bt.addAll(custom.k()); @@ -688,7 +689,7 @@ public class B { bt.add(v); } - for (Identifier id : Iris.service(ExternalDataSVC.class).getAllItemIdentifiers()) + for (Identifier id : Iris.service(ExternalDataSVC.class).getAllIdentifiers(DataType.ITEM)) bt.add(id.toString()); return bt.toArray(new String[0]); diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/J.java b/core/src/main/java/com/volmit/iris/util/scheduling/J.java index a669317df..550b94092 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/J.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/J.java @@ -240,6 +240,21 @@ public class J { return f; } + public static CompletableFuture sfut(Supplier r) { + CompletableFuture f = new CompletableFuture<>(); + if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { + return null; + } + Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> { + try { + f.complete(r.get()); + } catch (Throwable e) { + f.completeExceptionally(e); + } + }); + return f; + } + public static CompletableFuture sfut(Runnable r, int delay) { CompletableFuture f = new CompletableFuture(); From 387e8adfe2639de66464fed00ed7b584c58b9433 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 12 Jul 2025 18:10:39 +0200 Subject: [PATCH 11/36] ignore errors when scanning for external data providers --- .../main/java/com/volmit/iris/core/service/ExternalDataSVC.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java b/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java index 69fec1912..49303b60c 100644 --- a/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java @@ -174,7 +174,7 @@ public class ExternalDataSVC implements IrisService { } private static KList createProviders() { - JarScanner jar = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.core.link.data"); + JarScanner jar = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.core.link.data", false); J.attempt(jar::scan); KList providers = new KList<>(); From 106a3834ab96707a19a46c4a21633a642555b556 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 13 Jul 2025 17:42:10 +0200 Subject: [PATCH 12/36] fix iris create command failing --- .../iris/core/commands/CommandIris.java | 1279 ++++++++--------- 1 file changed, 631 insertions(+), 648 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 4723ed3e1..38e2266e3 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -1,648 +1,631 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris.core.commands; - -import com.volmit.iris.Iris; -import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.loader.IrisData; -import com.volmit.iris.core.nms.INMS; -import com.volmit.iris.core.pregenerator.ChunkUpdater; -import com.volmit.iris.core.service.StudioSVC; -import com.volmit.iris.core.tools.IrisToolbelt; -import com.volmit.iris.engine.framework.Engine; -import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.core.safeguard.UtilsSFG; -import com.volmit.iris.engine.object.IrisWorld; -import com.volmit.iris.engine.platform.BukkitChunkGenerator; -import com.volmit.iris.engine.platform.DummyChunkGenerator; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.decree.DecreeExecutor; -import com.volmit.iris.util.decree.DecreeOrigin; -import com.volmit.iris.util.decree.annotations.Decree; -import com.volmit.iris.util.decree.annotations.Param; -import com.volmit.iris.util.decree.specialhandlers.NullablePlayerHandler; -import com.volmit.iris.util.format.C; -import com.volmit.iris.util.format.Form; -import com.volmit.iris.util.plugin.VolmitSender; -import com.volmit.iris.util.scheduling.J; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.WorldCreator; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.generator.ChunkGenerator; -import org.bukkit.scheduler.BukkitRunnable; - -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.List; - -import static com.volmit.iris.Iris.service; -import static com.volmit.iris.core.service.EditSVC.deletingWorld; -import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode; -import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities; -import static org.bukkit.Bukkit.getServer; - -@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command") -public class CommandIris implements DecreeExecutor { - private CommandStudio studio; - private CommandPregen pregen; - private CommandSettings settings; - private CommandObject object; - private CommandJigsaw jigsaw; - private CommandWhat what; - private CommandEdit edit; - private CommandFind find; - private CommandDeveloper developer; - public static boolean worldCreation = false; - String WorldEngine; - String worldNameToCheck = "YourWorldName"; - VolmitSender sender = Iris.getSender(); - - @Decree(description = "Create a new world", aliases = {"+", "c"}) - public void create( - @Param(aliases = "world-name", description = "The name of the world to create") - String name, - @Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default") - IrisDimension type, - @Param(description = "The seed to generate the world with", defaultValue = "1337") - long seed - ) { - if(sender() instanceof Player) { - if (incompatibilities.get("Multiverse-Core")) { - sender().sendMessage(C.RED + "Your server has an incompatibility that may corrupt all worlds on the server if not handled properly."); - sender().sendMessage(C.RED + "it is strongly advised for you to take action. see log for full detail"); - sender().sendMessage(C.RED + "----------------------------------------------------------------"); - sender().sendMessage(C.RED + "Command ran: /iris create"); - sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings()); - sender().sendMessage(C.RED + "----------------------------------------------------------------"); - } - if (unstablemode && !incompatibilities.get("Multiverse-Core")) { - sender().sendMessage(C.RED + "Your server is experiencing an incompatibility with the Iris plugin."); - sender().sendMessage(C.RED + "Please rectify this problem to avoid further complications."); - sender().sendMessage(C.RED + "----------------------------------------------------------------"); - sender().sendMessage(C.RED + "Command ran: /iris create"); - sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings()); - sender().sendMessage(C.RED + "----------------------------------------------------------------"); - } - } - if (name.equals("iris")) { - sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds."); - sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); - return; - } - if (name.equals("Benchmark")) { - sender().sendMessage(C.RED + "You cannot use the world name \"Benchmark\" for creating worlds as Iris uses this directory for Benchmarking Packs."); - sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); - return; - } - - if (new File(Bukkit.getWorldContainer(), name).exists()) { - sender().sendMessage(C.RED + "That folder already exists!"); - return; - } - - try { - worldCreation = true; - IrisToolbelt.createWorld() - .dimension(type.getLoadKey()) - .name(name) - .seed(seed) - .sender(sender()) - .studio(false) - .create(); - } catch (Throwable e) { - sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details."); - Iris.error("Exception raised during world creation: " + e.getMessage()); - Iris.reportError(e); - worldCreation = false; - return; - } - worldCreation = false; - sender().sendMessage(C.GREEN + "Successfully created your world!"); - } - - @Decree(description = "Teleport to another world", aliases = {"tp"}, sync = true) - public void teleport( - @Param(description = "World to teleport to") - World world, - @Param(description = "Player to teleport", defaultValue = "---", customHandler = NullablePlayerHandler.class) - Player player - ) { - if (player == null && sender().isPlayer()) - player = sender().player(); - - final Player target = player; - if (target == null) { - sender().sendMessage(C.RED + "The specified player does not exist."); - return; - } - - new BukkitRunnable() { - @Override - public void run() { - target.teleport(world.getSpawnLocation()); - new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + "."); - } - }.runTask(Iris.instance); - } - - @Decree(description = "Print version information") - public void version() { - sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software"); - } - - /* - /todo - @Decree(description = "Benchmark a pack", origin = DecreeOrigin.CONSOLE) - public void packbenchmark( - @Param(description = "Dimension to benchmark") - IrisDimension type - ) throws InterruptedException { - - BenchDimension = type.getLoadKey(); - - IrisPackBenchmarking.runBenchmark(); - } */ - - @Decree(description = "Print world height information", origin = DecreeOrigin.PLAYER) - public void height() { - if (sender().isPlayer()) { - sender().sendMessage(C.GREEN + "" + sender().player().getWorld().getMinHeight() + " to " + sender().player().getWorld().getMaxHeight()); - sender().sendMessage(C.GREEN + "Total Height: " + (sender().player().getWorld().getMaxHeight() - sender().player().getWorld().getMinHeight())); - } else { - World mainWorld = getServer().getWorlds().get(0); - Iris.info(C.GREEN + "" + mainWorld.getMinHeight() + " to " + mainWorld.getMaxHeight()); - Iris.info(C.GREEN + "Total Height: " + (mainWorld.getMaxHeight() - mainWorld.getMinHeight())); - } - } - - @Decree(description = "QOL command to open a overworld studio world.", sync = true) - public void so() { - sender().sendMessage(C.GREEN + "Opening studio for the \"Overworld\" pack (seed: 1337)"); - Iris.service(StudioSVC.class).open(sender(), 1337, "overworld"); - } - - @Decree(description = "Check access of all worlds.", aliases = {"accesslist"}) - public void worlds() { - KList IrisWorlds = new KList<>(); - KList BukkitWorlds = new KList<>(); - - for (World w : Bukkit.getServer().getWorlds()) { - try { - Engine engine = IrisToolbelt.access(w).getEngine(); - if (engine != null) { - IrisWorlds.add(w); - } - } catch (Exception e) { - BukkitWorlds.add(w); - } - } - - if (sender().isPlayer()) { - sender().sendMessage(C.BLUE + "Iris Worlds: "); - for (World IrisWorld : IrisWorlds.copy()) { - sender().sendMessage(C.IRIS + "- " +IrisWorld.getName()); - } - sender().sendMessage(C.GOLD + "Bukkit Worlds: "); - for (World BukkitWorld : BukkitWorlds.copy()) { - sender().sendMessage(C.GRAY + "- " +BukkitWorld.getName()); - } - } else { - Iris.info(C.BLUE + "Iris Worlds: "); - for (World IrisWorld : IrisWorlds.copy()) { - Iris.info(C.IRIS + "- " +IrisWorld.getName()); - } - Iris.info(C.GOLD + "Bukkit Worlds: "); - for (World BukkitWorld : BukkitWorlds.copy()) { - Iris.info(C.GRAY + "- " +BukkitWorld.getName()); - } - - } - } - - @Decree(description = "Remove an Iris world", aliases = {"del", "rm", "delete"}, sync = true) - public void remove( - @Param(description = "The world to remove") - World world, - @Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true") - boolean delete - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); - return; - } - sender().sendMessage(C.GREEN + "Removing world: " + world.getName()); - - if (!IrisToolbelt.evacuate(world)) { - sender().sendMessage(C.RED + "Failed to evacuate world: " + world.getName()); - return; - } - - if (!Bukkit.unloadWorld(world, false)) { - sender().sendMessage(C.RED + "Failed to unload world: " + world.getName()); - return; - } - - try { - if (IrisToolbelt.removeWorld(world)) { - sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml"); - } else { - sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml"); - } - } catch (IOException e) { - sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage()); - e.printStackTrace(); - } - IrisToolbelt.evacuate(world, "Deleting world"); - deletingWorld = true; - if (!delete) { - deletingWorld = false; - return; - } - VolmitSender sender = sender(); - J.a(() -> { - int retries = 12; - - if (deleteDirectory(world.getWorldFolder())) { - sender.sendMessage(C.GREEN + "Successfully removed world folder"); - } else { - while(true){ - if (deleteDirectory(world.getWorldFolder())){ - sender.sendMessage(C.GREEN + "Successfully removed world folder"); - break; - } - retries--; - if (retries == 0){ - sender.sendMessage(C.RED + "Failed to remove world folder"); - break; - } - J.sleep(3000); - } - } - deletingWorld = false; - }); - } - - public static boolean deleteDirectory(File dir) { - if (dir.isDirectory()) { - File[] children = dir.listFiles(); - for (int i = 0; i < children.length; i++) { - boolean success = deleteDirectory(children[i]); - if (!success) { - return false; - } - } - } - return dir.delete(); - } - - @Decree(description = "Updates all chunk in the specified world") - public void updater( - @Param(description = "World to update chunks at") - World world - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.GOLD + "This is not an Iris world"); - return; - } - ChunkUpdater updater = new ChunkUpdater(world); - if (sender().isPlayer()) { - sender().sendMessage(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); - } else { - Iris.info(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); - } - updater.start(); - } - - @Decree(description = "Set aura spins") - public void aura( - @Param(description = "The h color value", defaultValue = "-20") - int h, - @Param(description = "The s color value", defaultValue = "7") - int s, - @Param(description = "The b color value", defaultValue = "8") - int b - ) { - IrisSettings.get().getGeneral().setSpinh(h); - IrisSettings.get().getGeneral().setSpins(s); - IrisSettings.get().getGeneral().setSpinb(b); - IrisSettings.get().forceSave(); - sender().sendMessage("Aura Spins updated to " + h + " " + s + " " + b); - } - - @Decree(description = "Bitwise calculations") - public void bitwise( - @Param(description = "The first value to run calculations on") - int value1, - @Param(description = "The operator: | & ^ ≺≺ ≻≻ %") - String operator, - @Param(description = "The second value to run calculations on") - int value2 - ) { - Integer v = null; - switch (operator) { - case "|" -> v = value1 | value2; - case "&" -> v = value1 & value2; - case "^" -> v = value1 ^ value2; - case "%" -> v = value1 % value2; - case ">>" -> v = value1 >> value2; - case "<<" -> v = value1 << value2; - } - if (v == null) { - sender().sendMessage(C.RED + "The operator you entered: (" + operator + ") is invalid!"); - return; - } - sender().sendMessage(C.GREEN + "" + value1 + " " + C.GREEN + operator.replaceAll("<", "≺").replaceAll(">", "≻").replaceAll("%", "%") + " " + C.GREEN + value2 + C.GREEN + " returns " + C.GREEN + v); - } - - @Decree(description = "Toggle debug") - public void debug( - @Param(name = "on", description = "Whether or not debug should be on", defaultValue = "other") - Boolean on - ) { - boolean to = on == null ? !IrisSettings.get().getGeneral().isDebug() : on; - IrisSettings.get().getGeneral().setDebug(to); - IrisSettings.get().forceSave(); - sender().sendMessage(C.GREEN + "Set debug to: " + to); - } - - @Decree(description = "Download a project.", aliases = "dl") - public void download( - @Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project") - String pack, - @Param(name = "branch", description = "The branch to download from", defaultValue = "main") - String branch, - @Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") - boolean trim, - @Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false") - boolean overwrite - ) { - sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : "")); - if (pack.equals("overworld")) { - String url = "https://github.com/IrisDimensions/overworld/releases/download/" + INMS.OVERWORLD_TAG + "/overworld.zip"; - Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite); - } else { - Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite); - } - } - - @Decree(description = "Get metrics for your world", aliases = "measure", origin = DecreeOrigin.PLAYER) - public void metrics() { - if (!IrisToolbelt.isIrisWorld(world())) { - sender().sendMessage(C.RED + "You must be in an Iris world"); - return; - } - sender().sendMessage(C.GREEN + "Sending metrics..."); - engine().printMetrics(sender()); - } - - @Decree(description = "Reload configuration file (this is also done automatically)") - public void reload() { - IrisSettings.invalidate(); - IrisSettings.get(); - sender().sendMessage(C.GREEN + "Hotloaded settings"); - } - - @Decree(description = "Update the pack of a world (UNSAFE!)", name = "^world", aliases = "update-world") - public void updateWorld( - @Param(description = "The world to update", contextual = true) - World world, - @Param(description = "The pack to install into the world", contextual = true, aliases = "dimension") - IrisDimension pack, - @Param(description = "Make sure to make a backup & read the warnings first!", defaultValue = "false", aliases = "c") - boolean confirm, - @Param(description = "Should Iris download the pack again for you", defaultValue = "false", name = "fresh-download", aliases = {"fresh", "new"}) - boolean freshDownload - ) { - if (!confirm) { - sender().sendMessage(new String[]{ - C.RED + "You should always make a backup before using this", - C.YELLOW + "Issues caused by this can be, but are not limited to:", - C.YELLOW + " - Broken chunks (cut-offs) between old and new chunks (before & after the update)", - C.YELLOW + " - Regenerated chunks that do not fit in with the old chunks", - C.YELLOW + " - Structures not spawning again when regenerating", - C.YELLOW + " - Caves not lining up", - C.YELLOW + " - Terrain layers not lining up", - C.RED + "Now that you are aware of the risks, and have made a back-up:", - C.RED + "/iris ^world " + world.getName() + " " + pack.getLoadKey() + " confirm=true" - }); - return; - } - - File folder = world.getWorldFolder(); - folder.mkdirs(); - - if (freshDownload) { - Iris.service(StudioSVC.class).downloadSearch(sender(), pack.getLoadKey(), false, true); - } - - Iris.service(StudioSVC.class).installIntoWorld(sender(), pack.getLoadKey(), folder); - } - - @Decree(description = "Unload an Iris World", origin = DecreeOrigin.PLAYER, sync = true) - public void unloadWorld( - @Param(description = "The world to unload") - World world - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); - return; - } - sender().sendMessage(C.GREEN + "Unloading world: " + world.getName()); - try { - IrisToolbelt.evacuate(world); - Bukkit.unloadWorld(world, false); - sender().sendMessage(C.GREEN + "World unloaded successfully."); - } catch (Exception e) { - sender().sendMessage(C.RED + "Failed to unload the world: " + e.getMessage()); - e.printStackTrace(); - } - } - - @Decree(description = "Load an Iris World", origin = DecreeOrigin.PLAYER, sync = true, aliases = {"import"}) - public void loadWorld( - @Param(description = "The name of the world to load") - String world - ) { - World worldloaded = Bukkit.getWorld(world); - worldNameToCheck = world; - boolean worldExists = doesWorldExist(worldNameToCheck); - WorldEngine = world; - - if (!worldExists) { - sender().sendMessage(C.YELLOW + world + " Doesnt exist on the server."); - return; - } - - File BUKKIT_YML = new File("bukkit.yml"); - String pathtodim = world + File.separator +"iris"+File.separator +"pack"+File.separator +"dimensions"+File.separator; - File directory = new File(Bukkit.getWorldContainer(), pathtodim); - - String dimension = null; - if (directory.exists() && directory.isDirectory()) { - File[] files = directory.listFiles(); - if (files != null) { - for (File file : files) { - if (file.isFile()) { - String fileName = file.getName(); - if (fileName.endsWith(".json")) { - dimension = fileName.substring(0, fileName.length() - 5); - sender().sendMessage(C.BLUE + "Generator: " + dimension); - } - } - } - } - } else { - sender().sendMessage(C.GOLD + world + " is not an iris world."); - return; - } - sender().sendMessage(C.GREEN + "Loading world: " + world); - - YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML); - String gen = "Iris:" + dimension; - ConfigurationSection section = yml.contains("worlds") ? yml.getConfigurationSection("worlds") : yml.createSection("worlds"); - if (!section.contains(world)) { - section.createSection(world).set("generator", gen); - try { - yml.save(BUKKIT_YML); - Iris.info("Registered \"" + world + "\" in bukkit.yml"); - } catch (IOException e) { - Iris.error("Failed to update bukkit.yml!"); - e.printStackTrace(); - return; - } - } - checkForBukkitWorlds(world); - sender().sendMessage(C.GREEN + world + " loaded successfully."); - } - @Decree(description = "Evacuate an iris world", origin = DecreeOrigin.PLAYER, sync = true) - public void evacuate( - @Param(description = "Evacuate the world") - World world - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); - return; - } - sender().sendMessage(C.GREEN + "Evacuating world" + world.getName()); - IrisToolbelt.evacuate(world); - } - - boolean doesWorldExist(String worldName) { - File worldContainer = Bukkit.getWorldContainer(); - File worldDirectory = new File(worldContainer, worldName); - return worldDirectory.exists() && worldDirectory.isDirectory(); - } - private void checkForBukkitWorlds(String world) { - FileConfiguration fc = new YamlConfiguration(); - try { - fc.load(new File("bukkit.yml")); - ConfigurationSection section = fc.getConfigurationSection("worlds"); - if (section == null) { - return; - } - - List worldsToLoad = Collections.singletonList(world); - - for (String s : section.getKeys(false)) { - if (!worldsToLoad.contains(s)) { - continue; - } - ConfigurationSection entry = section.getConfigurationSection(s); - if (!entry.contains("generator", true)) { - continue; - } - String generator = entry.getString("generator"); - if (generator.startsWith("Iris:")) { - generator = generator.split("\\Q:\\E")[1]; - } else if (generator.equalsIgnoreCase("Iris")) { - generator = IrisSettings.get().getGenerator().getDefaultWorldType(); - } else { - continue; - } - Iris.info("2 World: %s | Generator: %s", s, generator); - if (Bukkit.getWorlds().stream().anyMatch(w -> w.getName().equals(s))) { - continue; - } - Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); - WorldCreator c = new WorldCreator(s) - .generator(getDefaultWorldGenerator(s, generator)) - .environment(IrisData.loadAnyDimension(generator).getEnvironment()); - INMS.get().createWorld(c); - Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { - Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id); - if (worldName.equals("test")) { - try { - throw new RuntimeException(); - } catch (Throwable e) { - Iris.info(e.getStackTrace()[1].getClassName()); - if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) { - Iris.debug("MVC Test detected, Quick! Send them the dummy!"); - return new DummyChunkGenerator(); - } - } - } - IrisDimension dim; - if (id == null || id.isEmpty()) { - dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); - } else { - dim = IrisData.loadAnyDimension(id); - } - Iris.debug("Generator ID: " + id + " requested by bukkit/plugin"); - - if (dim == null) { - Iris.warn("Unable to find dimension type " + id + " Looking for online packs..."); - - service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true); - dim = IrisData.loadAnyDimension(id); - - if (dim == null) { - throw new RuntimeException("Can't find dimension " + id + "!"); - } else { - Iris.info("Resolved missing dimension, proceeding with generation."); - } - } - Iris.debug("Assuming IrisDimension: " + dim.getName()); - IrisWorld w = IrisWorld.builder() - .name(worldName) - .seed(1337) - .environment(dim.getEnvironment()) - .worldFolder(new File(Bukkit.getWorldContainer(), worldName)) - .minHeight(dim.getMinHeight()) - .maxHeight(dim.getMaxHeight()) - .build(); - Iris.debug("Generator Config: " + w.toString()); - File ff = new File(w.worldFolder(), "iris/pack"); - if (!ff.exists() || ff.listFiles().length == 0) { - ff.mkdirs(); - service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), ff.getParentFile()); - } - return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey()); - } -} +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2022 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.core.commands; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.pregenerator.ChunkUpdater; +import com.volmit.iris.core.service.StudioSVC; +import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.IrisDimension; +import com.volmit.iris.core.safeguard.UtilsSFG; +import com.volmit.iris.engine.object.IrisWorld; +import com.volmit.iris.engine.platform.BukkitChunkGenerator; +import com.volmit.iris.engine.platform.DummyChunkGenerator; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.decree.DecreeExecutor; +import com.volmit.iris.util.decree.DecreeOrigin; +import com.volmit.iris.util.decree.annotations.Decree; +import com.volmit.iris.util.decree.annotations.Param; +import com.volmit.iris.util.decree.specialhandlers.NullablePlayerHandler; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.plugin.VolmitSender; +import com.volmit.iris.util.scheduling.J; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.WorldCreator; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.scheduler.BukkitRunnable; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import static com.volmit.iris.Iris.service; +import static com.volmit.iris.core.service.EditSVC.deletingWorld; +import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode; +import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities; +import static org.bukkit.Bukkit.getServer; + +@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command") +public class CommandIris implements DecreeExecutor { + private CommandStudio studio; + private CommandPregen pregen; + private CommandSettings settings; + private CommandObject object; + private CommandJigsaw jigsaw; + private CommandWhat what; + private CommandEdit edit; + private CommandFind find; + private CommandDeveloper developer; + public static boolean worldCreation = false; + String WorldEngine; + String worldNameToCheck = "YourWorldName"; + VolmitSender sender = Iris.getSender(); + + @Decree(description = "Create a new world", aliases = {"+", "c"}) + public void create( + @Param(aliases = "world-name", description = "The name of the world to create") + String name, + @Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default") + IrisDimension type, + @Param(description = "The seed to generate the world with", defaultValue = "1337") + long seed + ) { + if (name.equalsIgnoreCase("iris")) { + sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds."); + sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); + return; + } + + if (name.equalsIgnoreCase("benchmark")) { + sender().sendMessage(C.RED + "You cannot use the world name \"benchmark\" for creating worlds as Iris uses this directory for Benchmarking Packs."); + sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); + return; + } + + if (new File(Bukkit.getWorldContainer(), name).exists()) { + sender().sendMessage(C.RED + "That folder already exists!"); + return; + } + + try { + worldCreation = true; + IrisToolbelt.createWorld() + .dimension(type.getLoadKey()) + .name(name) + .seed(seed) + .sender(sender()) + .studio(false) + .create(); + } catch (Throwable e) { + sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details."); + Iris.error("Exception raised during world creation: " + e.getMessage()); + Iris.reportError(e); + worldCreation = false; + return; + } + worldCreation = false; + sender().sendMessage(C.GREEN + "Successfully created your world!"); + } + + @Decree(description = "Teleport to another world", aliases = {"tp"}, sync = true) + public void teleport( + @Param(description = "World to teleport to") + World world, + @Param(description = "Player to teleport", defaultValue = "---", customHandler = NullablePlayerHandler.class) + Player player + ) { + if (player == null && sender().isPlayer()) + player = sender().player(); + + final Player target = player; + if (target == null) { + sender().sendMessage(C.RED + "The specified player does not exist."); + return; + } + + new BukkitRunnable() { + @Override + public void run() { + target.teleport(world.getSpawnLocation()); + new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + "."); + } + }.runTask(Iris.instance); + } + + @Decree(description = "Print version information") + public void version() { + sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software"); + } + + /* + /todo + @Decree(description = "Benchmark a pack", origin = DecreeOrigin.CONSOLE) + public void packbenchmark( + @Param(description = "Dimension to benchmark") + IrisDimension type + ) throws InterruptedException { + + BenchDimension = type.getLoadKey(); + + IrisPackBenchmarking.runBenchmark(); + } */ + + @Decree(description = "Print world height information", origin = DecreeOrigin.PLAYER) + public void height() { + if (sender().isPlayer()) { + sender().sendMessage(C.GREEN + "" + sender().player().getWorld().getMinHeight() + " to " + sender().player().getWorld().getMaxHeight()); + sender().sendMessage(C.GREEN + "Total Height: " + (sender().player().getWorld().getMaxHeight() - sender().player().getWorld().getMinHeight())); + } else { + World mainWorld = getServer().getWorlds().get(0); + Iris.info(C.GREEN + "" + mainWorld.getMinHeight() + " to " + mainWorld.getMaxHeight()); + Iris.info(C.GREEN + "Total Height: " + (mainWorld.getMaxHeight() - mainWorld.getMinHeight())); + } + } + + @Decree(description = "QOL command to open a overworld studio world.", sync = true) + public void so() { + sender().sendMessage(C.GREEN + "Opening studio for the \"Overworld\" pack (seed: 1337)"); + Iris.service(StudioSVC.class).open(sender(), 1337, "overworld"); + } + + @Decree(description = "Check access of all worlds.", aliases = {"accesslist"}) + public void worlds() { + KList IrisWorlds = new KList<>(); + KList BukkitWorlds = new KList<>(); + + for (World w : Bukkit.getServer().getWorlds()) { + try { + Engine engine = IrisToolbelt.access(w).getEngine(); + if (engine != null) { + IrisWorlds.add(w); + } + } catch (Exception e) { + BukkitWorlds.add(w); + } + } + + if (sender().isPlayer()) { + sender().sendMessage(C.BLUE + "Iris Worlds: "); + for (World IrisWorld : IrisWorlds.copy()) { + sender().sendMessage(C.IRIS + "- " +IrisWorld.getName()); + } + sender().sendMessage(C.GOLD + "Bukkit Worlds: "); + for (World BukkitWorld : BukkitWorlds.copy()) { + sender().sendMessage(C.GRAY + "- " +BukkitWorld.getName()); + } + } else { + Iris.info(C.BLUE + "Iris Worlds: "); + for (World IrisWorld : IrisWorlds.copy()) { + Iris.info(C.IRIS + "- " +IrisWorld.getName()); + } + Iris.info(C.GOLD + "Bukkit Worlds: "); + for (World BukkitWorld : BukkitWorlds.copy()) { + Iris.info(C.GRAY + "- " +BukkitWorld.getName()); + } + + } + } + + @Decree(description = "Remove an Iris world", aliases = {"del", "rm", "delete"}, sync = true) + public void remove( + @Param(description = "The world to remove") + World world, + @Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true") + boolean delete + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); + return; + } + sender().sendMessage(C.GREEN + "Removing world: " + world.getName()); + + if (!IrisToolbelt.evacuate(world)) { + sender().sendMessage(C.RED + "Failed to evacuate world: " + world.getName()); + return; + } + + if (!Bukkit.unloadWorld(world, false)) { + sender().sendMessage(C.RED + "Failed to unload world: " + world.getName()); + return; + } + + try { + if (IrisToolbelt.removeWorld(world)) { + sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml"); + } else { + sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml"); + } + } catch (IOException e) { + sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage()); + e.printStackTrace(); + } + IrisToolbelt.evacuate(world, "Deleting world"); + deletingWorld = true; + if (!delete) { + deletingWorld = false; + return; + } + VolmitSender sender = sender(); + J.a(() -> { + int retries = 12; + + if (deleteDirectory(world.getWorldFolder())) { + sender.sendMessage(C.GREEN + "Successfully removed world folder"); + } else { + while(true){ + if (deleteDirectory(world.getWorldFolder())){ + sender.sendMessage(C.GREEN + "Successfully removed world folder"); + break; + } + retries--; + if (retries == 0){ + sender.sendMessage(C.RED + "Failed to remove world folder"); + break; + } + J.sleep(3000); + } + } + deletingWorld = false; + }); + } + + public static boolean deleteDirectory(File dir) { + if (dir.isDirectory()) { + File[] children = dir.listFiles(); + for (int i = 0; i < children.length; i++) { + boolean success = deleteDirectory(children[i]); + if (!success) { + return false; + } + } + } + return dir.delete(); + } + + @Decree(description = "Updates all chunk in the specified world") + public void updater( + @Param(description = "World to update chunks at") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.GOLD + "This is not an Iris world"); + return; + } + ChunkUpdater updater = new ChunkUpdater(world); + if (sender().isPlayer()) { + sender().sendMessage(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); + } else { + Iris.info(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); + } + updater.start(); + } + + @Decree(description = "Set aura spins") + public void aura( + @Param(description = "The h color value", defaultValue = "-20") + int h, + @Param(description = "The s color value", defaultValue = "7") + int s, + @Param(description = "The b color value", defaultValue = "8") + int b + ) { + IrisSettings.get().getGeneral().setSpinh(h); + IrisSettings.get().getGeneral().setSpins(s); + IrisSettings.get().getGeneral().setSpinb(b); + IrisSettings.get().forceSave(); + sender().sendMessage("Aura Spins updated to " + h + " " + s + " " + b); + } + + @Decree(description = "Bitwise calculations") + public void bitwise( + @Param(description = "The first value to run calculations on") + int value1, + @Param(description = "The operator: | & ^ ≺≺ ≻≻ %") + String operator, + @Param(description = "The second value to run calculations on") + int value2 + ) { + Integer v = null; + switch (operator) { + case "|" -> v = value1 | value2; + case "&" -> v = value1 & value2; + case "^" -> v = value1 ^ value2; + case "%" -> v = value1 % value2; + case ">>" -> v = value1 >> value2; + case "<<" -> v = value1 << value2; + } + if (v == null) { + sender().sendMessage(C.RED + "The operator you entered: (" + operator + ") is invalid!"); + return; + } + sender().sendMessage(C.GREEN + "" + value1 + " " + C.GREEN + operator.replaceAll("<", "≺").replaceAll(">", "≻").replaceAll("%", "%") + " " + C.GREEN + value2 + C.GREEN + " returns " + C.GREEN + v); + } + + @Decree(description = "Toggle debug") + public void debug( + @Param(name = "on", description = "Whether or not debug should be on", defaultValue = "other") + Boolean on + ) { + boolean to = on == null ? !IrisSettings.get().getGeneral().isDebug() : on; + IrisSettings.get().getGeneral().setDebug(to); + IrisSettings.get().forceSave(); + sender().sendMessage(C.GREEN + "Set debug to: " + to); + } + + @Decree(description = "Download a project.", aliases = "dl") + public void download( + @Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project") + String pack, + @Param(name = "branch", description = "The branch to download from", defaultValue = "main") + String branch, + @Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") + boolean trim, + @Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false") + boolean overwrite + ) { + sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : "")); + if (pack.equals("overworld")) { + String url = "https://github.com/IrisDimensions/overworld/releases/download/" + INMS.OVERWORLD_TAG + "/overworld.zip"; + Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite); + } else { + Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite); + } + } + + @Decree(description = "Get metrics for your world", aliases = "measure", origin = DecreeOrigin.PLAYER) + public void metrics() { + if (!IrisToolbelt.isIrisWorld(world())) { + sender().sendMessage(C.RED + "You must be in an Iris world"); + return; + } + sender().sendMessage(C.GREEN + "Sending metrics..."); + engine().printMetrics(sender()); + } + + @Decree(description = "Reload configuration file (this is also done automatically)") + public void reload() { + IrisSettings.invalidate(); + IrisSettings.get(); + sender().sendMessage(C.GREEN + "Hotloaded settings"); + } + + @Decree(description = "Update the pack of a world (UNSAFE!)", name = "^world", aliases = "update-world") + public void updateWorld( + @Param(description = "The world to update", contextual = true) + World world, + @Param(description = "The pack to install into the world", contextual = true, aliases = "dimension") + IrisDimension pack, + @Param(description = "Make sure to make a backup & read the warnings first!", defaultValue = "false", aliases = "c") + boolean confirm, + @Param(description = "Should Iris download the pack again for you", defaultValue = "false", name = "fresh-download", aliases = {"fresh", "new"}) + boolean freshDownload + ) { + if (!confirm) { + sender().sendMessage(new String[]{ + C.RED + "You should always make a backup before using this", + C.YELLOW + "Issues caused by this can be, but are not limited to:", + C.YELLOW + " - Broken chunks (cut-offs) between old and new chunks (before & after the update)", + C.YELLOW + " - Regenerated chunks that do not fit in with the old chunks", + C.YELLOW + " - Structures not spawning again when regenerating", + C.YELLOW + " - Caves not lining up", + C.YELLOW + " - Terrain layers not lining up", + C.RED + "Now that you are aware of the risks, and have made a back-up:", + C.RED + "/iris ^world " + world.getName() + " " + pack.getLoadKey() + " confirm=true" + }); + return; + } + + File folder = world.getWorldFolder(); + folder.mkdirs(); + + if (freshDownload) { + Iris.service(StudioSVC.class).downloadSearch(sender(), pack.getLoadKey(), false, true); + } + + Iris.service(StudioSVC.class).installIntoWorld(sender(), pack.getLoadKey(), folder); + } + + @Decree(description = "Unload an Iris World", origin = DecreeOrigin.PLAYER, sync = true) + public void unloadWorld( + @Param(description = "The world to unload") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); + return; + } + sender().sendMessage(C.GREEN + "Unloading world: " + world.getName()); + try { + IrisToolbelt.evacuate(world); + Bukkit.unloadWorld(world, false); + sender().sendMessage(C.GREEN + "World unloaded successfully."); + } catch (Exception e) { + sender().sendMessage(C.RED + "Failed to unload the world: " + e.getMessage()); + e.printStackTrace(); + } + } + + @Decree(description = "Load an Iris World", origin = DecreeOrigin.PLAYER, sync = true, aliases = {"import"}) + public void loadWorld( + @Param(description = "The name of the world to load") + String world + ) { + World worldloaded = Bukkit.getWorld(world); + worldNameToCheck = world; + boolean worldExists = doesWorldExist(worldNameToCheck); + WorldEngine = world; + + if (!worldExists) { + sender().sendMessage(C.YELLOW + world + " Doesnt exist on the server."); + return; + } + + File BUKKIT_YML = new File("bukkit.yml"); + String pathtodim = world + File.separator +"iris"+File.separator +"pack"+File.separator +"dimensions"+File.separator; + File directory = new File(Bukkit.getWorldContainer(), pathtodim); + + String dimension = null; + if (directory.exists() && directory.isDirectory()) { + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isFile()) { + String fileName = file.getName(); + if (fileName.endsWith(".json")) { + dimension = fileName.substring(0, fileName.length() - 5); + sender().sendMessage(C.BLUE + "Generator: " + dimension); + } + } + } + } + } else { + sender().sendMessage(C.GOLD + world + " is not an iris world."); + return; + } + sender().sendMessage(C.GREEN + "Loading world: " + world); + + YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML); + String gen = "Iris:" + dimension; + ConfigurationSection section = yml.contains("worlds") ? yml.getConfigurationSection("worlds") : yml.createSection("worlds"); + if (!section.contains(world)) { + section.createSection(world).set("generator", gen); + try { + yml.save(BUKKIT_YML); + Iris.info("Registered \"" + world + "\" in bukkit.yml"); + } catch (IOException e) { + Iris.error("Failed to update bukkit.yml!"); + e.printStackTrace(); + return; + } + } + checkForBukkitWorlds(world); + sender().sendMessage(C.GREEN + world + " loaded successfully."); + } + @Decree(description = "Evacuate an iris world", origin = DecreeOrigin.PLAYER, sync = true) + public void evacuate( + @Param(description = "Evacuate the world") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); + return; + } + sender().sendMessage(C.GREEN + "Evacuating world" + world.getName()); + IrisToolbelt.evacuate(world); + } + + boolean doesWorldExist(String worldName) { + File worldContainer = Bukkit.getWorldContainer(); + File worldDirectory = new File(worldContainer, worldName); + return worldDirectory.exists() && worldDirectory.isDirectory(); + } + private void checkForBukkitWorlds(String world) { + FileConfiguration fc = new YamlConfiguration(); + try { + fc.load(new File("bukkit.yml")); + ConfigurationSection section = fc.getConfigurationSection("worlds"); + if (section == null) { + return; + } + + List worldsToLoad = Collections.singletonList(world); + + for (String s : section.getKeys(false)) { + if (!worldsToLoad.contains(s)) { + continue; + } + ConfigurationSection entry = section.getConfigurationSection(s); + if (!entry.contains("generator", true)) { + continue; + } + String generator = entry.getString("generator"); + if (generator.startsWith("Iris:")) { + generator = generator.split("\\Q:\\E")[1]; + } else if (generator.equalsIgnoreCase("Iris")) { + generator = IrisSettings.get().getGenerator().getDefaultWorldType(); + } else { + continue; + } + Iris.info("2 World: %s | Generator: %s", s, generator); + if (Bukkit.getWorlds().stream().anyMatch(w -> w.getName().equals(s))) { + continue; + } + Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); + WorldCreator c = new WorldCreator(s) + .generator(getDefaultWorldGenerator(s, generator)) + .environment(IrisData.loadAnyDimension(generator).getEnvironment()); + INMS.get().createWorld(c); + Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { + Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id); + if (worldName.equals("test")) { + try { + throw new RuntimeException(); + } catch (Throwable e) { + Iris.info(e.getStackTrace()[1].getClassName()); + if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) { + Iris.debug("MVC Test detected, Quick! Send them the dummy!"); + return new DummyChunkGenerator(); + } + } + } + IrisDimension dim; + if (id == null || id.isEmpty()) { + dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); + } else { + dim = IrisData.loadAnyDimension(id); + } + Iris.debug("Generator ID: " + id + " requested by bukkit/plugin"); + + if (dim == null) { + Iris.warn("Unable to find dimension type " + id + " Looking for online packs..."); + + service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true); + dim = IrisData.loadAnyDimension(id); + + if (dim == null) { + throw new RuntimeException("Can't find dimension " + id + "!"); + } else { + Iris.info("Resolved missing dimension, proceeding with generation."); + } + } + Iris.debug("Assuming IrisDimension: " + dim.getName()); + IrisWorld w = IrisWorld.builder() + .name(worldName) + .seed(1337) + .environment(dim.getEnvironment()) + .worldFolder(new File(Bukkit.getWorldContainer(), worldName)) + .minHeight(dim.getMinHeight()) + .maxHeight(dim.getMaxHeight()) + .build(); + Iris.debug("Generator Config: " + w.toString()); + File ff = new File(w.worldFolder(), "iris/pack"); + if (!ff.exists() || ff.listFiles().length == 0) { + ff.mkdirs(); + service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), ff.getParentFile()); + } + return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey()); + } +} From d49f7d7821733751989d12e269367ab285f27dbf Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 13 Jul 2025 17:43:11 +0200 Subject: [PATCH 13/36] add parameter to the create command to make it your main world --- .../iris/core/commands/CommandIris.java | 50 ++++++++++++------- .../main/java/com/volmit/iris/util/io/IO.java | 20 ++++++++ 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 38e2266e3..84f601642 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -27,10 +27,8 @@ import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.core.safeguard.UtilsSFG; import com.volmit.iris.engine.object.IrisWorld; import com.volmit.iris.engine.platform.BukkitChunkGenerator; -import com.volmit.iris.engine.platform.DummyChunkGenerator; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; @@ -39,8 +37,11 @@ import com.volmit.iris.util.decree.annotations.Param; import com.volmit.iris.util.decree.specialhandlers.NullablePlayerHandler; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; +import lombok.SneakyThrows; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.WorldCreator; @@ -51,15 +52,13 @@ import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.bukkit.scheduler.BukkitRunnable; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import static com.volmit.iris.Iris.service; import static com.volmit.iris.core.service.EditSVC.deletingWorld; -import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode; -import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities; import static org.bukkit.Bukkit.getServer; @Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command") @@ -74,6 +73,7 @@ public class CommandIris implements DecreeExecutor { private CommandFind find; private CommandDeveloper developer; public static boolean worldCreation = false; + private static final AtomicReference mainWorld = new AtomicReference<>(); String WorldEngine; String worldNameToCheck = "YourWorldName"; VolmitSender sender = Iris.getSender(); @@ -85,7 +85,9 @@ public class CommandIris implements DecreeExecutor { @Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default") IrisDimension type, @Param(description = "The seed to generate the world with", defaultValue = "1337") - long seed + long seed, + @Param(aliases = "main-world", description = "Whether or not to automatically use this world as the main world", defaultValue = "false") + boolean main ) { if (name.equalsIgnoreCase("iris")) { sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds."); @@ -113,6 +115,12 @@ public class CommandIris implements DecreeExecutor { .sender(sender()) .studio(false) .create(); + if (main) { + Runtime.getRuntime().addShutdownHook(mainWorld.updateAndGet(old -> { + if (old != null) Runtime.getRuntime().removeShutdownHook(old); + return new Thread(() -> updateMainWorld(name)); + })); + } } catch (Throwable e) { sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details."); Iris.error("Exception raised during world creation: " + e.getMessage()); @@ -124,6 +132,23 @@ public class CommandIris implements DecreeExecutor { sender().sendMessage(C.GREEN + "Successfully created your world!"); } + @SneakyThrows + private void updateMainWorld(String newName) { + File worlds = Bukkit.getWorldContainer(); + var data = ServerProperties.DATA; + try (var in = new FileInputStream(ServerProperties.SERVER_PROPERTIES)) { + data.load(in); + } + for (String sub : List.of("datapacks", "playerdata", "advancements", "stats")) { + IO.copyDirectory(new File(worlds, ServerProperties.LEVEL_NAME + "/" + sub).toPath(), new File(worlds, newName + "/" + sub).toPath()); + } + + data.setProperty("level-name", newName); + try (var out = new FileOutputStream(ServerProperties.SERVER_PROPERTIES)) { + data.store(out, null); + } + } + @Decree(description = "Teleport to another world", aliases = {"tp"}, sync = true) public void teleport( @Param(description = "World to teleport to") @@ -580,17 +605,6 @@ public class CommandIris implements DecreeExecutor { } public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id); - if (worldName.equals("test")) { - try { - throw new RuntimeException(); - } catch (Throwable e) { - Iris.info(e.getStackTrace()[1].getClassName()); - if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) { - Iris.debug("MVC Test detected, Quick! Send them the dummy!"); - return new DummyChunkGenerator(); - } - } - } IrisDimension dim; if (id == null || id.isEmpty()) { dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); diff --git a/core/src/main/java/com/volmit/iris/util/io/IO.java b/core/src/main/java/com/volmit/iris/util/io/IO.java index 61deb3670..247dfefb1 100644 --- a/core/src/main/java/com/volmit/iris/util/io/IO.java +++ b/core/src/main/java/com/volmit/iris/util/io/IO.java @@ -30,6 +30,7 @@ import org.apache.commons.io.function.IOFunction; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.security.DigestInputStream; import java.security.MessageDigest; @@ -592,6 +593,25 @@ public class IO { } } + public static void copyDirectory(Path source, Path target) throws IOException { + Files.walk(source).forEach(sourcePath -> { + Path targetPath = target.resolve(source.relativize(sourcePath)); + + try { + if (Files.isDirectory(sourcePath)) { + if (!Files.exists(targetPath)) { + Files.createDirectories(targetPath); + } + } else { + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + } + } catch (IOException e) { + Iris.error("Failed to copy " + targetPath); + e.printStackTrace(); + } + }); + } + /** * Unconditionally close an Reader. *

From a8892b04ef6074096d2500e5f2079f8ade2b4c52 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 19 Jul 2025 12:59:50 +0200 Subject: [PATCH 14/36] bump nms for 1.21.8 support --- .../java/com/volmit/iris/core/nms/INMS.java | 37 ++++++++++--------- gradle/libs.versions.toml | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMS.java b/core/src/main/java/com/volmit/iris/core/nms/INMS.java index 8b998147c..e4d6bc682 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMS.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMS.java @@ -24,21 +24,21 @@ import com.volmit.iris.core.nms.v1X.NMSBinding1X; import org.bukkit.Bukkit; import java.util.List; -import java.util.Map; public class INMS { - private static final Map REVISION = Map.of( - "1.20.5", "v1_20_R4", - "1.20.6", "v1_20_R4", - "1.21", "v1_21_R1", - "1.21.1", "v1_21_R1", - "1.21.2", "v1_21_R2", - "1.21.3", "v1_21_R2", - "1.21.4", "v1_21_R3", - "1.21.5", "v1_21_R4", - "1.21.6", "v1_21_R5", - "1.21.7", "v1_21_R5" + private static final Version CURRENT = Boolean.getBoolean("iris.no-version-limit") ? + new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, null) : + new Version(21, 8, null); + + private static final List REVISION = List.of( + new Version(21, 6, "v1_21_R5"), + new Version(21, 5, "v1_21_R4"), + new Version(21, 4, "v1_21_R3"), + new Version(21, 2, "v1_21_R2"), + new Version(21, 0, "v1_21_R1"), + new Version(20, 5, "v1_20_R4") ); + private static final List PACKS = List.of( new Version(21, 5, "31100"), new Version(21, 4, "31020"), @@ -48,7 +48,7 @@ public class INMS { //@done private static final INMSBinding binding = bind(); - public static final String OVERWORLD_TAG = getOverworldTag(); + public static final String OVERWORLD_TAG = getTag(PACKS, "3910"); public static INMSBinding get() { return binding; @@ -62,7 +62,7 @@ public class INMS { try { String name = Bukkit.getServer().getClass().getCanonicalName(); if (name.equals("org.bukkit.craftbukkit.CraftServer")) { - return REVISION.getOrDefault(Bukkit.getServer().getBukkitVersion().split("-")[0], "BUKKIT"); + return getTag(REVISION, "BUKKIT"); } else { return name.split("\\Q.\\E")[3]; } @@ -100,7 +100,7 @@ public class INMS { return new NMSBinding1X(); } - private static String getOverworldTag() { + private static String getTag(List versions, String def) { var version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.", 3); int major = 0; int minor = 0; @@ -111,13 +111,16 @@ public class INMS { } else if (version.length == 2) { major = Integer.parseInt(version[1]); } + if (CURRENT.major < major || CURRENT.minor < minor) { + return versions.getFirst().tag; + } - for (var p : PACKS) { + for (var p : versions) { if (p.major > major || p.minor > minor) continue; return p.tag; } - return "3910"; + return def; } private record Version(int major, int minor, String tag) {} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bdc075162..f697c836e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ [versions] # Plugins shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow -slimjar = "2.0.7" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.0.8" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin From dee46a42843b6a8965e1cc7e631ee4172c2cc0e7 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 19 Jul 2025 17:48:58 +0200 Subject: [PATCH 15/36] cleanup object mask rotation --- .../iris/engine/object/IrisCaveShape.java | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) 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 index f5001befb..4972ce516 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java @@ -6,6 +6,7 @@ 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; @@ -36,17 +37,40 @@ public class IrisCaveShape { 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; - }); + 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); } } From 8262e52893e216757cde2af313bcf8be2ef47248 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 30 Mar 2025 13:48:43 +0200 Subject: [PATCH 16/36] cleanup regen --- .../iris/core/commands/CommandStudio.java | 140 +++++++++--------- .../engine/platform/BukkitChunkGenerator.java | 74 ++++----- .../platform/PlatformChunkGenerator.java | 4 +- .../iris/util/parallel/SyncExecutor.java | 46 ++++++ 4 files changed, 160 insertions(+), 104 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java index 0abb77a15..1635dd3bb 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java @@ -46,18 +46,20 @@ import com.volmit.iris.util.interpolation.InterpolationMethod; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONArray; import com.volmit.iris.util.json.JSONObject; +import com.volmit.iris.util.mantle.MantleChunk; +import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.Spiraler; import com.volmit.iris.util.noise.CNG; -import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.MultiBurst; +import com.volmit.iris.util.parallel.SyncExecutor; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.O; import com.volmit.iris.util.scheduling.PrecisionStopwatch; -import com.volmit.iris.util.scheduling.jobs.QueueJob; +import com.volmit.iris.util.scheduling.jobs.ParallelQueueJob; import io.papermc.lib.PaperLib; import org.bukkit.*; import org.bukkit.event.inventory.InventoryType; @@ -76,8 +78,7 @@ import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Date; import java.util.Objects; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; @@ -161,70 +162,77 @@ public class CommandStudio implements DecreeExecutor { @Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5") int radius ) { - if (IrisToolbelt.isIrisWorld(player().getWorld())) { - VolmitSender sender = sender(); - J.a(() -> { - DecreeContext.touch(sender); - PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld()); - Engine engine = plat.getEngine(); - try { - Chunk cx = player().getLocation().getChunk(); - KList js = new KList<>(); - BurstExecutor b = MultiBurst.burst.burst(); - b.setMulticore(false); - int rad = engine.getMantle().getRadius(); - for (int i = -(radius + rad); i <= radius + rad; i++) { - for (int j = -(radius + rad); j <= radius + rad; j++) { - engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ()); - } - } - - for (int i = -radius; i <= radius; i++) { - for (int j = -radius; j <= radius; j++) { - int finalJ = j; - int finalI = i; - b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> { - synchronized (js) { - js.add(f); - } - })); - } - } - - b.complete(); - sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections"); - QueueJob r = new QueueJob<>() { - final KList> futures = new KList<>(); - - @Override - public void execute(Runnable runnable) { - futures.add(J.sfut(runnable)); - - if (futures.size() > 64) { - while (futures.isNotEmpty()) { - try { - futures.remove(0).get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } - } - } - } - - @Override - public String getName() { - return "Regenerating"; - } - }; - r.queue(js); - r.execute(sender()); - } catch (Throwable e) { - sender().sendMessage("Unable to parse view-distance"); - } - }); - } else { + World world = player().getWorld(); + if (!IrisToolbelt.isIrisWorld(world)) { sender().sendMessage(C.RED + "You must be in an Iris World to use regen!"); } + + VolmitSender sender = sender(); + var loc = player().getLocation().clone(); + + J.a(() -> { + DecreeContext.touch(sender); + PlatformChunkGenerator plat = IrisToolbelt.access(world); + Engine engine = plat.getEngine(); + try (SyncExecutor executor = new SyncExecutor(20)) { + int x = loc.getBlockX() >> 4; + int z = loc.getBlockZ() >> 4; + + int rad = engine.getMantle().getRadius(); + var mantle = engine.getMantle().getMantle(); + var chunkMap = new KMap(); + for (int i = -(radius + rad); i <= radius + rad; i++) { + for (int j = -(radius + rad); j <= radius + rad; j++) { + int xx = i + x, zz = j + z; + if (Math.abs(i) <= radius && Math.abs(j) <= radius) { + mantle.deleteChunk(xx, zz); + continue; + } + chunkMap.put(new Position2(xx, zz), mantle.getChunk(xx, zz)); + mantle.deleteChunk(xx, zz); + } + } + + ParallelQueueJob job = new ParallelQueueJob<>() { + @Override + public void execute(Position2 p) { + plat.injectChunkReplacement(world, p.getX(), p.getZ(), executor); + } + + @Override + public String getName() { + return "Regenerating"; + } + }; + for (int i = -radius; i <= radius; i++) { + for (int j = -radius; j <= radius; j++) { + job.queue(new Position2(i + x, j + z)); + } + } + + CountDownLatch latch = new CountDownLatch(1); + job.execute(sender(), latch::countDown); + latch.await(); + + int sections = mantle.getWorldHeight() >> 4; + chunkMap.forEach((pos, chunk) -> { + var c = mantle.getChunk(pos.getX(), pos.getZ()); + for (MantleFlag flag : MantleFlag.values()) { + c.flag(flag, chunk.isFlagged(flag)); + } + c.clear(); + for (int y = 0; y < sections; y++) { + var slice = chunk.get(y); + if (slice == null) continue; + var s = c.getOrCreate(y); + slice.getSliceMap().forEach(s::putSlice); + } + }); + } catch (Throwable e) { + sender().sendMessage("Error while regenerating chunks"); + e.printStackTrace(); + } + }); } @Decree(description = "Convert objects in the \"convert\" folder") diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index 2e6035534..1f7fbd9a6 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -64,12 +64,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.List; import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Semaphore; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; @EqualsAndHashCode(callSuper = true) @Data @@ -95,8 +93,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun @Setter private volatile StudioGenerator studioGenerator; - private boolean initialized = false; - public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) { setup = new AtomicBoolean(false); studioGenerator = null; @@ -114,8 +110,8 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun @EventHandler(priority = EventPriority.LOWEST) public void onWorldInit(WorldInitEvent event) { - if (initialized || !world.name().equals(event.getWorld().getName())) - return; + if (!world.name().equals(event.getWorld().getName())) return; + Iris.instance.unregisterListener(this); world.setRawWorldSeed(event.getWorld().getSeed()); if (initialize(event.getWorld())) return; @@ -140,7 +136,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun } spawnChunks.complete(INMS.get().getSpawnChunkCount(world)); Iris.instance.unregisterListener(this); - initialized = true; IrisWorlds.get().put(world.getName(), dimensionKey); return true; } @@ -205,50 +200,57 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun } @Override - public void injectChunkReplacement(World world, int x, int z, Consumer jobs) { + public void injectChunkReplacement(World world, int x, int z, Executor syncExecutor) { try { loadLock.acquire(); IrisBiomeStorage st = new IrisBiomeStorage(); TerrainChunk tc = TerrainChunk.createUnsafe(world, st); - Hunk blocks = Hunk.view(tc); - Hunk biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight()); this.world.bind(world); - getEngine().generate(x << 4, z << 4, blocks, biomes, true); - Iris.debug("Regenerated " + x + " " + z); - int t = 0; + getEngine().generate(x << 4, z << 4, tc, false); + + Chunk c = PaperLib.getChunkAtAsync(world, x, z) + .thenApply(d -> { + d.addPluginChunkTicket(Iris.instance); + + for (Entity ee : d.getEntities()) { + if (ee instanceof Player) { + continue; + } + + ee.remove(); + } + + engine.getWorldManager().onChunkLoad(d, false); + return d; + }).get(); + + + KList> futures = new KList<>(1 + getEngine().getHeight() >> 4); for (int i = getEngine().getHeight() >> 4; i >= 0; i--) { - if (!world.isChunkLoaded(x, z)) { - continue; - } - - Chunk c = world.getChunkAt(x, z); - for (Entity ee : c.getEntities()) { - if (ee instanceof Player) { - continue; - } - - J.s(ee::remove); - } - - J.s(() -> engine.getWorldManager().onChunkLoad(c, false)); - - int finalI = i; - jobs.accept(() -> { - + int finalI = i << 4; + futures.add(CompletableFuture.runAsync(() -> { for (int xx = 0; xx < 16; xx++) { for (int yy = 0; yy < 16; yy++) { for (int zz = 0; zz < 16; zz++) { - if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) { + if (yy + finalI >= engine.getHeight() || yy + finalI < 0) { continue; } - c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz) - .setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false); + int y = yy + finalI + world.getMinHeight(); + c.getBlock(xx, y, zz).setBlockData(tc.getBlockData(xx, y, zz), false); } } } - }); + }, syncExecutor)); } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenRunAsync(() -> { + c.removePluginChunkTicket(Iris.instance); + c.unload(); + }, syncExecutor) + .get(); + Iris.debug("Regenerated " + x + " " + z); + loadLock.release(); } catch (Throwable e) { loadLock.release(); diff --git a/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java index 687788527..93066fb62 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java @@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; +import java.util.concurrent.Executor; public interface PlatformChunkGenerator extends Hotloadable, DataProvider { @Nullable @@ -42,7 +42,7 @@ public interface PlatformChunkGenerator extends Hotloadable, DataProvider { @NotNull EngineTarget getTarget(); - void injectChunkReplacement(World world, int x, int z, Consumer jobs); + void injectChunkReplacement(World world, int x, int z, Executor syncExecutor); void close(); diff --git a/core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java b/core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java new file mode 100644 index 000000000..00966b226 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java @@ -0,0 +1,46 @@ +package com.volmit.iris.util.parallel; + +import com.volmit.iris.util.math.M; +import com.volmit.iris.util.scheduling.SR; +import org.jetbrains.annotations.NotNull; + +import java.util.Queue; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; + +public class SyncExecutor implements Executor, AutoCloseable { + private final CountDownLatch latch = new CountDownLatch(1); + private final Queue queue = new ConcurrentLinkedQueue<>(); + private final AtomicBoolean closed = new AtomicBoolean(false); + + public SyncExecutor(int msPerTick) { + new SR() { + @Override + public void run() { + var time = M.ms() + msPerTick; + while (time > M.ms()) { + Runnable r = queue.poll(); + if (r == null) break; + r.run(); + } + + if (closed.get() && queue.isEmpty()) { + cancel(); + latch.countDown(); + } + } + }; + } + + @Override + public void execute(@NotNull Runnable command) { + if (closed.get()) throw new IllegalStateException("Executor is closed!"); + queue.add(command); + } + + @Override + public void close() throws Exception { + closed.set(true); + latch.await(); + } +} From f50e964d4f53e36bb7f65852e8a695da02fc3ece Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 21 Jul 2025 17:14:45 +0200 Subject: [PATCH 17/36] hopefully fix unsafe mantle chunk operations --- .../com/volmit/iris/util/mantle/Mantle.java | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java index 6e1e56e54..6851c4cea 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -421,19 +421,19 @@ public class Mantle { throw new RuntimeException("The Mantle is closed"); } - adjustedIdleDuration.set(baseIdleDuration); + double idleDuration = baseIdleDuration; if (loadedRegions.size() > tectonicLimit) { // todo update this correctly and maybe do something when its above a 100% - adjustedIdleDuration.set(Math.max(adjustedIdleDuration.get() - (1000 * (((loadedRegions.size() - tectonicLimit) / (double) tectonicLimit) * 100) * 0.4), 4000)); + idleDuration = Math.max(idleDuration - (1000 * (((loadedRegions.size() - tectonicLimit) / (double) tectonicLimit) * 100) * 0.4), 4000); } + adjustedIdleDuration.set(idleDuration); ioTrim.set(true); try { - double adjustedIdleDuration = this.adjustedIdleDuration.get(); - Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration, 0)); + Iris.debug("Trimming Tectonic Plates older than " + Form.duration(idleDuration, 0)); if (lastUse.isEmpty()) return; - double unloadTime = M.ms() - adjustedIdleDuration; + double unloadTime = M.ms() - idleDuration; for (long id : lastUse.keySet()) { hyperLock.withLong(id, () -> { Long lastUseTime = lastUse.get(id); @@ -462,6 +462,7 @@ public class Mantle { ioTectonicUnload.set(true); try { for (long id : toUnload) { + double unloadTime = M.ms() - adjustedIdleDuration.get(); burst.queue(() -> hyperLock.withLong(id, () -> { TectonicPlate m = loadedRegions.get(id); if (m == null) { @@ -470,6 +471,11 @@ public class Mantle { return; } + var used = lastUse.getOrDefault(id, 0L); + if (!toUnload.contains(id) || used >= unloadTime) { + return; + } + if (m.inUse()) { Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ()); lastUse.put(id, M.ms()); @@ -522,9 +528,11 @@ public class Mantle { } } - TectonicPlate p = loadedRegions.get(key(x, z)); + Long key = key(x, z); + TectonicPlate p = loadedRegions.get(key); if (p != null) { + use(key); return p; } @@ -556,12 +564,12 @@ public class Mantle { TectonicPlate p = loadedRegions.get(k); if (p != null) { - lastUse.put(k, M.ms()); + use(k); return CompletableFuture.completedFuture(p); } return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> { - lastUse.put(k, M.ms()); + use(k); TectonicPlate region = loadedRegions.get(k); if (region != null) { @@ -602,6 +610,11 @@ public class Mantle { })); } + private void use(Long key) { + lastUse.put(key, M.ms()); + toUnload.remove(key); + } + public void saveAll() { } From 9d6e4e87d8477aae5ef12e8f4d430b589f8c6acc Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 22 Jul 2025 12:11:41 +0200 Subject: [PATCH 18/36] fix custom blocks not placing --- core/src/main/java/com/volmit/iris/engine/framework/Engine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index 010628b7d..1e39c8667 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -262,7 +262,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat getMantle().updateBlock(x, y, z); } if (data instanceof IrisCustomData) { - getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.CUSTOM, true); + getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.CUSTOM_ACTIVE, true); } } From fc54fcb7eb70c1206cb509806d029a6aa81a0398 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 22 Jul 2025 12:12:13 +0200 Subject: [PATCH 19/36] make itemsadder data provider standalone --- .../core/link/data/ItemAdderDataProvider.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java index c0bf27ef4..f030fc6a8 100644 --- a/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java @@ -3,10 +3,14 @@ package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; import com.volmit.iris.core.link.ExternalDataProvider; import com.volmit.iris.core.link.Identifier; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.data.B; +import com.volmit.iris.util.data.IrisCustomData; import dev.lone.itemsadder.api.CustomBlock; import dev.lone.itemsadder.api.CustomStack; +import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -40,7 +44,11 @@ public class ItemAdderDataProvider extends ExternalDataProvider { @NotNull @Override public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { - return CustomBlock.getBaseBlockData(blockId.toString()); + CustomBlock block = CustomBlock.getInstance(blockId.toString()); + if (block == null) { + throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); + } + return new IrisCustomData(B.getAir(), blockId); } @NotNull @@ -53,6 +61,11 @@ public class ItemAdderDataProvider extends ExternalDataProvider { return stack.getItemStack(); } + @Override + public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) { + CustomBlock.place(blockId.toString(), block.getLocation()); + } + @Override public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { return switch (dataType) { From 3949468a6080bbb4ba300ad936ff155b71f8932d Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 23 Jul 2025 14:45:54 +0200 Subject: [PATCH 20/36] inject into the library loader to make sure libraries can always be loaded --- .../com/volmit/iris/util/misc/SlimJar.java | 122 +++++++++++++++--- 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java index fa79b849d..e4c882b74 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -1,20 +1,35 @@ package com.volmit.iris.util.misc; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.container.Pair; import io.github.slimjar.app.builder.ApplicationBuilder; +import io.github.slimjar.exceptions.InjectorException; +import io.github.slimjar.injector.loader.Injectable; +import io.github.slimjar.injector.loader.InjectableFactory; +import io.github.slimjar.injector.loader.IsolatedInjectableClassLoader; import io.github.slimjar.logging.ProcessLogger; +import io.github.slimjar.resolver.data.Repository; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiFunction; +import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; public class SlimJar { - private static final Logger LOGGER = Logger.getLogger("Iris"); + private static final String NAME = "Iris"; + private static final Logger LOGGER = Logger.getLogger(NAME); private static final ReentrantLock lock = new ReentrantLock(); private static final AtomicBoolean loaded = new AtomicBoolean(); + private static final boolean DISABLE_REMAPPER = Boolean.getBoolean("iris.disable-remapper"); public static void debug(boolean debug) { LOGGER.setLevel(debug ? Level.FINE : Level.INFO); @@ -31,28 +46,99 @@ public class SlimJar { } LOGGER.info("Loading libraries..."); - ApplicationBuilder.appending("Iris") - .downloadDirectoryPath(localRepository.toPath()) - .logger(new ProcessLogger() { - @Override - public void info(@NotNull String message, @Nullable Object... args) { - LOGGER.fine(message.formatted(args)); - } + load(localRepository.toPath(), new ProcessLogger() { + @Override + public void info(@NotNull String message, @Nullable Object... args) { + LOGGER.fine(message.formatted(args)); + } - @Override - public void error(@NotNull String message, @Nullable Object... args) { - LOGGER.severe(message.formatted(args)); - } + @Override + public void error(@NotNull String message, @Nullable Object... args) { + LOGGER.severe(message.formatted(args)); + } - @Override - public void debug(@NotNull String message, @Nullable Object... args) { - LOGGER.fine(message.formatted(args)); - } - }) - .build(); + @Override + public void debug(@NotNull String message, @Nullable Object... args) { + LOGGER.fine(message.formatted(args)); + } + }); LOGGER.info("Libraries loaded successfully!"); } finally { lock.unlock(); } } + + private static void load(Path downloadPath, ProcessLogger logger) { + try { + loadSpigot(downloadPath, logger); + } catch (Throwable e) { + Iris.warn("Failed to inject the library loader, falling back to application builder"); + ApplicationBuilder.appending(NAME) + .downloadDirectoryPath(downloadPath) + .logger(logger) + .build(); + } + } + + private static void loadSpigot(Path downloadPath, ProcessLogger logger) throws Throwable { + var current = SlimJar.class.getClassLoader(); + var libraryLoader = current.getClass().getDeclaredField("libraryLoader"); + libraryLoader.setAccessible(true); + if (!ClassLoader.class.isAssignableFrom(libraryLoader.getType())) throw new IllegalStateException("Failed to find library loader"); + + final var pair = findRemapper(); + final var remapper = pair.getA(); + final var factory = pair.getB(); + + final var libraries = factory.apply(new URL[0], current.getParent()); + final var injecting = InjectableFactory.create(downloadPath, List.of(Repository.central()), libraries); + + ApplicationBuilder.injecting(NAME, new Injectable() { + @Override + public void inject(@NotNull URL url) throws InjectorException { + try { + final List mapped; + synchronized (remapper) { + mapped = remapper.apply(List.of(Path.of(url.toURI()))); + } + + for (final Path path : mapped) { + injecting.inject(path.toUri().toURL()); + } + } catch (Throwable e) { + throw new InjectorException("Failed to inject " + url, e); + } + } + + @Override + public boolean isThreadSafe() { + return injecting.isThreadSafe(); + } + }) + .downloadDirectoryPath(downloadPath) + .logger(logger) + .build(); + + libraryLoader.set(current, libraries); + } + + private static Pair, List>, BiFunction> findRemapper() { + Function, List> mapper = null; + BiFunction factory = null; + if (!DISABLE_REMAPPER) { + try { + var libraryLoader = Class.forName("org.bukkit.plugin.java.LibraryLoader"); + var mapperField = libraryLoader.getDeclaredField("REMAPPER"); + var factoryField = libraryLoader.getDeclaredField("LIBRARY_LOADER_FACTORY"); + mapperField.setAccessible(true); + factoryField.setAccessible(true); + mapper = (Function, List>) mapperField.get(null); + factory = (BiFunction) factoryField.get(null); + } catch (Throwable ignored) {} + } + + if (mapper == null) mapper = Function.identity(); + if (factory == null) factory = (urls, parent) -> new IsolatedInjectableClassLoader(urls, List.of(), parent); + return new Pair<>(mapper, factory); + } } From e5f2fee926045c983053f6de520c7c499518db62 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 23 Jul 2025 15:07:06 +0200 Subject: [PATCH 21/36] add info about used commit to sentry reports --- core/build.gradle.kts | 8 ++++++++ .../src/main/java/com/volmit/iris/util/misc/Bindings.java | 7 +++++++ core/src/main/resources/plugin.yml | 2 ++ 3 files changed, 17 insertions(+) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index ef7cc7168..a559f2b7f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -137,6 +137,14 @@ tasks { "version" to rootProject.version, "apiVersion" to apiVersion, "main" to main, + "environment" to if (project.hasProperty("release")) "production" else "development", + "commit" to provider { + ProcessBuilder("git", "rev-parse", "HEAD") + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .start() + .inputStream.bufferedReader().readText().trim() + .takeIf { it.length == 40 } ?: "unknown" + } ) filesMatching("**/plugin.yml") { expand(inputs.properties) diff --git a/core/src/main/java/com/volmit/iris/util/misc/Bindings.java b/core/src/main/java/com/volmit/iris/util/misc/Bindings.java index 308d3d235..6dea9f4a8 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/Bindings.java +++ b/core/src/main/java/com/volmit/iris/util/misc/Bindings.java @@ -23,9 +23,11 @@ import org.bstats.charts.SimplePie; import org.bstats.charts.SingleLineChart; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import oshi.SystemInfo; +import java.io.InputStreamReader; import java.math.RoundingMode; import java.text.NumberFormat; import java.util.HashMap; @@ -45,6 +47,9 @@ public class Bindings { if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) return; Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings."); Iris.info("Your server ID is: " + ServerID.ID); + var resource = Iris.instance.getResource("plugin.yml"); + YamlConfiguration desc = resource != null ? YamlConfiguration.loadConfiguration(new InputStreamReader(resource)) : new YamlConfiguration(); + Sentry.init(options -> { options.setDsn("https://b16ecc222e9c1e0c48faecacb906fd89@o4509451052646400.ingest.de.sentry.io/4509452722765904"); if (settings.debug) { @@ -55,6 +60,7 @@ public class Bindings { options.setAttachServerName(false); options.setEnableUncaughtExceptionHandler(false); options.setRelease(Iris.instance.getDescription().getVersion()); + options.setEnvironment(desc.getString("environment", "production")); options.setBeforeSend((event, hint) -> { if (suppress(event.getThrowable())) return null; event.setTag("iris.safeguard", IrisSafeguard.mode()); @@ -71,6 +77,7 @@ public class Bindings { scope.setTag("server", Bukkit.getVersion()); scope.setTag("server.type", Bukkit.getName()); scope.setTag("server.api", Bukkit.getBukkitVersion()); + scope.setTag("iris.commit", desc.getString("commit", "unknown")); }); Runtime.getRuntime().addShutdownHook(new Thread(Sentry::close)); } diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 99fa326be..f871ec1e3 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -5,6 +5,8 @@ load: STARTUP authors: [ cyberpwn, NextdoorPsycho, Vatuu ] website: volmit.com description: More than a Dimension! +environment: '${environment}' +commit: '${commit}' commands: iris: aliases: [ ir, irs ] From 16a4d20c90352ff579497c5368e058084b5d1bc1 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 23 Jul 2025 18:06:52 +0200 Subject: [PATCH 22/36] use grgit to resolve current commit --- core/build.gradle.kts | 9 ++++----- gradle/libs.versions.toml | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index a559f2b7f..ef3c51465 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -26,6 +26,7 @@ plugins { alias(libs.plugins.shadow) alias(libs.plugins.sentry) alias(libs.plugins.slimjar) + alias(libs.plugins.grgit) } val apiVersion = "1.19" @@ -139,11 +140,9 @@ tasks { "main" to main, "environment" to if (project.hasProperty("release")) "production" else "development", "commit" to provider { - ProcessBuilder("git", "rev-parse", "HEAD") - .redirectOutput(ProcessBuilder.Redirect.PIPE) - .start() - .inputStream.bufferedReader().readText().trim() - .takeIf { it.length == 40 } ?: "unknown" + runCatching { grgit.head().id } + .getOrDefault("") + .takeIf { it.length == 40 } ?: "unknown" } ) filesMatching("**/plugin.yml") { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f697c836e..cc74057db 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ slimjar = "2.0.8" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin +grgit = "5.3.2" # https://github.com/ajoberstar/grgit # Core Libraries lombok = "1.18.38" @@ -100,3 +101,4 @@ slimjar = { id = "de.crazydev22.slimjar", version.ref = "slimjar" } download = { id = "de.undercouch.download", version.ref = "download" } runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" } sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentryPlugin" } +grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" } From 556bef6e4309440da14ca18a47537009920794f8 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 25 Jul 2025 12:44:01 +0200 Subject: [PATCH 23/36] fix more unsafe mantle chunk accesses --- .../com/volmit/iris/util/mantle/Mantle.java | 90 ++++++++++--------- .../iris/util/mantle/TectonicPlate.java | 8 ++ 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java index 6851c4cea..c48c43bd8 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -47,7 +47,6 @@ import org.bukkit.Chunk; import java.io.EOFException; import java.io.File; import java.io.IOException; -import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -58,16 +57,18 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class Mantle { + private static final int LOCK_SIZE = Short.MAX_VALUE; + private final File dataFolder; @Getter private final int worldHeight; - private final Map lastUse; - private final Map loadedRegions; + private final KMap lastUse; + private final KMap loadedRegions; private final HyperLock hyperLock; private final AtomicBoolean closed; private final MultiBurst ioBurst; - private final AtomicBoolean ioTrim; - private final AtomicBoolean ioTectonicUnload; + private final Semaphore ioTrim; + private final Semaphore ioTectonicUnload; private final AtomicDouble adjustedIdleDuration; private final KSet toUnload; @@ -83,8 +84,8 @@ public class Mantle { this.closed = new AtomicBoolean(false); this.dataFolder = dataFolder; this.worldHeight = worldHeight; - this.ioTrim = new AtomicBoolean(false); - this.ioTectonicUnload = new AtomicBoolean(false); + this.ioTrim = new Semaphore(LOCK_SIZE, true); + this.ioTectonicUnload = new Semaphore(LOCK_SIZE, true); loadedRegions = new KMap<>(); lastUse = new KMap<>(); ioBurst = MultiBurst.burst; @@ -428,7 +429,7 @@ public class Mantle { } adjustedIdleDuration.set(idleDuration); - ioTrim.set(true); + ioTrim.acquireUninterruptibly(LOCK_SIZE); try { Iris.debug("Trimming Tectonic Plates older than " + Form.duration(idleDuration, 0)); @@ -446,7 +447,7 @@ public class Mantle { } catch (Throwable e) { Iris.reportError(e); } finally { - ioTrim.set(false); + ioTrim.release(LOCK_SIZE); } } @@ -459,7 +460,7 @@ public class Mantle { BurstExecutor burst = ioBurst.burst(toUnload.size()); burst.setMulticore(toUnload.size() > tectonicLimit); - ioTectonicUnload.set(true); + ioTectonicUnload.acquireUninterruptibly(LOCK_SIZE); try { for (long id : toUnload) { double unloadTime = M.ms() - adjustedIdleDuration.get(); @@ -478,15 +479,14 @@ public class Mantle { if (m.inUse()) { Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ()); - lastUse.put(id, M.ms()); - toUnload.remove(id); + use(id); return; } try { m.write(fileForRegion(dataFolder, id, false)); oldFileForRegion(dataFolder, id).delete(); - loadedRegions.remove(id); + loadedRegions.remove(id, m); lastUse.remove(id); toUnload.remove(id); i.incrementAndGet(); @@ -502,7 +502,7 @@ public class Mantle { e.printStackTrace(); burst.complete(); } finally { - ioTectonicUnload.set(false); + ioTectonicUnload.release(LOCK_SIZE); } return i.get(); } @@ -518,32 +518,39 @@ public class Mantle { */ @RegionCoordinates private TectonicPlate get(int x, int z) { - if (ioTrim.get() || ioTectonicUnload.get()) { + boolean trim = ioTrim.tryAcquire(); + boolean unload = ioTectonicUnload.tryAcquire(); + try { + if (!trim || !unload) { + try { + return getSafe(x, z).get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + } + + Long key = key(x, z); + TectonicPlate p = loadedRegions.get(key); + + if (p != null && !p.isClosed()) { + use(key); + return p; + } + try { return getSafe(x, z).get(); } catch (InterruptedException e) { - e.printStackTrace(); + Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)"); + Iris.reportError(e); } catch (ExecutionException e) { - e.printStackTrace(); + Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)"); + Iris.reportError(e); } - } - - Long key = key(x, z); - TectonicPlate p = loadedRegions.get(key); - - if (p != null) { - use(key); - return p; - } - - try { - return getSafe(x, z).get(); - } catch (InterruptedException e) { - Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)"); - Iris.reportError(e); - } catch (ExecutionException e) { - Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)"); - Iris.reportError(e); + } finally { + if (trim) ioTrim.release(); + if (unload) ioTectonicUnload.release(); } Iris.warn("Retrying to get " + x + " " + z + " Mantle Region"); @@ -560,19 +567,12 @@ public class Mantle { */ @RegionCoordinates private Future getSafe(int x, int z) { - Long k = key(x, z); - TectonicPlate p = loadedRegions.get(k); - - if (p != null) { - use(k); - return CompletableFuture.completedFuture(p); - } - return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> { + Long k = key(x, z); use(k); TectonicPlate region = loadedRegions.get(k); - if (region != null) { + if (region != null && !region.isClosed()) { return region; } @@ -600,12 +600,14 @@ public class Mantle { Iris.debug("Created new Tectonic Plate (Due to Load Failure) " + C.DARK_GREEN + x + " " + z); } + use(k); return region; } region = new TectonicPlate(worldHeight, x, z); loadedRegions.put(k, region); Iris.debug("Created new Tectonic Plate " + C.DARK_GREEN + x + " " + z); + use(k); return region; })); } diff --git a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java index 101019023..181ce9cd2 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java @@ -39,6 +39,7 @@ import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReferenceArray; /** @@ -52,6 +53,7 @@ public class TectonicPlate { private final int sectionHeight; private final AtomicReferenceArray chunks; + private final AtomicBoolean closed; @Getter private final int x; @@ -67,6 +69,7 @@ public class TectonicPlate { public TectonicPlate(int worldHeight, int x, int z) { this.sectionHeight = worldHeight >> 4; this.chunks = new AtomicReferenceArray<>(1024); + this.closed = new AtomicBoolean(false); this.x = x; this.z = z; } @@ -143,6 +146,7 @@ public class TectonicPlate { } public void close() throws InterruptedException { + closed.set(true); for (int i = 0; i < chunks.length(); i++) { MantleChunk chunk = chunks.get(i); if (chunk != null) { @@ -151,6 +155,10 @@ public class TectonicPlate { } } + public boolean isClosed() { + return closed.get(); + } + /** * Check if a chunk exists in this plate or not (same as get(x, z) != null) * From 08b9058c8f0ba3ee967da80b46caaf295627b4df Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 25 Jul 2025 13:07:13 +0200 Subject: [PATCH 24/36] make git commit retrieval fail safe --- core/build.gradle.kts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index ef3c51465..7365bde48 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,5 +1,6 @@ import io.github.slimjar.func.slimjar import io.github.slimjar.resolver.data.Mirror +import org.ajoberstar.grgit.Grgit import java.net.URI /* @@ -140,10 +141,13 @@ tasks { "main" to main, "environment" to if (project.hasProperty("release")) "production" else "development", "commit" to provider { - runCatching { grgit.head().id } + runCatching { extensions.getByType().head().id } .getOrDefault("") - .takeIf { it.length == 40 } ?: "unknown" - } + .takeIf { it.length == 40 } ?: { + project.logger.error("Git commit hash not found") + "unknown" + }() + }, ) filesMatching("**/plugin.yml") { expand(inputs.properties) From b0ca0e36170c668fe15a5aeeef8a0b497b3cc077 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 25 Jul 2025 13:21:16 +0200 Subject: [PATCH 25/36] whoops messed up the extension retrieval --- core/build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 7365bde48..7f8361822 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -141,10 +141,10 @@ tasks { "main" to main, "environment" to if (project.hasProperty("release")) "production" else "development", "commit" to provider { - runCatching { extensions.getByType().head().id } - .getOrDefault("") + val res = runCatching { project.extensions.getByType().head().id } + res.getOrDefault("") .takeIf { it.length == 40 } ?: { - project.logger.error("Git commit hash not found") + logger.error("Git commit hash not found", res.exceptionOrNull()) "unknown" }() }, From 76a6f1465adfe79acad417606d561715b117914c Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 26 Jul 2025 14:31:45 +0200 Subject: [PATCH 26/36] update slimjar --- core/src/main/java/com/volmit/iris/Iris.java | 1 - .../com/volmit/iris/core/IrisSettings.java | 2 -- .../com/volmit/iris/util/misc/SlimJar.java | 26 +++++++++---------- gradle/libs.versions.toml | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index f299e4409..4bd6c7ffc 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -436,7 +436,6 @@ public class Iris extends VolmitPlugin implements Listener { public Iris() { instance = this; - SlimJar.debug(IrisSettings.get().getSentry().isDebug()); SlimJar.load(getDataFolder("cache", "libraries")); } diff --git a/core/src/main/java/com/volmit/iris/core/IrisSettings.java b/core/src/main/java/com/volmit/iris/core/IrisSettings.java index faaecc8f0..30216b29e 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -23,7 +23,6 @@ import com.volmit.iris.Iris; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONException; import com.volmit.iris.util.json.JSONObject; -import com.volmit.iris.util.misc.SlimJar; import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.plugin.VolmitSender; import lombok.AllArgsConstructor; @@ -87,7 +86,6 @@ public class IrisSettings { Iris.error("Configuration Error in settings.json! " + ee.getClass().getSimpleName() + ": " + ee.getMessage()); } } - SlimJar.debug(settings.general.debug); return settings; } diff --git a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java index e4c882b74..f2cdb771a 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -21,19 +21,16 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiFunction; import java.util.function.Function; -import java.util.logging.Level; import java.util.logging.Logger; public class SlimJar { private static final String NAME = "Iris"; private static final Logger LOGGER = Logger.getLogger(NAME); - private static final ReentrantLock lock = new ReentrantLock(); - private static final AtomicBoolean loaded = new AtomicBoolean(); + private static final boolean DEBUG = Boolean.getBoolean("iris.debug-slimjar"); private static final boolean DISABLE_REMAPPER = Boolean.getBoolean("iris.disable-remapper"); - public static void debug(boolean debug) { - LOGGER.setLevel(debug ? Level.FINE : Level.INFO); - } + private static final ReentrantLock lock = new ReentrantLock(); + private static final AtomicBoolean loaded = new AtomicBoolean(); public static void load(@Nullable File localRepository) { if (loaded.get()) return; @@ -49,7 +46,8 @@ public class SlimJar { load(localRepository.toPath(), new ProcessLogger() { @Override public void info(@NotNull String message, @Nullable Object... args) { - LOGGER.fine(message.formatted(args)); + if (!DEBUG) return; + LOGGER.info(message.formatted(args)); } @Override @@ -59,7 +57,8 @@ public class SlimJar { @Override public void debug(@NotNull String message, @Nullable Object... args) { - LOGGER.fine(message.formatted(args)); + if (!DEBUG) return; + LOGGER.info(message.formatted(args)); } }); LOGGER.info("Libraries loaded successfully!"); @@ -82,15 +81,16 @@ public class SlimJar { private static void loadSpigot(Path downloadPath, ProcessLogger logger) throws Throwable { var current = SlimJar.class.getClassLoader(); - var libraryLoader = current.getClass().getDeclaredField("libraryLoader"); - libraryLoader.setAccessible(true); - if (!ClassLoader.class.isAssignableFrom(libraryLoader.getType())) throw new IllegalStateException("Failed to find library loader"); + var libraryLoaderField = current.getClass().getDeclaredField("libraryLoader"); + libraryLoaderField.setAccessible(true); + if (!ClassLoader.class.isAssignableFrom(libraryLoaderField.getType())) throw new IllegalStateException("Failed to find library loader"); + final var libraryLoader = (ClassLoader) libraryLoaderField.get(current); final var pair = findRemapper(); final var remapper = pair.getA(); final var factory = pair.getB(); - final var libraries = factory.apply(new URL[0], current.getParent()); + final var libraries = factory.apply(new URL[0], libraryLoader == null ? current.getParent() : libraryLoader); final var injecting = InjectableFactory.create(downloadPath, List.of(Repository.central()), libraries); ApplicationBuilder.injecting(NAME, new Injectable() { @@ -119,7 +119,7 @@ public class SlimJar { .logger(logger) .build(); - libraryLoader.set(current, libraries); + libraryLoaderField.set(current, libraries); } private static Pair, List>, BiFunction> findRemapper() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cc74057db..4ea7eb557 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ [versions] # Plugins shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow -slimjar = "2.0.8" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.1.0" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin From 472a98da169819ebc5cfc079b6b0649b9c58bd33 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 27 Jul 2025 18:43:33 +0200 Subject: [PATCH 27/36] update slimjar --- core/build.gradle.kts | 1 + core/src/main/java/com/volmit/iris/util/misc/SlimJar.java | 6 ++++-- gradle/libs.versions.toml | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 7f8361822..140281fbb 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -158,6 +158,7 @@ tasks { mergeServiceFiles() //minimize() relocate("io.github.slimjar", "$lib.slimjar") + exclude("modules/loader-agent.isolated-jar") } } diff --git a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java index f2cdb771a..ccdc58c5b 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -5,8 +5,8 @@ import com.volmit.iris.core.nms.container.Pair; import io.github.slimjar.app.builder.ApplicationBuilder; import io.github.slimjar.exceptions.InjectorException; import io.github.slimjar.injector.loader.Injectable; -import io.github.slimjar.injector.loader.InjectableFactory; import io.github.slimjar.injector.loader.IsolatedInjectableClassLoader; +import io.github.slimjar.injector.loader.factory.InjectableFactory; import io.github.slimjar.logging.ProcessLogger; import io.github.slimjar.resolver.data.Repository; import org.jetbrains.annotations.NotNull; @@ -31,6 +31,7 @@ public class SlimJar { private static final ReentrantLock lock = new ReentrantLock(); private static final AtomicBoolean loaded = new AtomicBoolean(); + private static final InjectableFactory FACTORY = InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE); public static void load(@Nullable File localRepository) { if (loaded.get()) return; @@ -73,6 +74,7 @@ public class SlimJar { } catch (Throwable e) { Iris.warn("Failed to inject the library loader, falling back to application builder"); ApplicationBuilder.appending(NAME) + .injectableFactory(FACTORY) .downloadDirectoryPath(downloadPath) .logger(logger) .build(); @@ -91,7 +93,7 @@ public class SlimJar { final var factory = pair.getB(); final var libraries = factory.apply(new URL[0], libraryLoader == null ? current.getParent() : libraryLoader); - final var injecting = InjectableFactory.create(downloadPath, List.of(Repository.central()), libraries); + final var injecting = FACTORY.create(downloadPath, List.of(Repository.central()), libraries); ApplicationBuilder.injecting(NAME, new Injectable() { @Override diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4ea7eb557..8b6647568 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ [versions] # Plugins shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow -slimjar = "2.1.0" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.1.1" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin From c4539441a0c087473f565a62fa809a39b503d6e4 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 27 Jul 2025 23:22:40 +0200 Subject: [PATCH 28/36] fix datapack generation ignoring worlds when updating from <3.7.0 --- .../java/com/volmit/iris/core/IrisWorlds.java | 43 ++++++++++++++++++- .../volmit/iris/core/ServerConfigurator.java | 5 +-- .../iris/core/safeguard/ServerBootSFG.java | 31 +++---------- 3 files changed, 49 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java index 9c8302102..2e30bf117 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java +++ b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java @@ -4,10 +4,14 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.volmit.iris.Iris; +import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.misc.ServerProperties; import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.io.IOException; @@ -25,6 +29,7 @@ public class IrisWorlds { private IrisWorlds(KMap worlds) { this.worlds = worlds; + readBukkitWorlds().forEach(this::put); save(); } @@ -56,8 +61,19 @@ public class IrisWorlds { save(); } - public Stream getFolders() { - return worlds.keySet().stream().map(k -> new File(Bukkit.getWorldContainer(), k)); + public Stream getPacks() { + return getDimensions() + .map(IrisDimension::getLoader) + .filter(Objects::nonNull); + } + + public Stream getDimensions() { + return readBukkitWorlds() + .put(worlds) + .entrySet() + .stream() + .map(entry -> Iris.loadDimension(entry.getKey(), entry.getValue())) + .filter(Objects::nonNull); } public void clean() { @@ -76,4 +92,27 @@ public class IrisWorlds { Iris.reportError(e); } } + + private static KMap readBukkitWorlds() { + var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); + var worlds = bukkit.getConfigurationSection("worlds"); + if (worlds == null) return new KMap<>(); + + var result = new KMap(); + for (String world : worlds.getKeys(false)) { + var gen = worlds.getString(world + ".generator"); + if (gen == null) continue; + + String loadKey; + if (gen.equalsIgnoreCase("iris")) { + loadKey = IrisSettings.get().getGenerator().getDefaultWorldType(); + } else if (gen.startsWith("Iris:")) { + loadKey = gen.substring(5); + } else continue; + + result.put(world, loadKey); + } + + return result; + } } diff --git a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java index d249bfbcd..51ab974c5 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -237,14 +237,13 @@ public class ServerConfigurator { } public static Stream allPacks() { - return Stream.concat(listFiles(Iris.instance.getDataFolder("packs")), - IrisWorlds.get().getFolders().map(w -> new File(w, "iris/pack"))) + return Stream.concat(listFiles(Iris.instance.getDataFolder("packs")) .filter(File::isDirectory) .filter( base -> { var content = new File(base, "dimensions").listFiles(); return content != null && content.length > 0; }) - .map(IrisData::get); + .map(IrisData::get), IrisWorlds.get().getPacks()); } @Nullable diff --git a/core/src/main/java/com/volmit/iris/core/safeguard/ServerBootSFG.java b/core/src/main/java/com/volmit/iris/core/safeguard/ServerBootSFG.java index 8ec35899f..50de28b29 100644 --- a/core/src/main/java/com/volmit/iris/core/safeguard/ServerBootSFG.java +++ b/core/src/main/java/com/volmit/iris/core/safeguard/ServerBootSFG.java @@ -1,15 +1,13 @@ package com.volmit.iris.core.safeguard; import com.volmit.iris.Iris; -import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.IrisWorlds; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.collection.KSet; -import com.volmit.iris.util.misc.ServerProperties; import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import javax.tools.JavaCompiler; @@ -21,6 +19,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.*; +import java.util.stream.Collectors; import static com.volmit.iris.Iris.getJavaVersion; import static com.volmit.iris.core.safeguard.IrisSafeguard.*; @@ -187,27 +186,9 @@ public class ServerBootSFG { } private static KSet getDimensionTypes() { - var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); - var worlds = bukkit.getConfigurationSection("worlds"); - if (worlds == null) return new KSet<>(); - - var types = new KSet(); - for (String world : worlds.getKeys(false)) { - var gen = worlds.getString(world + ".generator"); - if (gen == null) continue; - - String loadKey; - if (gen.equalsIgnoreCase("iris")) { - loadKey = IrisSettings.get().getGenerator().getDefaultWorldType(); - } else if (gen.startsWith("Iris:")) { - loadKey = gen.substring(5); - } else continue; - - IrisDimension dimension = Iris.loadDimension(world, loadKey); - if (dimension == null) continue; - types.add(dimension.getDimensionTypeKey()); - } - - return types; + return IrisWorlds.get() + .getDimensions() + .map(IrisDimension::getDimensionTypeKey) + .collect(Collectors.toCollection(KSet::new)); } } From 8471f15bc87aa74ef44265fd51881105b4821111 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 27 Jul 2025 23:23:04 +0200 Subject: [PATCH 29/36] make world creation more failsafe --- core/src/main/java/com/volmit/iris/Iris.java | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 4bd6c7ffc..194abbab4 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -501,12 +501,21 @@ public class Iris extends VolmitPlugin implements Listener { Iris.info("Loading World: %s | Generator: %s", s, generator); - Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); - WorldCreator c = new WorldCreator(s) - .generator(getDefaultWorldGenerator(s, generator)) - .environment(IrisData.loadAnyDimension(generator).getEnvironment()); - INMS.get().createWorld(c); - Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); + try { + var gen = getDefaultWorldGenerator(s, generator); + var dim = loadDimension(s, generator); + assert dim != null && gen != null; + + Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); + WorldCreator c = new WorldCreator(s) + .generator(gen) + .environment(dim.getEnvironment()); + INMS.get().createWorld(c); + Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); + } catch (Throwable e) { + Iris.error("Failed to load world " + s + "!"); + e.printStackTrace(); + } } } catch (Throwable e) { e.printStackTrace(); From 501c42630290b9a1daafeb7f42fe0d87ff0377c8 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 12:31:07 +0200 Subject: [PATCH 30/36] fix slimjar error for new projects --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8b6647568..84911a178 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ [versions] # Plugins shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow -slimjar = "2.1.1" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.1.2" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin From 70130e976db202bd71fe94f77bf59854e905afc6 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 13:53:11 +0200 Subject: [PATCH 31/36] add getter method to IrisWorlds --- .../main/java/com/volmit/iris/core/IrisWorlds.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java index 2e30bf117..a46be559e 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java +++ b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java @@ -29,7 +29,7 @@ public class IrisWorlds { private IrisWorlds(KMap worlds) { this.worlds = worlds; - readBukkitWorlds().forEach(this::put); + readBukkitWorlds().forEach(this::put0); save(); } @@ -55,10 +55,18 @@ public class IrisWorlds { } public void put(String name, String type) { + put0(name, type); + save(); + } + + private void put0(String name, String type) { String old = worlds.put(name, type); if (!type.equals(old)) dirty = true; - save(); + } + + public KMap getWorlds() { + return readBukkitWorlds().put(worlds); } public Stream getPacks() { From 74128d58cfac96b91411ff2b88849fd2a1466024 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 15:06:34 +0200 Subject: [PATCH 32/36] disable pack trimming for now --- .../java/com/volmit/iris/core/commands/CommandIris.java | 6 ++++-- .../java/com/volmit/iris/core/commands/CommandStudio.java | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 84f601642..77f794781 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -394,17 +394,19 @@ public class CommandIris implements DecreeExecutor { sender().sendMessage(C.GREEN + "Set debug to: " + to); } + //TODO fix pack trimming @Decree(description = "Download a project.", aliases = "dl") public void download( @Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project") String pack, @Param(name = "branch", description = "The branch to download from", defaultValue = "main") String branch, - @Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") - boolean trim, + //@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") + //boolean trim, @Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false") boolean overwrite ) { + boolean trim = false; sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : "")); if (pack.equals("overworld")) { String url = "https://github.com/IrisDimensions/overworld/releases/download/" + INMS.OVERWORLD_TAG + "/overworld.zip"; diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java index 1635dd3bb..d6261ee23 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java @@ -92,18 +92,19 @@ public class CommandStudio implements DecreeExecutor { return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase(); } + //TODO fix pack trimming @Decree(description = "Download a project.", aliases = "dl") public void download( @Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project") String pack, @Param(name = "branch", description = "The branch to download from", defaultValue = "master") String branch, - @Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") - boolean trim, + //@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") + //boolean trim, @Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false") boolean overwrite ) { - new CommandIris().download(pack, branch, trim, overwrite); + new CommandIris().download(pack, branch, overwrite); } @Decree(description = "Open a new studio world", aliases = "o", sync = true) From fba9c17e3f0381cb61f0cf8008335e3d7e7b4a9d Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 15:08:07 +0200 Subject: [PATCH 33/36] fix not using relocated bukkit.yml correctly and remove duplicate code --- core/src/main/java/com/volmit/iris/Iris.java | 42 ++------- .../java/com/volmit/iris/core/IrisWorlds.java | 2 +- .../iris/core/commands/CommandIris.java | 93 +------------------ .../volmit/iris/core/tools/IrisCreator.java | 3 +- .../iris/util/misc/ServerProperties.java | 31 +++++-- 5 files changed, 39 insertions(+), 132 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 194abbab4..f17fec0be 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -22,6 +22,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.IrisWorlds; import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.link.IrisPapiExpansion; import com.volmit.iris.core.link.MultiverseCoreLink; @@ -65,9 +66,6 @@ import org.bukkit.*; import org.bukkit.block.data.BlockData; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.*; import org.bukkit.generator.BiomeProvider; @@ -81,6 +79,7 @@ import java.io.*; import java.lang.annotation.Annotation; import java.net.URL; import java.util.*; +import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -466,42 +465,19 @@ public class Iris extends VolmitPlugin implements Listener { IrisSafeguard.splash(false); autoStartStudio(); - checkForBukkitWorlds(); + checkForBukkitWorlds(s -> true); IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName()); IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName()); }); } - private void checkForBukkitWorlds() { - FileConfiguration fc = new YamlConfiguration(); + public void checkForBukkitWorlds(Predicate filter) { try { - fc.load(new File("bukkit.yml")); - ConfigurationSection section = fc.getConfigurationSection("worlds"); - if (section == null) { - return; - } - - for (String s : section.getKeys(false)) { - ConfigurationSection entry = section.getConfigurationSection(s); - if (!entry.contains("generator", true)) { - continue; - } - - String generator = entry.getString("generator"); - if (generator.startsWith("Iris:")) { - generator = generator.split("\\Q:\\E")[1]; - } else if (generator.equalsIgnoreCase("Iris")) { - generator = IrisSettings.get().getGenerator().getDefaultWorldType(); - } else { - continue; - } - - if (Bukkit.getWorld(s) != null) - continue; - - Iris.info("Loading World: %s | Generator: %s", s, generator); - + IrisWorlds.readBukkitWorlds().forEach((s, generator) -> { try { + if (Bukkit.getWorld(s) != null || !filter.test(s)) return; + + Iris.info("Loading World: %s | Generator: %s", s, generator); var gen = getDefaultWorldGenerator(s, generator); var dim = loadDimension(s, generator); assert dim != null && gen != null; @@ -516,7 +492,7 @@ public class Iris extends VolmitPlugin implements Listener { Iris.error("Failed to load world " + s + "!"); e.printStackTrace(); } - } + }); } catch (Throwable e) { e.printStackTrace(); reportError(e); diff --git a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java index a46be559e..69721ced2 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java +++ b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java @@ -101,7 +101,7 @@ public class IrisWorlds { } } - private static KMap readBukkitWorlds() { + public static KMap readBukkitWorlds() { var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); var worlds = bukkit.getConfigurationSection("worlds"); if (worlds == null) return new KMap<>(); diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 77f794781..89fa7cf5f 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -20,15 +20,12 @@ package com.volmit.iris.core.commands; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.pregenerator.ChunkUpdater; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.engine.object.IrisWorld; -import com.volmit.iris.engine.platform.BukkitChunkGenerator; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; @@ -44,21 +41,17 @@ import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.WorldCreator; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; -import org.bukkit.generator.ChunkGenerator; import org.bukkit.scheduler.BukkitRunnable; import java.io.*; -import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicReference; -import static com.volmit.iris.Iris.service; import static com.volmit.iris.core.service.EditSVC.deletingWorld; +import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML; import static org.bukkit.Bukkit.getServer; @Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command") @@ -504,7 +497,6 @@ public class CommandIris implements DecreeExecutor { return; } - File BUKKIT_YML = new File("bukkit.yml"); String pathtodim = world + File.separator +"iris"+File.separator +"pack"+File.separator +"dimensions"+File.separator; File directory = new File(Bukkit.getWorldContainer(), pathtodim); @@ -542,7 +534,7 @@ public class CommandIris implements DecreeExecutor { return; } } - checkForBukkitWorlds(world); + Iris.instance.checkForBukkitWorlds(world::equals); sender().sendMessage(C.GREEN + world + " loaded successfully."); } @Decree(description = "Evacuate an iris world", origin = DecreeOrigin.PLAYER, sync = true) @@ -563,85 +555,4 @@ public class CommandIris implements DecreeExecutor { File worldDirectory = new File(worldContainer, worldName); return worldDirectory.exists() && worldDirectory.isDirectory(); } - private void checkForBukkitWorlds(String world) { - FileConfiguration fc = new YamlConfiguration(); - try { - fc.load(new File("bukkit.yml")); - ConfigurationSection section = fc.getConfigurationSection("worlds"); - if (section == null) { - return; - } - - List worldsToLoad = Collections.singletonList(world); - - for (String s : section.getKeys(false)) { - if (!worldsToLoad.contains(s)) { - continue; - } - ConfigurationSection entry = section.getConfigurationSection(s); - if (!entry.contains("generator", true)) { - continue; - } - String generator = entry.getString("generator"); - if (generator.startsWith("Iris:")) { - generator = generator.split("\\Q:\\E")[1]; - } else if (generator.equalsIgnoreCase("Iris")) { - generator = IrisSettings.get().getGenerator().getDefaultWorldType(); - } else { - continue; - } - Iris.info("2 World: %s | Generator: %s", s, generator); - if (Bukkit.getWorlds().stream().anyMatch(w -> w.getName().equals(s))) { - continue; - } - Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); - WorldCreator c = new WorldCreator(s) - .generator(getDefaultWorldGenerator(s, generator)) - .environment(IrisData.loadAnyDimension(generator).getEnvironment()); - INMS.get().createWorld(c); - Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { - Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id); - IrisDimension dim; - if (id == null || id.isEmpty()) { - dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); - } else { - dim = IrisData.loadAnyDimension(id); - } - Iris.debug("Generator ID: " + id + " requested by bukkit/plugin"); - - if (dim == null) { - Iris.warn("Unable to find dimension type " + id + " Looking for online packs..."); - - service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true); - dim = IrisData.loadAnyDimension(id); - - if (dim == null) { - throw new RuntimeException("Can't find dimension " + id + "!"); - } else { - Iris.info("Resolved missing dimension, proceeding with generation."); - } - } - Iris.debug("Assuming IrisDimension: " + dim.getName()); - IrisWorld w = IrisWorld.builder() - .name(worldName) - .seed(1337) - .environment(dim.getEnvironment()) - .worldFolder(new File(Bukkit.getWorldContainer(), worldName)) - .minHeight(dim.getMinHeight()) - .maxHeight(dim.getMaxHeight()) - .build(); - Iris.debug("Generator Config: " + w.toString()); - File ff = new File(w.worldFolder(), "iris/pack"); - if (!ff.exists() || ff.listFiles().length == 0) { - ff.mkdirs(); - service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), ff.getParentFile()); - } - return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey()); - } } diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java index fac42b051..f10cbdfd2 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java @@ -46,13 +46,14 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; +import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML; + /** * Makes it a lot easier to setup an engine, world, studio or whatever */ @Data @Accessors(fluent = true, chain = true) public class IrisCreator { - private static final File BUKKIT_YML = new File("bukkit.yml"); /** * Specify an area to pregenerate during creation */ diff --git a/core/src/main/java/com/volmit/iris/util/misc/ServerProperties.java b/core/src/main/java/com/volmit/iris/util/misc/ServerProperties.java index ecfc4f518..fb9a31c73 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/ServerProperties.java +++ b/core/src/main/java/com/volmit/iris/util/misc/ServerProperties.java @@ -1,5 +1,8 @@ package com.volmit.iris.util.misc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -22,12 +25,13 @@ public class ServerProperties { String bukkitYml = "bukkit.yml"; String levelName = null; - for (int i = 0; i < args.length - 1; i++) { - switch (args[i]) { - case "-c", "--config" -> propertiesPath = args[i + 1]; - case "-b", "--bukkit-settings" -> bukkitYml = args[i + 1]; - case "-w", "--level-name", "--world" -> levelName = args[i + 1]; - } + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + String next = i < args.length - 1 ? args[i + 1] : null; + + propertiesPath = parse(arg, next, propertiesPath, "-c", "--config"); + bukkitYml = parse(arg, next, bukkitYml, "-b", "--bukkit-settings"); + levelName = parse(arg, next, levelName, "-w", "--level-name", "--world"); } SERVER_PROPERTIES = new File(propertiesPath); @@ -41,4 +45,19 @@ public class ServerProperties { if (levelName != null) LEVEL_NAME = levelName; else LEVEL_NAME = DATA.getProperty("level-name", "world"); } + + private static String parse( + @NotNull String current, + @Nullable String next, + String fallback, + @NotNull String @NotNull ... keys + ) { + for (String k : keys) { + if (current.equals(k) && next != null) + return next; + if (current.startsWith(k + "=") && current.length() > k.length() + 1) + return current.substring(k.length() + 1); + } + return fallback; + } } From 0648cfd3fa2eaa6a24a6c8b12282c33c3b6b6fe6 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 15:16:21 +0200 Subject: [PATCH 34/36] add message for promotion of world to main world --- .../src/main/java/com/volmit/iris/core/commands/CommandIris.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 89fa7cf5f..3f1c0b588 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -123,6 +123,7 @@ public class CommandIris implements DecreeExecutor { } worldCreation = false; sender().sendMessage(C.GREEN + "Successfully created your world!"); + if (main) sender().sendMessage(C.GREEN + "Your world will automatically be set as the main world when the server restarts."); } @SneakyThrows From a610d0a7a97d013188db665ff98da764433c5355 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 20:53:01 +0200 Subject: [PATCH 35/36] remove unnecessary classpath injections --- .../iris/core/tools/IrisWorldCreator.java | 3 -- .../volmit/iris/util/collection/KList.java | 13 ++++++ .../iris/util/function/NastyFunction.java | 3 +- .../com/volmit/iris/util/misc/SlimJar.java | 40 +++++-------------- 4 files changed, 24 insertions(+), 35 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisWorldCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisWorldCreator.java index 97ec2eceb..cd6c17a91 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisWorldCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisWorldCreator.java @@ -21,13 +21,10 @@ package com.volmit.iris.core.tools; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.platform.BukkitChunkGenerator; -import com.volmit.iris.util.reflect.WrappedField; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.WorldCreator; -import org.bukkit.WorldType; import org.bukkit.generator.ChunkGenerator; -import sun.misc.Unsafe; import java.io.File; diff --git a/core/src/main/java/com/volmit/iris/util/collection/KList.java b/core/src/main/java/com/volmit/iris/util/collection/KList.java index bf1cf916d..a22c562db 100644 --- a/core/src/main/java/com/volmit/iris/util/collection/KList.java +++ b/core/src/main/java/com/volmit/iris/util/collection/KList.java @@ -19,6 +19,7 @@ package com.volmit.iris.util.collection; import com.google.common.util.concurrent.AtomicDoubleArray; +import com.volmit.iris.util.function.NastyFunction; import com.volmit.iris.util.json.JSONArray; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; @@ -306,6 +307,18 @@ public class KList extends ArrayList implements List { return v; } + /** + * Convert this list into another list type. Such as GList to + * GList. list.convertNasty((i) -> "" + i); + */ + public KList convertNasty(NastyFunction converter) throws Throwable { + KList v = new KList(size()); + for (final var t : this) { + v.addNonNull(converter.run(t)); + } + return v; + } + public KList removeWhere(Predicate t) { for (T i : copy()) { if (t.test(i)) { diff --git a/core/src/main/java/com/volmit/iris/util/function/NastyFunction.java b/core/src/main/java/com/volmit/iris/util/function/NastyFunction.java index f490848a2..dd056c169 100644 --- a/core/src/main/java/com/volmit/iris/util/function/NastyFunction.java +++ b/core/src/main/java/com/volmit/iris/util/function/NastyFunction.java @@ -18,6 +18,7 @@ package com.volmit.iris.util.function; +@FunctionalInterface public interface NastyFunction { - R run(T t); + R run(T t) throws Throwable; } diff --git a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java index ccdc58c5b..488000bf9 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -2,13 +2,11 @@ package com.volmit.iris.util.misc; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.container.Pair; +import com.volmit.iris.util.collection.KList; import io.github.slimjar.app.builder.ApplicationBuilder; -import io.github.slimjar.exceptions.InjectorException; -import io.github.slimjar.injector.loader.Injectable; import io.github.slimjar.injector.loader.IsolatedInjectableClassLoader; import io.github.slimjar.injector.loader.factory.InjectableFactory; import io.github.slimjar.logging.ProcessLogger; -import io.github.slimjar.resolver.data.Repository; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,7 +29,6 @@ public class SlimJar { private static final ReentrantLock lock = new ReentrantLock(); private static final AtomicBoolean loaded = new AtomicBoolean(); - private static final InjectableFactory FACTORY = InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE); public static void load(@Nullable File localRepository) { if (loaded.get()) return; @@ -74,7 +71,7 @@ public class SlimJar { } catch (Throwable e) { Iris.warn("Failed to inject the library loader, falling back to application builder"); ApplicationBuilder.appending(NAME) - .injectableFactory(FACTORY) + .injectableFactory(InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE)) .downloadDirectoryPath(downloadPath) .logger(logger) .build(); @@ -91,37 +88,18 @@ public class SlimJar { final var pair = findRemapper(); final var remapper = pair.getA(); final var factory = pair.getB(); + final var classpath = new KList(); - final var libraries = factory.apply(new URL[0], libraryLoader == null ? current.getParent() : libraryLoader); - final var injecting = FACTORY.create(downloadPath, List.of(Repository.central()), libraries); - - ApplicationBuilder.injecting(NAME, new Injectable() { - @Override - public void inject(@NotNull URL url) throws InjectorException { - try { - final List mapped; - synchronized (remapper) { - mapped = remapper.apply(List.of(Path.of(url.toURI()))); - } - - for (final Path path : mapped) { - injecting.inject(path.toUri().toURL()); - } - } catch (Throwable e) { - throw new InjectorException("Failed to inject " + url, e); - } - } - - @Override - public boolean isThreadSafe() { - return injecting.isThreadSafe(); - } - }) + ApplicationBuilder.injecting(NAME, classpath::add) .downloadDirectoryPath(downloadPath) .logger(logger) .build(); - libraryLoaderField.set(current, libraries); + final var urls = remapper.andThen(KList::new) + .apply(classpath.convertNasty(url -> Path.of(url.toURI()))) + .convertNasty(path -> path.toUri().toURL()) + .toArray(URL[]::new); + libraryLoaderField.set(current, factory.apply(urls, libraryLoader == null ? current.getParent() : libraryLoader)); } private static Pair, List>, BiFunction> findRemapper() { From 8705ca6e47005831d419de605dab43ec275188d2 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 21:44:27 +0200 Subject: [PATCH 36/36] save structure placed at block --- .../com/volmit/iris/engine/IrisEngine.java | 7 ++++ .../volmit/iris/engine/framework/Engine.java | 3 ++ .../iris/engine/jigsaw/PlannedStructure.java | 7 ++-- .../matter/slices/JigsawStructureMatter.java | 35 +++++++++++++++++++ .../container/JigsawStructureContainer.java | 13 +++++++ 5 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/matter/slices/JigsawStructureMatter.java create mode 100644 core/src/main/java/com/volmit/iris/util/matter/slices/container/JigsawStructureContainer.java diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java index 2f9bd5a88..e5db0d978 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -47,6 +47,7 @@ import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.MatterStructurePOI; +import com.volmit.iris.util.matter.slices.container.JigsawStructureContainer; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; @@ -223,6 +224,12 @@ public class IrisEngine implements Engine { return getMantle().getJigsawComponent().guess(x, z); } + @Override + public IrisJigsawStructure getStructureAt(int x, int y, int z) { + var container = getMantle().getMantle().get(x, y, z, JigsawStructureContainer.class); + return container == null ? null : container.load(getData()); + } + private void warmupChunk(int x, int z) { for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index 1e39c8667..40072c47b 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -231,6 +231,9 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat @ChunkCoordinates IrisJigsawStructure getStructureAt(int x, int z); + @BlockCoordinates + IrisJigsawStructure getStructureAt(int x, int y, int z); + @BlockCoordinates default IrisBiome getCaveBiome(int x, int z) { return getComplex().getCaveBiomeStream().get(x, z); diff --git a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java index d6a49b58f..c045cf922 100644 --- a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java +++ b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java @@ -29,6 +29,7 @@ import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer; +import com.volmit.iris.util.matter.slices.container.JigsawStructureContainer; import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer; import com.volmit.iris.util.scheduling.J; import lombok.Data; @@ -149,11 +150,13 @@ public class PlannedStructure { } int id = rng.i(0, Integer.MAX_VALUE); - JigsawPieceContainer container = JigsawPieceContainer.toContainer(i.getPiece()); + JigsawPieceContainer piece = JigsawPieceContainer.toContainer(i.getPiece()); + JigsawStructureContainer structure = JigsawStructureContainer.toContainer(getStructure()); i.setRealPositions(xx, height, zz, placer); return v.place(xx, height, zz, placer, options, rng, (b, data) -> { e.set(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id); - e.set(b.getX(), b.getY(), b.getZ(), container); + e.set(b.getX(), b.getY(), b.getZ(), structure); + e.set(b.getX(), b.getY(), b.getZ(), piece); }, null, getData().getEngine() != null ? getData() : eng.getData()) != -1; } diff --git a/core/src/main/java/com/volmit/iris/util/matter/slices/JigsawStructureMatter.java b/core/src/main/java/com/volmit/iris/util/matter/slices/JigsawStructureMatter.java new file mode 100644 index 000000000..6e9ec2ce0 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/matter/slices/JigsawStructureMatter.java @@ -0,0 +1,35 @@ +package com.volmit.iris.util.matter.slices; + +import com.volmit.iris.util.data.palette.Palette; +import com.volmit.iris.util.matter.Sliced; +import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +@Sliced +public class JigsawStructureMatter extends RawMatter { + public JigsawStructureMatter() { + this(1,1,1); + } + + public JigsawStructureMatter(int width, int height, int depth) { + super(width, height, depth, JigsawPieceContainer.class); + } + + @Override + public Palette getGlobalPalette() { + return null; + } + + @Override + public void writeNode(JigsawPieceContainer b, DataOutputStream dos) throws IOException { + dos.writeUTF(b.getLoadKey()); + } + + @Override + public JigsawPieceContainer readNode(DataInputStream din) throws IOException { + return new JigsawPieceContainer(din.readUTF()); + } +} diff --git a/core/src/main/java/com/volmit/iris/util/matter/slices/container/JigsawStructureContainer.java b/core/src/main/java/com/volmit/iris/util/matter/slices/container/JigsawStructureContainer.java new file mode 100644 index 000000000..bd581ede3 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/matter/slices/container/JigsawStructureContainer.java @@ -0,0 +1,13 @@ +package com.volmit.iris.util.matter.slices.container; + +import com.volmit.iris.engine.object.IrisJigsawStructure; + +public class JigsawStructureContainer extends RegistrantContainer { + public JigsawStructureContainer(String loadKey) { + super(IrisJigsawStructure.class, loadKey); + } + + public static JigsawStructureContainer toContainer(IrisJigsawStructure structure) { + return new JigsawStructureContainer(structure.getLoadKey()); + } +}