remove carver addon from main repo

This commit is contained in:
dfsek 2021-10-17 14:34:34 -07:00
parent 765322ef57
commit 8df87df374
10 changed files with 0 additions and 813 deletions

View File

@ -1,3 +0,0 @@
# config-carver
Registers the default configuration for Terra Carvers, `CARVER`.

View File

@ -1,2 +0,0 @@
dependencies {
}

View File

@ -1,71 +0,0 @@
package com.dfsek.terra.addons.carver;
import com.dfsek.terra.api.Platform;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import com.dfsek.terra.addons.carver.carving.Worm;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.util.PopulationUtil;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class CarverCache {
private final LoadingCache<Long, List<Worm.WormPoint>> cache;
private final UserDefinedCarver carver;
public CarverCache(World w, Platform platform, UserDefinedCarver carver) {
this.carver = carver;
cache = CacheBuilder.newBuilder().maximumSize(platform.getTerraConfig().getCarverCacheSize())
.build(new CacheLoader<>() {
@Override
public List<Worm.WormPoint> load(@NotNull Long key) {
int chunkX = (int) (key >> 32);
int chunkZ = (int) key.longValue();
BiomeProvider provider = w.getBiomeProvider();
if(CarverCache.this.carver.isChunkCarved(w, chunkX, chunkZ, new Random(
PopulationUtil.getCarverChunkSeed(chunkX, chunkZ,
w.getSeed() + CarverCache.this.carver.hashCode())))) {
long seed = PopulationUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed());
Random r = new Random(seed);
Worm carving = CarverCache.this.carver.getWorm(seed, new Vector3((chunkX << 4) + r.nextInt(16),
CarverCache.this.carver.getConfig()
.getHeight()
.get(r),
(chunkZ << 4) + r.nextInt(16)));
List<Worm.WormPoint> points = new ArrayList<>();
for(int i = 0; i < carving.getLength(); i++) {
carving.step();
TerraBiome biome = provider.getBiome(carving.getRunning(), w.getSeed());
/*
if(!((UserDefinedBiome) biome).getConfig().getCarvers().containsKey(CarverCache.this.carver)) { // Stop
if we enter a biome this carver is not present in
return Collections.emptyList();
}
*/
points.add(carving.getPoint());
}
return points;
}
return Collections.emptyList();
}
});
}
public List<Worm.WormPoint> getPoints(int chunkX, int chunkZ) {
return cache.getUnchecked(MathUtil.squash(chunkX, chunkZ));
}
}

View File

@ -1,40 +0,0 @@
package com.dfsek.terra.addons.carver;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.tectonic.exception.LoadException;
import java.util.Arrays;
import java.util.List;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.MathUtil;
public class CarverFactory implements ConfigFactory<CarverTemplate, UserDefinedCarver> {
private final ConfigPack pack;
public CarverFactory(ConfigPack pack) {
this.pack = pack;
}
@Override
public UserDefinedCarver build(CarverTemplate config, Platform platform) throws LoadException {
double[] start = { config.getStartX(), config.getStartY(), config.getStartZ() };
double[] mutate = { config.getMutateX(), config.getMutateY(), config.getMutateZ() };
List<String> radius = Arrays.asList(config.getRadMX(), config.getRadMY(), config.getRadMZ());
long hash = MathUtil.hashToLong(config.getID());
UserDefinedCarver carver;
try {
carver = new UserDefinedCarver(config.getHeight(), config.getLength(), start, mutate, radius, new Scope(), hash,
config.getCutTop(), config.getCutBottom(), config, platform);
} catch(ParseException e) {
throw new LoadException("Unable to parse radius equations", e);
}
carver.setRecalc(config.getRecalc());
carver.setRecalcMagnitude(config.getRecaclulateMagnitude());
return carver;
}
}

View File

