Supercarves

This commit is contained in:
Daniel Mills 2020-09-03 03:59:03 -04:00
parent 3663b9f957
commit 607a7be337
13 changed files with 274 additions and 99 deletions

View File

@ -100,19 +100,7 @@ public abstract class ParallaxChunkGenerator extends TerrainChunkGenerator imple
@Override
public int getHighest(int x, int z, boolean ignoreFluid)
{
int h = (int) Math.round(ignoreFluid ? getTerrainHeight(x, z) : getTerrainWaterHeight(x, z));
if(getDimension().isCarving() && h >= getDimension().getCarvingMin())
{
while(getGlCarve().isCarved(x, h, z))
{
h--;
}
return h;
}
return h;
return getCarvedHeight(x, z, ignoreFluid);
}
@Override

View File

@ -184,13 +184,13 @@ public abstract class PostBlockChunkGenerator extends ParallaxChunkGenerator imp
@Override
public int highestTerrainOrFluidBlock(int x, int z)
{
return getHighest(x, z, false);
return (int) getTerrainWaterHeight(x, z);
}
@Override
public int highestTerrainBlock(int x, int z)
{
return getHighest(x, z, true);
return (int) getTerrainHeight(x, z);
}
@Override

View File

@ -76,6 +76,36 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
glCarve = new GenLayerCarve(this, rng.nextParallelRNG(968346576));
}
public int getCarvedHeight(int x, int z, boolean ignoreFluid)
{
if(ignoreFluid)
{
return getCache().getCarvedHeightIgnoreWater(x, z, () ->
{
int h = (int) Math.round(getTerrainHeight(x, z));
h = getGlCarve().getSurfaceCarve(x, h, z);
return h;
});
}
return getCache().getCarvedHeightIgnoreWater(x, z, () ->
{
int h = (int) Math.round(getTerrainWaterHeight(x, z));
h = getGlCarve().getSurfaceCarve(x, h, z);
return h;
});
}
public int getCarvedHeight(int x, int z)
{
return getCarvedHeight(x, z, false);
}
public int getCarvedWaterHeight(int x, int z)
{
return getCarvedHeight(x, z, true);
}
public KList<CaveResult> getCaves(int x, int z)
{
return glCave.genCaves(x, z, x & 15, z & 15, null);
@ -104,9 +134,10 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
int depth = 0;
double noise = getTerrainHeight(rx, rz);
int height = (int) Math.round(noise);
boolean carvable = getDimension().isCarving() && height > getDimension().getCarvingMin();
boolean carvable = getGlCarve().couldCarveBelow(rx, height, rz);
IrisRegion region = sampleRegion(rx, rz);
IrisBiome biome = sampleTrueBiome(rx, rz, noise);
IrisBiome landBiome = null;
if(biome == null)
{
@ -114,6 +145,7 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
}
KList<BlockData> layers = biome.generateLayers(rx, rz, masterRandom, height, height - getFluidHeight());
KList<BlockData> cavernLayers = null;
KList<BlockData> seaLayers = biome.isAquatic() || biome.isShore() ? biome.generateSeaLayers(rx, rz, masterRandom, fluidHeight - height) : new KList<>();
boolean caverning = false;
KList<Integer> cavernHeights = new KList<>();
@ -146,7 +178,12 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
{
if(biomeMap != null)
{
sliver.set(k, biome.getDerivative());
if(landBiome == null)
{
landBiome = glBiome.generateData(InferredType.LAND, x, z, x, z, region);
}
sliver.set(k, landBiome.getDerivative());
}
sliver.set(k, CAVE_AIR);
@ -189,9 +226,19 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
}
// Set Surface Material for cavern layer surfaces
else if(layers.hasIndex(lastCavernHeight - k))
else if(carvable && cavernHeights.isNotEmpty() && lastCavernHeight - k >= 0 && lastCavernHeight - k < 5)
{
block = layers.get(lastCavernHeight - k);
if(landBiome == null)
{
landBiome = glBiome.generateData(InferredType.LAND, x, z, x, z, region);
}
if(cavernLayers == null)
{
cavernLayers = landBiome.generateLayers(rx, rz, masterRandom, 5, height - getFluidHeight());
}
block = cavernLayers.get(lastCavernHeight - k);
}
// Set Surface Material for true surface
@ -213,7 +260,12 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
// Decorate Cavern surfaces, but not the true surface
if((carvable && cavernSurface) && !(k == Math.max(height, fluidHeight) && block.getMaterial().isSolid() && k < 255 && k >= fluidHeight))
{
decorateLand(biome, sliver, wx, k, wz, rx, rz, block);
if(landBiome == null)
{
landBiome = glBiome.generateData(InferredType.LAND, z, x, x, z, region);
}
decorateLand(landBiome, sliver, wx, k, wz, rx, rz, block);
}
}
@ -233,7 +285,7 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
}
KList<BlockData> floor = caveBiome.generateLayers(wx, wz, rockRandom, i.getFloor() - 2, i.getFloor() - 2);
KList<BlockData> ceiling = caveBiome.generateLayers(wx + 256, wz + 256, rockRandom, height - i.getCeiling() - 2, height - i.getCeiling() - 2);
KList<BlockData> ceiling = caveBiome.generateLayers(wx + 256, wz + 256, rockRandom, (carvable ? getCarvedWaterHeight(rx, rz) : height) - i.getCeiling() - 2, (carvable ? getCarvedWaterHeight(rx, rz) : height) - i.getCeiling() - 2);
BlockData blockc = null;
for(int j = 0; j < floor.size(); j++)
{

View File

@ -16,6 +16,8 @@ public class AtomicMulticache
private int hit = 0;
private int miss = 0;
private final KMap<Long, Double> height;
private final KMap<Long, Integer> carvedHeight;
private final KMap<Long, Integer> carvedHeightIgnoreWater;
private final KMap<Long, IrisBiome> biome;
private final KMap<Long, IrisBiome> rawBiome;
private final KMap<Long, IrisRegion> region;
@ -25,6 +27,8 @@ public class AtomicMulticache
x = new AtomicInteger(0);
z = new AtomicInteger(0);
height = new KMap<Long, Double>();
carvedHeight = new KMap<Long, Integer>();
carvedHeightIgnoreWater = new KMap<Long, Integer>();
biome = new KMap<Long, IrisBiome>();
rawBiome = new KMap<Long, IrisBiome>();
region = new KMap<Long, IrisRegion>();
@ -52,6 +56,16 @@ public class AtomicMulticache
height.clear();
}
if(carvedHeight.size() > getLimit())
{
carvedHeight.clear();
}
if(carvedHeightIgnoreWater.size() > getLimit())
{
carvedHeightIgnoreWater.clear();
}
if(biome.size() > getLimit())
{
biome.clear();
@ -99,6 +113,56 @@ public class AtomicMulticache
return r;
}
public int getCarvedHeight(int x, int z, Supplier<Integer> g)
{
if(broken)
{
return -57841;
}
long pos = pos(x, z);
Integer r = carvedHeight.get(pos);
if(r == null)
{
miss++;
r = g.get();
carvedHeight.put(pos, r);
}
else
{
hit++;
}
return r;
}
public int getCarvedHeightIgnoreWater(int x, int z, Supplier<Integer> g)
{
if(broken)
{
return -57841;
}
long pos = pos(x, z);
Integer r = carvedHeightIgnoreWater.get(pos);
if(r == null)
{
miss++;
r = g.get();
carvedHeightIgnoreWater.put(pos, r);
}
else
{
hit++;
}
return r;
}
public IrisRegion getRegion(int x, int z, Supplier<IrisRegion> g)
{
long pos = pos(x, z);

View File

@ -370,6 +370,11 @@ public class AtomicSliver
BlockData b = block.get(i);
if(b != null)
{
if(b.getMaterial().equals(Material.AIR))
{
continue;
}
currentData.setBlock(x, i, z, b);
}
}

