diff --git a/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java b/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java index bb4896e24..fd0d82591 100644 --- a/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/ParallaxChunkGenerator.java @@ -376,6 +376,12 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple return s; } + @Override + public boolean isDebugSmartBore() + { + return getDimension().isDebugSmartBore(); + } + @Override public boolean isPreventingDecay() { diff --git a/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java b/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java index 6baa05ac8..57944fe9b 100644 --- a/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java +++ b/src/main/java/com/volmit/iris/gen/TerrainChunkGenerator.java @@ -588,6 +588,24 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator current = glBiome.generateData(InferredType.SHORE, wx, wz, x, z, region); } + // Impure Remove rivers, lakes & sea from land + if(current.isAquatic() && land) + { + current = glBiome.generatePureData(InferredType.LAND, wx, wz, x, z, region); + } + + // Impure Remove land from underwater + if(current.isLand() && sea) + { + current = glBiome.generatePureData(aquaticType, wx, wz, x, z, region); + } + + // Impure Add shores to land + if(shore) + { + current = glBiome.generatePureData(InferredType.SHORE, wx, wz, x, z, region); + } + return current; } diff --git a/src/main/java/com/volmit/iris/gen/layer/BiomeDataProvider.java b/src/main/java/com/volmit/iris/gen/layer/BiomeDataProvider.java index 3a7a4802a..d0be40aa4 100644 --- a/src/main/java/com/volmit/iris/gen/layer/BiomeDataProvider.java +++ b/src/main/java/com/volmit/iris/gen/layer/BiomeDataProvider.java @@ -25,11 +25,11 @@ public class BiomeDataProvider public IrisBiome generatePureData(ContextualChunkGenerator g, double bx, double bz, int rawX, int rawZ, IrisRegion regionData) { - return layer.generateBiomeData(bx, bz, regionData, getGenerator(), regionData.getBiomes(g, getType()), getType(), rawX, rawZ); + return layer.generateBiomeData(bx, bz, regionData, getGenerator(), regionData.getBiomes(g, getType()), getType(), rawX, rawZ, true); } public IrisBiome generateData(ContextualChunkGenerator g, double bx, double bz, int rawX, int rawZ, IrisRegion regionData) { - return layer.generateImpureData(rawX, rawZ, getType(), regionData, generatePureData(g, bx, bz, rawX, rawZ, regionData)); + return layer.generateBiomeData(bx, bz, regionData, getGenerator(), regionData.getBiomes(g, getType()), getType(), rawX, rawZ, false); } } diff --git a/src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java b/src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java index 9ee3bab83..8d8dece35 100644 --- a/src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java +++ b/src/main/java/com/volmit/iris/gen/layer/GenLayerBiome.java @@ -72,6 +72,11 @@ public class GenLayerBiome extends GenLayer return getProvider(type).generateData(iris, bx, bz, rawX, rawZ, regionData); } + public IrisBiome generatePureData(InferredType type, double bx, double bz, int rawX, int rawZ, IrisRegion regionData) + { + return getProvider(type).generatePureData(iris, bx, bz, rawX, rawZ, regionData); + } + public BiomeDataProvider getProvider(InferredType type) { if(type.equals(InferredType.SEA)) @@ -151,19 +156,27 @@ public class GenLayerBiome extends GenLayer public IrisBiome generateBiomeData(double bx, double bz, IrisRegion regionData, CNG cell, KList biomes, InferredType inferredType, int rx, int rz) { - for(IrisRegionRidge i : regionData.getRidgeBiomes()) - { - if(i.getType().equals(inferredType) && i.isRidge(rng, rx, rz)) - { - return iris.loadBiome(i.getBiome()).infer(i.getAs(), inferredType); - } - } + return generateBiomeData(bx, bz, regionData, cell, biomes, inferredType, rx, rz, false); + } - for(IrisRegionSpot i : regionData.getSpotBiomes()) + public IrisBiome generateBiomeData(double bx, double bz, IrisRegion regionData, CNG cell, KList biomes, InferredType inferredType, int rx, int rz, boolean pure) + { + if(!pure) { - if(i.getType().equals(inferredType) && i.isSpot(rng, rx, rz)) + for(IrisRegionRidge i : regionData.getRidgeBiomes()) { - return iris.loadBiome(i.getBiome()).infer(i.getAs(), inferredType); + if(i.getType().equals(inferredType) && i.isRidge(rng, rx, rz)) + { + return iris.loadBiome(i.getBiome()).infer(i.getAs(), inferredType); + } + } + + for(IrisRegionSpot i : regionData.getSpotBiomes()) + { + if(i.getType().equals(inferredType) && i.isSpot(rng, rx, rz)) + { + return iris.loadBiome(i.getBiome()).infer(i.getAs(), inferredType); + } } } diff --git a/src/main/java/com/volmit/iris/object/IrisDimension.java b/src/main/java/com/volmit/iris/object/IrisDimension.java index de66aa67c..abec7a09a 100644 --- a/src/main/java/com/volmit/iris/object/IrisDimension.java +++ b/src/main/java/com/volmit/iris/object/IrisDimension.java @@ -130,6 +130,10 @@ public class IrisDimension extends IrisRegistrant @Desc("Generate caves or not.") private boolean caves = true; + @DontObfuscate + @Desc("Instead of filling objects with air, fills them with cobweb so you can see them") + private boolean debugSmartBore = false; + @DontObfuscate @Desc("Carve terrain or not") private boolean carving = true; diff --git a/src/main/java/com/volmit/iris/object/IrisObject.java b/src/main/java/com/volmit/iris/object/IrisObject.java index 122478626..a71ea7ba4 100644 --- a/src/main/java/com/volmit/iris/object/IrisObject.java +++ b/src/main/java/com/volmit/iris/object/IrisObject.java @@ -17,10 +17,12 @@ import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.Leaves; import org.bukkit.util.BlockVector; +import com.volmit.iris.Iris; import com.volmit.iris.util.B; import com.volmit.iris.util.BlockPosition; import com.volmit.iris.util.ChunkPosition; import com.volmit.iris.util.IObjectPlacer; +import com.volmit.iris.util.IrisLock; import com.volmit.iris.util.KMap; import com.volmit.iris.util.RNG; @@ -32,6 +34,8 @@ import lombok.EqualsAndHashCode; public class IrisObject extends IrisRegistrant { private static final BlockData AIR = B.getBlockData("CAVE_AIR"); + private static final BlockData VAIR = B.getBlockData("VOID_AIR"); + private static final BlockData VAIR_DEBUG = B.getBlockData("COBWEB"); private static final BlockData[] SNOW_LAYERS = new BlockData[] {B.getBlockData("minecraft:snow[layers=1]"), B.getBlockData("minecraft:snow[layers=2]"), B.getBlockData("minecraft:snow[layers=3]"), B.getBlockData("minecraft:snow[layers=4]"), B.getBlockData("minecraft:snow[layers=5]"), B.getBlockData("minecraft:snow[layers=6]"), B.getBlockData("minecraft:snow[layers=7]"), B.getBlockData("minecraft:snow[layers=8]")}; public static boolean shitty = false; private KMap blocks; @@ -39,6 +43,143 @@ public class IrisObject extends IrisRegistrant private int d; private int h; private transient BlockVector center; + private transient volatile boolean smartBored = false; + private transient IrisLock lock = new IrisLock("Preloadcache"); + + public void ensureSmartBored(boolean debug) + { + if(smartBored) + { + return; + } + + lock.lock(); + int applied = 0; + if(blocks.isEmpty()) + { + lock.unlock(); + Iris.warn("Cannot Smart Bore " + getLoadKey() + " because it has 0 blocks in it."); + smartBored = true; + return; + } + + BlockVector max = new BlockVector(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE); + BlockVector min = new BlockVector(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); + + for(BlockVector i : blocks.k()) + { + max.setX(i.getX() > max.getX() ? i.getX() : max.getX()); + min.setX(i.getX() < min.getX() ? i.getX() : min.getX()); + max.setY(i.getY() > max.getY() ? i.getY() : max.getY()); + min.setY(i.getY() < min.getY() ? i.getY() : min.getY()); + max.setZ(i.getZ() > max.getZ() ? i.getZ() : max.getZ()); + min.setZ(i.getZ() < min.getZ() ? i.getZ() : min.getZ()); + } + + // Smash X + for(int rayY = min.getBlockY(); rayY <= max.getBlockY(); rayY++) + { + for(int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) + { + int start = Integer.MAX_VALUE; + int end = Integer.MIN_VALUE; + + for(int ray = min.getBlockX(); ray <= max.getBlockX(); ray++) + { + if(blocks.containsKey(new BlockVector(ray, rayY, rayZ))) + { + start = ray < start ? ray : start; + end = ray > end ? ray : end; + } + } + + if(start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) + { + for(int i = start; i <= end; i++) + { + BlockVector v = new BlockVector(i, rayY, rayZ); + + if(!blocks.containsKey(v) || B.isAir(blocks.get(v))) + { + blocks.put(v, debug ? VAIR_DEBUG : VAIR); + applied++; + } + } + } + } + } + + // Smash Y + for(int rayX = min.getBlockX(); rayX <= max.getBlockX(); rayX++) + { + for(int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) + { + int start = Integer.MAX_VALUE; + int end = Integer.MIN_VALUE; + + for(int ray = min.getBlockY(); ray <= max.getBlockY(); ray++) + { + if(blocks.containsKey(new BlockVector(rayX, ray, rayZ))) + { + start = ray < start ? ray : start; + end = ray > end ? ray : end; + } + } + + if(start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) + { + for(int i = start; i <= end; i++) + { + BlockVector v = new BlockVector(rayX, i, rayZ); + + if(!blocks.containsKey(v) || B.isAir(blocks.get(v))) + { + blocks.put(v, debug ? VAIR_DEBUG : VAIR); + applied++; + } + } + } + } + } + + // Smash Z + for(int rayX = min.getBlockX(); rayX <= max.getBlockX(); rayX++) + { + for(int rayY = min.getBlockY(); rayY <= max.getBlockY(); rayY++) + { + int start = Integer.MAX_VALUE; + int end = Integer.MIN_VALUE; + + for(int ray = min.getBlockZ(); ray <= max.getBlockZ(); ray++) + { + if(blocks.containsKey(new BlockVector(rayX, rayY, ray))) + { + start = ray < start ? ray : start; + end = ray > end ? ray : end; + } + } + + if(start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) + { + for(int i = start; i <= end; i++) + { + BlockVector v = new BlockVector(rayX, rayY, i); + + if(!blocks.containsKey(v) || B.isAir(blocks.get(v))) + { + blocks.put(v, debug ? VAIR_DEBUG : VAIR); + applied++; + } + } + } + } + } + + Iris.verbose("- Applied Smart Bore to " + getLoadKey() + " Filled with " + applied + " VOID_AIR blocks."); + + smartBored = true; + lock.unlock(); + } public IrisObject copy() { @@ -190,10 +331,13 @@ public class IrisObject extends IrisRegistrant public int place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, Consumer listener) { + if(config.isSmartBore()) + { + ensureSmartBored(placer.isDebugSmartBore()); + } + boolean warped = !config.getWarp().isFlat(); boolean stilting = (config.getMode().equals(ObjectPlaceMode.STILT) || config.getMode().equals(ObjectPlaceMode.FAST_STILT)); - KMap lowmap = stilting ? new KMap<>() : null; - KMap lowmapData = stilting ? new KMap<>() : null; KMap heightmap = config.getSnow() > 0 ? new KMap<>() : null; int spinx = rng.imax() / 1000; int spiny = rng.imax() / 1000; @@ -201,6 +345,7 @@ public class IrisObject extends IrisRegistrant int rty = config.getRotation().rotate(new BlockVector(0, getCenter().getBlockY(), 0), spinx, spiny, spinz).getBlockY(); int ty = config.getTranslate().translate(new BlockVector(0, getCenter().getBlockY(), 0), config.getRotation(), spinx, spiny, spinz).getBlockY(); int y = -1; + int xx, zz; if(yv < 0) { @@ -344,6 +489,11 @@ public class IrisObject extends IrisRegistrant i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone(); BlockData data = blocks.get(g).clone(); + if(stilting && i.getBlockY() < lowest && !B.isAir(data)) + { + lowest = i.getBlockY(); + } + if(placer.isPreventingDecay() && data instanceof Leaves && !((Leaves) data).isPersistent()) { ((Leaves) data).setPersistent(true); @@ -361,9 +511,9 @@ public class IrisObject extends IrisRegistrant } data = config.getRotation().rotate(data, spinx, spiny, spinz); - int xx = x + (int) Math.round(i.getX()); + xx = x + (int) Math.round(i.getX()); int yy = y + (int) Math.round(i.getY()); - int zz = z + (int) Math.round(i.getZ()); + zz = z + (int) Math.round(i.getZ()); if(warped) { @@ -410,59 +560,47 @@ public class IrisObject extends IrisRegistrant { placer.set(xx, yy, zz, data); } - - if(yy < lowest) - { - lowest = yy; - } - - if(stilting) - { - BlockData bdata = data; - int yyy = yy; - ChunkPosition ck = new ChunkPosition(xx, zz); - - lowmap.compute(ck, (k, v) -> - { - if(v == null) - { - lowmapData.put(ck, bdata); - return yyy; - } - - if(v > yyy) - { - lowmapData.put(ck, bdata); - return yyy; - } - - return v; - }); - } } if(stilting) { - for(ChunkPosition i : lowmap.keySet()) + for(BlockVector g : blocks.keySet()) { - int yf = lowmap.get(i); + BlockVector i = g.clone(); + i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone(); + i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone(); - if(yf > lowest) + if(i.getBlockY() != lowest) { continue; } - int xf = i.getX(); - int zf = i.getZ(); - int yg = Math.floorDiv(h, 2) + placer.getHighest(xf, zf, config.isUnderwater()); - BlockData d = lowmapData.get(i); + BlockData d = blocks.get(i); - if(d != null && !B.isAir(d)) + if(d == null || B.isAir(d)) { - for(int j = yf; j > yg - config.getOverStilt(); j--) - { - placer.set(xf, j, zf, d); - } + continue; + } + + xx = x + (int) Math.round(i.getX()); + zz = z + (int) Math.round(i.getZ()); + + if(warped) + { + xx += config.warp(rng, i.getX() + x, i.getY() + y, i.getZ() + z); + zz += config.warp(rng, i.getZ() + z, i.getY() + y, i.getX() + x); + } + + int yg = placer.getHighest(xx, zz, config.isUnderwater()); + + if(yv >= 0 && config.isBottom()) + { + y += Math.floorDiv(h, 2); + } + + for(int j = lowest + y; j > yg - config.getOverStilt() - 1; j--) + { + placer.set(xx, j, zz, d); } } } diff --git a/src/main/java/com/volmit/iris/object/IrisObjectPlacement.java b/src/main/java/com/volmit/iris/object/IrisObjectPlacement.java index 72b789363..a15474c59 100644 --- a/src/main/java/com/volmit/iris/object/IrisObjectPlacement.java +++ b/src/main/java/com/volmit/iris/object/IrisObjectPlacement.java @@ -92,6 +92,10 @@ public class IrisObjectPlacement @Desc("If set to true, objects will place on the terrain height, ignoring the water surface.") private boolean underwater = false; + @DontObfuscate + @Desc("If set to true, Iris will try to fill the insides of 'rooms' and 'pockets' where air should fit based off of raytrace checks. This prevents a village house placing in an area where a tree already exists, and instead replaces the parts of the tree where the interior of the structure is. \n\nThis operation does not affect warmed-up generation speed however it does slow down loading objects.") + private boolean smartBore = false; + @DontObfuscate @Desc("If set to true, Blocks placed underwater that could be waterlogged are waterlogged.") private boolean waterloggable = true; diff --git a/src/main/java/com/volmit/iris/object/IrisStructureTile.java b/src/main/java/com/volmit/iris/object/IrisStructureTile.java index e65308c46..b4f2a6418 100644 --- a/src/main/java/com/volmit/iris/object/IrisStructureTile.java +++ b/src/main/java/com/volmit/iris/object/IrisStructureTile.java @@ -70,6 +70,10 @@ public class IrisStructureTile @Desc("List of objects to place centered in this tile") private KList objects = new KList<>(); + @DontObfuscate + @Desc("If set to true, Iris will try to fill the insides of 'rooms' and 'pockets' where air should fit based off of raytrace checks. This prevents a village house placing in an area where a tree already exists, and instead replaces the parts of the tree where the interior of the structure is. \n\nThis operation does not affect warmed-up generation speed however it does slow down loading objects.") + private boolean smartBore = false; + private transient KMap forceObjects = new KMap<>(); @RegistryListObject diff --git a/src/main/java/com/volmit/iris/object/TileResult.java b/src/main/java/com/volmit/iris/object/TileResult.java index 8d0aee7c6..6f0c7e8b5 100644 --- a/src/main/java/com/volmit/iris/object/TileResult.java +++ b/src/main/java/com/volmit/iris/object/TileResult.java @@ -20,6 +20,7 @@ public class TileResult p.setBottom(true); p.setBore(structure.isBore()); p.setClamp(structure.getClamp()); + p.setSmartBore(tile.isSmartBore()); p.setWaterloggable(structure.isUnderwater()); p.setMode(tile.getPlaceMode()); placement = p; diff --git a/src/main/java/com/volmit/iris/util/IObjectPlacer.java b/src/main/java/com/volmit/iris/util/IObjectPlacer.java index 626baf200..10a7eef07 100644 --- a/src/main/java/com/volmit/iris/util/IObjectPlacer.java +++ b/src/main/java/com/volmit/iris/util/IObjectPlacer.java @@ -19,4 +19,6 @@ public interface IObjectPlacer public boolean isUnderwater(int x, int z); public int getFluidHeight(); + + public boolean isDebugSmartBore(); } diff --git a/src/main/java/com/volmit/iris/util/StructureTemplate.java b/src/main/java/com/volmit/iris/util/StructureTemplate.java index 5a1dd8f06..0c2c56dd5 100644 --- a/src/main/java/com/volmit/iris/util/StructureTemplate.java +++ b/src/main/java/com/volmit/iris/util/StructureTemplate.java @@ -1215,4 +1215,10 @@ public class StructureTemplate implements Listener, IObjectPlacer this.center = center; updateTiles(focus, null, null); } + + @Override + public boolean isDebugSmartBore() + { + return false; + } }