@ -1,66 +0,0 @@
package com.dfsek.terra.addons.carver;
import net.jafama.FastMath;
import java.util.Map;
import java.util.TreeMap;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.util.collection.MaterialSet;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings({ "unchecked", "rawtypes", "RedundantSuppression" })
public class CarverPalette {
private final boolean blacklist;
private final MaterialSet replace;
private final TreeMap<Integer, ProbabilityCollection<BlockState>> map = new TreeMap<>();
private ProbabilityCollection<BlockState>[] layers;
private int offset = 0;
public CarverPalette(MaterialSet replaceable, boolean blacklist) {
this.blacklist = blacklist;
this.replace = replaceable;
}
public CarverPalette add(ProbabilityCollection<BlockState> collection, int y) {
map.put(y, collection);
return this;
}
public ProbabilityCollection<BlockState> get(int y) {
int index = y + offset;
return index >= 0
? index < layers.length
? layers[index]
: layers[layers.length - 1]
: layers[0];
}
public boolean canReplace(BlockType material) {
return blacklist != replace.contains(material);
}
/**
* Build the palette to an array.
*/
public void build() {
int min = FastMath.min(map.keySet().stream().min(Integer::compareTo).orElse(0), 0);
int max = FastMath.max(map.keySet().stream().max(Integer::compareTo).orElse(255), 255);
layers = new ProbabilityCollection[map.lastKey() + 1 - min];
for(int y = min; y <= FastMath.max(map.lastKey(), max); y++) {
ProbabilityCollection<BlockState> d = null;
for(Map.Entry<Integer, ProbabilityCollection<BlockState>> e : map.entrySet()) {
if(e.getKey() >= y) {
d = e.getValue();
break;
}
}
if(d == null) throw new IllegalArgumentException("No palette for Y=" + y);
layers[y - min] = d;
}
offset = -min;
}
}

View File

@ -1,189 +0,0 @@
package com.dfsek.terra.addons.carver;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Final;
import com.dfsek.tectonic.annotations.Value;
import java.util.HashMap;
import java.util.Map;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.config.AbstractableTemplate;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.ConstantRange;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collection.MaterialSet;
@SuppressWarnings({ "unused", "FieldMayBeFinal" })
public class CarverTemplate implements AbstractableTemplate {
@Value("id")
@Final
private String id;
@Value("step")
@Default
private @Meta int step = 2;
@Value("recalculate-magnitude")
@Default
private @Meta double recaclulateMagnitude = 4;
@Value("recalculate-direction")
@Default
private @Meta Range recalc = new ConstantRange(8, 10);
@Value("length")
private @Meta Range length;
@Value("start.x")
private @Meta double startX;
@Value("start.y")
private @Meta double startY;
@Value("start.z")
private @Meta double startZ;
@Value("start.radius.x")
private @Meta String radMX;
@Value("start.radius.y")
private @Meta String radMY;
@Value("start.radius.z")
private @Meta String radMZ;
@Value("start.height")
private @Meta Range height;
@Value("cut.bottom")
@Default
private @Meta int cutBottom = 0;
@Value("cut.top")
@Default
private @Meta int cutTop = 0;
@Value("mutate.x")
private @Meta double mutateX;
@Value("mutate.y")
private @Meta double mutateY;
@Value("mutate.z")
private @Meta double mutateZ;
@Value("palette.top")
private @Meta CarverPalette top;
@Value("palette.bottom")
private @Meta CarverPalette bottom;
@Value("palette.outer")
private @Meta CarverPalette outer;
@Value("palette.inner")
private @Meta CarverPalette inner;
@Value("shift")
@Default
private @Meta Map<@Meta BlockType, @Meta MaterialSet> shift = new HashMap<>();
@Value("update")
@Default
private @Meta MaterialSet update = new MaterialSet();
public String getID() {
return id;
}
public int getStep() {
return step;
}
public Range getLength() {
return length;
}
public double getStartX() {
return startX;
}
public double getStartY() {
return startY;
}
public double getStartZ() {
return startZ;
}
public String getRadMX() {
return radMX;
}
public String getRadMY() {
return radMY;
}
public String getRadMZ() {
return radMZ;
}
public Range getHeight() {
return height;
}
public int getCutBottom() {
return cutBottom;
}
public int getCutTop() {
return cutTop;
}
public double getMutateX() {
return mutateX;
}
public double getMutateY() {
return mutateY;
}
public double getMutateZ() {
return mutateZ;
}
public CarverPalette getTop() {
return top;
}
public CarverPalette getBottom() {
return bottom;
}
public CarverPalette getOuter() {
return outer;
}
public CarverPalette getInner() {
return inner;
}
public Map<BlockType, MaterialSet> getShift() {
return shift;
}
public MaterialSet getUpdate() {
return update;
}
public Range getRecalc() {
return recalc;
}
public double getRecaclulateMagnitude() {
return recaclulateMagnitude;
}
}