View File

@ -1,37 +1,79 @@
package com.volmit.iris.gen.layer;
import com.volmit.iris.gen.DimensionChunkGenerator;
import com.volmit.iris.noise.CellGenerator;
import com.volmit.iris.object.IrisCarveLayer;
import com.volmit.iris.util.GenLayer;
import com.volmit.iris.util.IrisInterpolation;
import com.volmit.iris.util.M;
import com.volmit.iris.util.RNG;
public class GenLayerCarve extends GenLayer
{
private CellGenerator cell;
private boolean couldCarve;
private int minimum;
private int maximum;
public GenLayerCarve(DimensionChunkGenerator iris, RNG rng)
{
super(iris, rng);
cell = new CellGenerator(rng.nextParallelRNG(-135486678));
couldCarve = iris.getDimension().isCarving() && iris.getDimension().getCarveLayers().isNotEmpty();
minimum = 512;
maximum = -256;
for(IrisCarveLayer i : iris.getDimension().getCarveLayers())
{
minimum = i.getMinHeight() < minimum ? i.getMinHeight() : minimum;
maximum = i.getMaxHeight() > maximum ? i.getMaxHeight() : maximum;
}
}
public boolean couldCarve(int x, int y, int z)
{
return couldCarve && y >= minimum && y <= maximum;
}
public boolean couldCarveBelow(int x, int y, int z)
{
return couldCarve && y <= maximum;
}
public int getSurfaceCarve(int x, int y, int z)
{
if(couldCarveBelow(x, y, z))
{
int h = y;
while(isCarved(x, h, z))
{
if(h <= 0)
{
break;
}
h--;
}
return h;
}
return y;
}
public boolean isCarved(int xc, int y, int zc)
{
if(y > iris.getDimension().getCarvingMax() || y < iris.getDimension().getCarvingMin())
if(!couldCarve(xc, y, zc))
{
return false;
}
double x = ((double) xc / iris.getDimension().getCarvingZoom());
double z = ((double) zc / iris.getDimension().getCarvingZoom());
double x = ((double) xc);
double z = ((double) zc);
double opacity = Math.pow(IrisInterpolation.sinCenter(M.lerpInverse(iris.getDimension().getCarvingMin(), iris.getDimension().getCarvingMax(), y)), 4);
if(cell.getDistance(x - (Math.cos(y / iris.getDimension().getCarvingRippleThickness()) + 0.5D) / 2D, y / iris.getDimension().getCarvingSliverThickness(), z + (Math.sin(y / iris.getDimension().getCarvingRippleThickness()) + 0.5D) / 2D) < opacity * iris.getDimension().getCarvingEnvelope())
for(IrisCarveLayer i : iris.getDimension().getCarveLayers())
{
return true;
if(i.isCarved(rng, x, y, z))
{
return true;
}
}
return false;

View File

@ -59,13 +59,10 @@ public class PostSlabber extends IrisPostBlockFilter
return;
}
if(isAirOrWater(x, h + 2, z, currentPostX, currentPostZ, currentData))
if(isAirOrWater(x, h + 1, z, currentPostX, currentPostZ, currentData))
{
queue(() ->
{
setPostBlock(x, h + 1, z, d, currentPostX, currentPostZ, currentData);
updateHeight(x, z, h + 1);
});
setPostBlock(x, h + 1, z, d, currentPostX, currentPostZ, currentData);
updateHeight(x, z, h + 1);
}
}
}

