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 @Override
public int getHighest(int x, int z, boolean ignoreFluid) public int getHighest(int x, int z, boolean ignoreFluid)
{ {
int h = (int) Math.round(ignoreFluid ? getTerrainHeight(x, z) : getTerrainWaterHeight(x, z)); return getCarvedHeight(x, z, ignoreFluid);
if(getDimension().isCarving() && h >= getDimension().getCarvingMin())
{
while(getGlCarve().isCarved(x, h, z))
{
h--;
}
return h;
}
return h;
} }
@Override @Override

View File

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

View File

@ -76,6 +76,36 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
glCarve = new GenLayerCarve(this, rng.nextParallelRNG(968346576)); 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) public KList<CaveResult> getCaves(int x, int z)
{ {
return glCave.genCaves(x, z, x & 15, z & 15, null); return glCave.genCaves(x, z, x & 15, z & 15, null);
@ -104,9 +134,10 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
int depth = 0; int depth = 0;
double noise = getTerrainHeight(rx, rz); double noise = getTerrainHeight(rx, rz);
int height = (int) Math.round(noise); 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); IrisRegion region = sampleRegion(rx, rz);
IrisBiome biome = sampleTrueBiome(rx, rz, noise); IrisBiome biome = sampleTrueBiome(rx, rz, noise);
IrisBiome landBiome = null;
if(biome == 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> 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<>(); KList<BlockData> seaLayers = biome.isAquatic() || biome.isShore() ? biome.generateSeaLayers(rx, rz, masterRandom, fluidHeight - height) : new KList<>();
boolean caverning = false; boolean caverning = false;
KList<Integer> cavernHeights = new KList<>(); KList<Integer> cavernHeights = new KList<>();
@ -146,7 +178,12 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
{ {
if(biomeMap != null) 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); sliver.set(k, CAVE_AIR);
@ -189,9 +226,19 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
} }
// Set Surface Material for cavern layer surfaces // 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 // Set Surface Material for true surface
@ -213,7 +260,12 @@ public abstract class TerrainChunkGenerator extends ParallelChunkGenerator
// Decorate Cavern surfaces, but not the true surface // Decorate Cavern surfaces, but not the true surface
if((carvable && cavernSurface) && !(k == Math.max(height, fluidHeight) && block.getMaterial().isSolid() && k < 255 && k >= fluidHeight)) 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> 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; BlockData blockc = null;
for(int j = 0; j < floor.size(); j++) for(int j = 0; j < floor.size(); j++)
{ {

View File

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

View File

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

View File

@ -1,38 +1,80 @@
package com.volmit.iris.gen.layer; package com.volmit.iris.gen.layer;
import com.volmit.iris.gen.DimensionChunkGenerator; 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.GenLayer;
import com.volmit.iris.util.IrisInterpolation;
import com.volmit.iris.util.M;
import com.volmit.iris.util.RNG; import com.volmit.iris.util.RNG;
public class GenLayerCarve extends GenLayer public class GenLayerCarve extends GenLayer
{ {
private CellGenerator cell; private boolean couldCarve;
private int minimum;
private int maximum;
public GenLayerCarve(DimensionChunkGenerator iris, RNG rng) public GenLayerCarve(DimensionChunkGenerator iris, RNG rng)
{ {
super(iris, 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) 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; return false;
} }
double x = ((double) xc / iris.getDimension().getCarvingZoom()); double x = ((double) xc);
double z = ((double) zc / iris.getDimension().getCarvingZoom()); double z = ((double) zc);
double opacity = Math.pow(IrisInterpolation.sinCenter(M.lerpInverse(iris.getDimension().getCarvingMin(), iris.getDimension().getCarvingMax(), y)), 4); for(IrisCarveLayer i : iris.getDimension().getCarveLayers())
{
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()) if(i.isCarved(rng, x, y, z))
{ {
return true; return true;
} }
}
return false; return false;
} }

View File

@ -59,13 +59,10 @@ public class PostSlabber extends IrisPostBlockFilter
return; 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); setPostBlock(x, h + 1, z, d, currentPostX, currentPostZ, currentData);
updateHeight(x, z, h + 1); 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) 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)))); 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--) for(int i = h; i > h - max; i--)
{ {
@ -63,17 +54,18 @@ public class PostWallPatcher extends IrisPostBlockFilter
if(d != null) if(d != null)
{ {
if(d.getMaterial().equals(AIR))
{
continue;
}
if(isAirOrWater(x, i, z, currentPostX, currentPostZ, currentData)) if(isAirOrWater(x, i, z, currentPostX, currentPostZ, currentData))
{ {
if(brokeGround)
{
return;
}
continue; continue;
} }
setPostBlock(x, i, z, d, currentPostX, currentPostZ, currentData); 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) if(b instanceof Waterlogged)
{ {
Waterlogged ww = (Waterlogged) b; Waterlogged ww = (Waterlogged) b;
boolean w = false;
if(ww.isWaterlogged()) 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); w = true;
setPostBlock(x, h, z, ww, currentPostX, currentPostZ, currentData);
} }
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); 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 x = rng.i(af, bf);
int z = 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) if(height <= 0)
{ {

View File

@ -130,40 +130,6 @@ public class IrisDimension extends IrisRegistrant
@Desc("Generate caves or not.") @Desc("Generate caves or not.")
private boolean caves = true; 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 @DontObfuscate
@Desc("Carve terrain or not") @Desc("Carve terrain or not")
private boolean carving = true; private boolean carving = true;
@ -290,6 +256,11 @@ public class IrisDimension extends IrisRegistrant
@Desc("Define cave layers") @Desc("Define cave layers")
private KList<IrisCaveLayer> caveLayers = new KList<>(); private KList<IrisCaveLayer> caveLayers = new KList<>();
@ArrayType(min = 1, type = IrisCarveLayer.class)
@DontObfuscate
@Desc("Define carve layers")
private KList<IrisCarveLayer> carveLayers = new KList<>();
@DontObfuscate @DontObfuscate
@Desc("The noise style for fluid types") @Desc("The noise style for fluid types")
private IrisGeneratorStyle fluidStyle = NoiseStyle.STATIC.style(); 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) 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; return;
} }
@ -176,8 +176,13 @@ public class IrisStructurePlacement
return structure.aquire(() -> (g == null ? Iris.globaldata : g.getData()).getStructureLoader().load(getTileset())); 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) 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); return ratio > 0 ? getChanceGenerator(random).getDistance(x / zoom, z / zoom) > ratio : getChanceGenerator(random).getDistance(x / zoom, z / zoom) < Math.abs(ratio);