View File

@ -1,98 +0,0 @@
package com.dfsek.terra.addons.carver;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.config.WorldConfig;
import com.dfsek.terra.api.profiler.ProfileFrame;
import com.dfsek.terra.api.util.PopulationUtil;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.Chunk;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.generator.Chunkified;
import com.dfsek.terra.api.world.generator.GenerationStage;
public class CavePopulator implements GenerationStage, Chunkified {
private static final Map<BlockType, BlockState> shiftStorage = new HashMap<>();
// Persist BlockData created for shifts, to avoid re-calculating each time.
private final Platform platform;
public CavePopulator(Platform platform) {
this.platform = platform;
}
@SuppressWarnings("try")
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
try(ProfileFrame ignore = platform.getProfiler().profile("carving")) {
Random random = PopulationUtil.getRandom(chunk);
WorldConfig config = world.getConfig();
if(config.disableCarving()) return;
for(UserDefinedCarver c : config.getRegistry(UserDefinedCarver.class).entries()) {
CarverTemplate template = c.getConfig();
Map<Vector3, BlockState> shiftCandidate = new HashMap<>();
c.carve(chunk.getX(), chunk.getZ(), world, (v, type) -> {
try(ProfileFrame ignored = platform.getProfiler().profile("carving:" + c.getConfig().getID())) {
BlockState m = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
BlockType re = m.getBlockType();
switch(type) {
case CENTER:
if(template.getInner().canReplace(re)) {
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
template.getInner().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
}
break;
case WALL:
if(template.getOuter().canReplace(re)) {
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
template.getOuter().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
}
break;
case TOP:
if(template.getTop().canReplace(re)) {
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
template.getTop().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
}
break;
case BOTTOM:
if(template.getBottom().canReplace(re)) {
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
template.getBottom().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
}
break;
}
}
});
for(Map.Entry<Vector3, BlockState> entry : shiftCandidate.entrySet()) {
Vector3 l = entry.getKey();
Vector3 mut = l.clone();
BlockState orig = chunk.getBlock(l.getBlockX(), l.getBlockY(), l.getBlockZ());
do mut.subtract(0, 1, 0);
while(mut.getY() > world.getMinHeight() && chunk.getBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ()).matches(
orig));
try {
if(template.getShift().get(entry.getValue().getBlockType()).contains(
chunk.getBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ()).getBlockType())) {
chunk.setBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ(),
shiftStorage.computeIfAbsent(entry.getValue().getBlockType(), BlockType::getDefaultData), false);
}
} catch(NullPointerException ignored) {
}
}
}
}
}
}

View File