View File

@ -45,17 +45,8 @@ public class PostWallPatcher extends IrisPostBlockFilter
if(ha < h - 2 || hb < h - 2 || hc < h - 2 || hd < h - 2)
{
boolean brokeGround = false;
int max = Math.abs(Math.max(h - ha, Math.max(h - hb, Math.max(h - hc, h - hd))));
BlockData s = gen.sampleTrueBiome(x, z).getSlab().get(rng, x, h, z);
if(s != null)
{
if(!s.getMaterial().equals(AIR))
{
setPostBlock(x, h + 1, z, s, currentPostX, currentPostZ, currentData);
updateHeight(x, z, h + 1);
}
}
for(int i = h; i > h - max; i--)
{
@ -63,17 +54,18 @@ public class PostWallPatcher extends IrisPostBlockFilter
if(d != null)
{
if(d.getMaterial().equals(AIR))
{
continue;
}
if(isAirOrWater(x, i, z, currentPostX, currentPostZ, currentData))
{
if(brokeGround)
{
return;
}
continue;
}
setPostBlock(x, i, z, d, currentPostX, currentPostZ, currentData);
brokeGround = true;
}
}
}

View File

@ -36,21 +36,20 @@ public class PostWaterlogger extends IrisPostBlockFilter
if(b instanceof Waterlogged)
{
Waterlogged ww = (Waterlogged) b;
if(ww.isWaterlogged())
boolean w = false;
if(isWaterOrWaterlogged(x, h + 1, z, currentPostX, currentPostZ, currentData))
{
return;
w = true;
}
if(isWaterOrWaterlogged(x, h + 1, z, currentPostX, currentPostZ, currentData) && !ww.isWaterlogged())
else if((isWaterOrWaterlogged(x + 1, h, z, currentPostX, currentPostZ, currentData) || isWaterOrWaterlogged(x - 1, h, z, currentPostX, currentPostZ, currentData) || isWaterOrWaterlogged(x, h, z + 1, currentPostX, currentPostZ, currentData) || isWaterOrWaterlogged(x, h, z - 1, currentPostX, currentPostZ, currentData)))
{
ww.setWaterlogged(true);
setPostBlock(x, h, z, ww, currentPostX, currentPostZ, currentData);
w = true;
}
else if(!ww.isWaterlogged() && (isWaterOrWaterlogged(x + 1, h, z, currentPostX, currentPostZ, currentData) || isWaterOrWaterlogged(x - 1, h, z, currentPostX, currentPostZ, currentData) || isWaterOrWaterlogged(x, h, z + 1, currentPostX, currentPostZ, currentData) || isWaterOrWaterlogged(x, h, z - 1, currentPostX, currentPostZ, currentData)))
if(w != ww.isWaterlogged())
{
ww.setWaterlogged(true);
ww.setWaterlogged(w);
setPostBlock(x, h, z, ww, currentPostX, currentPostZ, currentData);
}
}