@ -1,172 +0,0 @@
package com.dfsek.terra.addons.carver;
import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import net.jafama.FastMath;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import com.dfsek.terra.addons.carver.carving.Carver;
import com.dfsek.terra.addons.carver.carving.Worm;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.util.ConstantRange;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.World;
public class UserDefinedCarver extends Carver {
private final double[] start; // 0, 1, 2 = x, y, z.
private final double[] mutate; // 0, 1, 2 = x, y, z. 3 = radius.
private final Range length;
private final long hash;
private final int topCut;
private final int bottomCut;
private final CarverTemplate config;
private final Expression xRad;
private final Expression yRad;
private final Expression zRad;
private final Map<Long, CarverCache> cacheMap = new ConcurrentHashMap<>();
private final Platform platform;
private double step = 2;
private Range recalc = new ConstantRange(8, 10);
private double recalcMagnitude = 3;
public UserDefinedCarver(Range height, Range length, double[] start, double[] mutate, List<String> radii, Scope parent, long hash,
int topCut, int bottomCut, CarverTemplate config, Platform platform) throws ParseException {
super(height.getMin(), height.getMax());
this.length = length;
this.start = start;
this.mutate = mutate;
this.hash = hash;
this.topCut = topCut;
this.bottomCut = bottomCut;
this.config = config;
this.platform = platform;
Parser p = new Parser();
Scope s = new Scope().withParent(parent);
s.addInvocationVariable("x");
s.addInvocationVariable("y");
s.addInvocationVariable("z");
s.addInvocationVariable("length");
s.addInvocationVariable("position");
s.addInvocationVariable("seed");
xRad = p.parse(radii.get(0), s);
yRad = p.parse(radii.get(1), s);
zRad = p.parse(radii.get(2), s);
}
@Override
public void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer) {
synchronized(cacheMap) {
CarverCache cache = cacheMap.computeIfAbsent(w.getSeed(), world -> new CarverCache(w, platform, this));
int carvingRadius = getCarvingRadius();
for(int x = chunkX - carvingRadius; x <= chunkX + carvingRadius; x++) {
for(int z = chunkZ - carvingRadius; z <= chunkZ + carvingRadius; z++) {
cache.getPoints(x, z).forEach(point -> {
Vector3 origin = point.getOrigin();
if(FastMath.floorDiv(origin.getBlockX(), 16) != chunkX && FastMath.floorDiv(origin.getBlockZ(), 16) !=
chunkZ) // We only want to carve this chunk.
return;
point.carve(chunkX, chunkZ, consumer, w);
});
}
}
}
}
@Override
public Worm getWorm(long l, Vector3 vector) {
Random r = new Random(l + hash);
return new UserDefinedWorm(length.get(r) / 2, r, vector, topCut, bottomCut, l);
}
@Override
public boolean isChunkCarved(World w, int chunkX, int chunkZ, Random random) {
/*BiomeTemplate conf = ((UserDefinedBiome) main.getWorld(w).getBiomeProvider().getBiome((chunkX << 4) + 8, (chunkZ << 4) + 8))
.getConfig();
if(conf.getCarvers().get(this) != null) {
return new Random(random.nextLong() + hash).nextInt(100) < conf.getCarvers().get(this);
}*/
return false;
}
public void setRecalc(Range recalc) {
this.recalc = recalc;
}
public void setRecalcMagnitude(double recalcMagnitude) {
this.recalcMagnitude = recalcMagnitude;
}
public void setStep(double step) {
this.step = step;
}
public CarverTemplate getConfig() {
return config;
}
private class UserDefinedWorm extends Worm {
private final Vector3 direction;
private final Vector3 origin;
private final long seed;
private int steps;
private int nextDirection = 0;
private double[] currentRotation = new double[3];
public UserDefinedWorm(int length, Random r, Vector3 origin, int topCut, int bottomCut, long seed) {
super(length, r, origin);
this.origin = origin;
this.seed = seed;
super.setTopCut(topCut);
super.setBottomCut(bottomCut);
direction = new Vector3((r.nextDouble() - 0.5D) * start[0], (r.nextDouble() - 0.5D) * start[1],
(r.nextDouble() - 0.5D) * start[2]).normalize().multiply(step);
double[] args = { origin.getX(), origin.getY(), origin.getZ(), length, 0, seed };
setRadius(new int[]{ (int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args)) });
}
@Override
public void step() {
if(steps == nextDirection) {
direction.rotateAroundX(FastMath.toRadians((getRandom().nextGaussian()) * mutate[0] * recalcMagnitude));
direction.rotateAroundY(FastMath.toRadians((getRandom().nextGaussian()) * mutate[1] * recalcMagnitude));
direction.rotateAroundZ(FastMath.toRadians((getRandom().nextGaussian()) * mutate[2] * recalcMagnitude));
currentRotation = new double[]{
(getRandom().nextGaussian()) * mutate[0],
(getRandom().nextGaussian()) * mutate[1],
(getRandom().nextGaussian()) * mutate[2]
};
nextDirection += recalc.get(getRandom());
}
steps++;
double[] args = { origin.getX(), origin.getY(), origin.getZ(), getLength(), steps, seed };
setRadius(new int[]{ (int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args)) });
direction.rotateAroundX(FastMath.toRadians(currentRotation[0] * mutate[0]));
direction.rotateAroundY(FastMath.toRadians(currentRotation[1] * mutate[1]));
direction.rotateAroundZ(FastMath.toRadians(currentRotation[2] * mutate[2]));
getRunning().add(direction);
}
@Override
public WormPoint getPoint() {
return new WormPoint(getRunning().clone(), getRadius(), config.getCutTop(), config.getCutBottom());
}
}
}

View File

@ -1,43 +0,0 @@
package com.dfsek.terra.addons.carver.carving;
import net.jafama.FastMath;
import java.util.Random;
import java.util.function.BiConsumer;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.World;
public abstract class Carver {
private final int minY;
private final int maxY;
private final double sixtyFourSq = FastMath.pow(64, 2);
private int carvingRadius = 4;
public Carver(int minY, int maxY) {
this.minY = minY;
this.maxY = maxY;
}
public abstract void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer);
public int getCarvingRadius() {
return carvingRadius;
}
public void setCarvingRadius(int carvingRadius) {
this.carvingRadius = carvingRadius;
}
public abstract Worm getWorm(long seed, Vector3 l);
public abstract boolean isChunkCarved(World w, int chunkX, int chunkZ, Random r);
public enum CarvingType {
CENTER,
WALL,
TOP,
BOTTOM
}
}

View File

@ -1,129 +0,0 @@
package com.dfsek.terra.addons.carver.carving;
import net.jafama.FastMath;
import java.util.Random;
import java.util.function.BiConsumer;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.World;
public abstract class Worm {
private final Random r;
private final Vector3 origin;
private final Vector3 running;
private final int length;
private int topCut = 0;
private int bottomCut = 0;
private int[] radius = { 0, 0, 0 };
public Worm(int length, Random r, Vector3 origin) {
this.r = r;
this.length = length;
this.origin = origin;
this.running = origin;
}
public abstract void step();
public void setBottomCut(int bottomCut) {
this.bottomCut = bottomCut;
}
public void setTopCut(int topCut) {
this.topCut = topCut;
}
public Vector3 getOrigin() {
return origin;
}
public int getLength() {
return length;
}
public Vector3 getRunning() {
return running;
}
public WormPoint getPoint() {
return new WormPoint(running, radius, topCut, bottomCut);
}
public int[] getRadius() {
return radius;
}
public void setRadius(int[] radius) {
this.radius = radius;
}
public Random getRandom() {
return r;
}
public static class WormPoint {
private final Vector3 origin;
private final int topCut;
private final int bottomCut;
private final int[] rad;
public WormPoint(Vector3 origin, int[] rad, int topCut, int bottomCut) {
this.origin = origin;
this.rad = rad;
this.topCut = topCut;
this.bottomCut = bottomCut;
}
private static double ellipseEquation(int x, int y, int z, double xr, double yr, double zr) {
return (FastMath.pow2(x) / FastMath.pow2(xr + 0.5D)) + (FastMath.pow2(y) / FastMath.pow2(yr + 0.5D)) + (FastMath.pow2(z) /
FastMath.pow2(
zr + 0.5D));
}
public void carve(int chunkX, int chunkZ, BiConsumer<Vector3, Carver.CarvingType> consumer, World world) {
int xRad = getRadius(0);
int yRad = getRadius(1);
int zRad = getRadius(2);
int originX = (chunkX << 4);
int originZ = (chunkZ << 4);
for(int x = -xRad - 1; x <= xRad + 1; x++) {
if(!(FastMath.floorDiv(origin.getBlockX() + x, 16) == chunkX)) continue;
for(int z = -zRad - 1; z <= zRad + 1; z++) {
if(!(FastMath.floorDiv(origin.getBlockZ() + z, 16) == chunkZ)) continue;
for(int y = -yRad - 1; y <= yRad + 1; y++) {
Vector3 position = origin.clone().add(new Vector3(x, y, z));
if(position.getY() < world.getMinHeight() || position.getY() > world.getMaxHeight()) continue;
double eq = ellipseEquation(x, y, z, xRad, yRad, zRad);
if(eq <= 1 &&
y >= -yRad - 1 + bottomCut && y <= yRad + 1 - topCut) {
consumer.accept(
new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ),
Carver.CarvingType.CENTER);
} else if(eq <= 1.5) {
Carver.CarvingType type = Carver.CarvingType.WALL;
if(y <= -yRad - 1 + bottomCut) {
type = Carver.CarvingType.BOTTOM;
} else if(y >= yRad + 1 - topCut) {
type = Carver.CarvingType.TOP;
}
consumer.accept(
new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ),
type);
}
}
}
}
}
public Vector3 getOrigin() {
return origin;
}
public int getRadius(int index) {
return rad[index];
}
}
}