View File

@ -0,0 +1,60 @@
package com.volmit.iris.object;
import com.volmit.iris.gen.atomics.AtomicCache;
import com.volmit.iris.noise.CNG;
import com.volmit.iris.util.Desc;
import com.volmit.iris.util.DontObfuscate;
import com.volmit.iris.util.IrisInterpolation;
import com.volmit.iris.util.M;
import com.volmit.iris.util.MaxNumber;
import com.volmit.iris.util.MinNumber;
import com.volmit.iris.util.RNG;
import com.volmit.iris.util.Required;
import lombok.Data;
@Desc("Translate objects")
@Data
public class IrisCarveLayer
{
@Required
@DontObfuscate
@Desc("The 4d slope this carve layer follows")
private IrisGeneratorStyle style = new IrisGeneratorStyle();
@MaxNumber(512)
@MinNumber(-128)
@DontObfuscate
@Desc("The max height")
private int maxHeight = 220;
@MaxNumber(512)
@MinNumber(-128)
@DontObfuscate
@Desc("The min height")
private int minHeight = 147;
@MaxNumber(1)
@MinNumber(0)
@DontObfuscate
@Desc("The threshold used as: \n\ncarved = noise(x,y,z) > threshold")
private double threshold = 0.5;
private transient AtomicCache<CNG> cng = new AtomicCache<>();
public IrisCarveLayer()
{
}
public boolean isCarved(RNG rng, double x, double y, double z)
{
if(y > getMaxHeight() || y < getMinHeight())
{
return false;
}
double opacity = Math.pow(IrisInterpolation.sinCenter(M.lerpInverse(getMinHeight(), getMaxHeight(), y)), 4);
return cng.aquire(() -> getStyle().create(rng.nextParallelRNG(-2340 * getMaxHeight() * getMinHeight()))).fitDouble(0D, 1D, x, y, z) * opacity > getThreshold();
}
}

View File

@ -170,7 +170,7 @@ public class IrisDepositGenerator
int x = rng.i(af, bf);
int z = rng.i(af, bf);
int height = (int) (Math.round(g.getTerrainHeight((cx << 4) + x, (cz << 4) + z))) - 7;
int height = (int) (Math.round(g.getCarvedWaterHeight((cx << 4) + x, (cz << 4) + z))) - 7;
if(height <= 0)
{

View File

@ -130,40 +130,6 @@ public class IrisDimension extends IrisRegistrant
@Desc("Generate caves or not.")
private boolean caves = true;
@DontObfuscate
@Desc("Carve terrain or not")
private double carvingZoom = 3.5;
@MinNumber(-256)
@MaxNumber(256)
@DontObfuscate
@Desc("Carving starts at this height")
private int carvingMin = 115;
@MinNumber(-256)
@MaxNumber(256)
@DontObfuscate
@Desc("The maximum height carving happens at")
private int carvingMax = 239;
@MinNumber(0.0001)
@MaxNumber(256)
@DontObfuscate
@Desc("The thickness of carvings (vertical)")
private double carvingSliverThickness = 5.5D;
@MinNumber(0.0001)
@MaxNumber(512)
@DontObfuscate
@Desc("The thickness of ripples on carved walls")
private double carvingRippleThickness = 3D;
@MinNumber(0.0001)
@MaxNumber(512)
@DontObfuscate
@Desc("How much of 3D space is carved out. Higher values make carvings cross into 3d space more often (bigger)")
private double carvingEnvelope = 0.335D;
@DontObfuscate
@Desc("Carve terrain or not")
private boolean carving = true;
@ -290,6 +256,11 @@ public class IrisDimension extends IrisRegistrant
@Desc("Define cave layers")
private KList<IrisCaveLayer> caveLayers = new KList<>();
@ArrayType(min = 1, type = IrisCarveLayer.class)
@DontObfuscate
@Desc("Define carve layers")
private KList<IrisCarveLayer> carveLayers = new KList<>();
@DontObfuscate
@Desc("The noise style for fluid types")
private IrisGeneratorStyle fluidStyle = NoiseStyle.STATIC.style();

View File

@ -120,7 +120,7 @@ public class IrisStructurePlacement
public void placeLayer(ParallaxChunkGenerator g, RNG rng, RNG rnp, int i, int k, int j, int s, int sh)
{
if(!hasStructure(rng, i, k, j))
if(!hasStructure(g, rng, i, k, j))
{
return;
}
@ -176,8 +176,13 @@ public class IrisStructurePlacement
return structure.aquire(() -> (g == null ? Iris.globaldata : g.getData()).getStructureLoader().load(getTileset()));
}
public boolean hasStructure(RNG random, double x, double y, double z)
public boolean hasStructure(ParallaxChunkGenerator g, RNG random, double x, double y, double z)
{
if(g.getGlCarve().isCarved((int) x, (int) y, (int) z))
{
return false;
}
if(getChanceGenerator(random).getIndex(x / zoom, y / zoom, z / zoom, getRarity()) == getRarity() / 2)
{
return ratio > 0 ? getChanceGenerator(random).getDistance(x / zoom, z / zoom) > ratio : getChanceGenerator(random).getDistance(x / zoom, z / zoom) < Math.abs(ratio);