From cb2e4da32cac2273320c27cd66381bbd99eb1d37 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sun, 17 Oct 2021 14:29:15 -0700 Subject: [PATCH 1/6] Initial commit --- common/addons/config-carver/README.md | 3 + common/addons/config-carver/build.gradle.kts | 2 + .../terra/addons/carver/CarverCache.java | 71 +++++++ .../terra/addons/carver/CarverFactory.java | 40 ++++ .../terra/addons/carver/CarverPalette.java | 66 ++++++ .../terra/addons/carver/CarverTemplate.java | 189 ++++++++++++++++++ .../terra/addons/carver/CavePopulator.java | 98 +++++++++ .../addons/carver/UserDefinedCarver.java | 172 ++++++++++++++++ .../terra/addons/carver/carving/Carver.java | 43 ++++ .../terra/addons/carver/carving/Worm.java | 129 ++++++++++++ 10 files changed, 813 insertions(+) create mode 100644 common/addons/config-carver/README.md create mode 100644 common/addons/config-carver/build.gradle.kts create mode 100644 common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java create mode 100644 common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverFactory.java create mode 100644 common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverPalette.java create mode 100644 common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverTemplate.java create mode 100644 common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CavePopulator.java create mode 100644 common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/UserDefinedCarver.java create mode 100644 common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Carver.java create mode 100644 common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Worm.java diff --git a/common/addons/config-carver/README.md b/common/addons/config-carver/README.md new file mode 100644 index 000000000..f5075b916 --- /dev/null +++ b/common/addons/config-carver/README.md @@ -0,0 +1,3 @@ +# config-carver + +Registers the default configuration for Terra Carvers, `CARVER`. \ No newline at end of file diff --git a/common/addons/config-carver/build.gradle.kts b/common/addons/config-carver/build.gradle.kts new file mode 100644 index 000000000..7d82dc72f --- /dev/null +++ b/common/addons/config-carver/build.gradle.kts @@ -0,0 +1,2 @@ +dependencies { +} diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java new file mode 100644 index 000000000..d0cad3be9 --- /dev/null +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java @@ -0,0 +1,71 @@ +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> 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 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 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 getPoints(int chunkX, int chunkZ) { + return cache.getUnchecked(MathUtil.squash(chunkX, chunkZ)); + } +} diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverFactory.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverFactory.java new file mode 100644 index 000000000..9af80f7aa --- /dev/null +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverFactory.java @@ -0,0 +1,40 @@ +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 { + 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 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; + } +} diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverPalette.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverPalette.java new file mode 100644 index 000000000..8920ebff8 --- /dev/null +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverPalette.java @@ -0,0 +1,66 @@ +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> map = new TreeMap<>(); + private ProbabilityCollection[] layers; + private int offset = 0; + + public CarverPalette(MaterialSet replaceable, boolean blacklist) { + this.blacklist = blacklist; + this.replace = replaceable; + } + + public CarverPalette add(ProbabilityCollection collection, int y) { + map.put(y, collection); + return this; + } + + public ProbabilityCollection 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 d = null; + for(Map.Entry> 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; + } +} diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverTemplate.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverTemplate.java new file mode 100644 index 000000000..b1f20f6f3 --- /dev/null +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverTemplate.java @@ -0,0 +1,189 @@ +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 getShift() { + return shift; + } + + public MaterialSet getUpdate() { + return update; + } + + public Range getRecalc() { + return recalc; + } + + public double getRecaclulateMagnitude() { + return recaclulateMagnitude; + } +} diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CavePopulator.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CavePopulator.java new file mode 100644 index 000000000..9ac8ad280 --- /dev/null +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CavePopulator.java @@ -0,0 +1,98 @@ +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 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 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 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) { + } + } + } + + } + } +} diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/UserDefinedCarver.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/UserDefinedCarver.java new file mode 100644 index 000000000..bfac24cd1 --- /dev/null +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/UserDefinedCarver.java @@ -0,0 +1,172 @@ +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 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 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 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()); + } + } +} diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Carver.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Carver.java new file mode 100644 index 000000000..0eb0e3e02 --- /dev/null +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Carver.java @@ -0,0 +1,43 @@ +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 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 + } +} diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Worm.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Worm.java new file mode 100644 index 000000000..fb064a46b --- /dev/null +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Worm.java @@ -0,0 +1,129 @@ +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 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]; + } + } +} From f6cc6d682f64f61d1c290d4bd6df1be74b4498f6 Mon Sep 17 00:00:00 2001 From: dfsek Date: Wed, 17 Nov 2021 10:20:05 -0700 Subject: [PATCH 2/6] create addon manifests --- .../config-carver/src/main/resources/terra.addon.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/addons/config-carver/src/main/resources/terra.addon.yml diff --git a/common/addons/config-carver/src/main/resources/terra.addon.yml b/common/addons/config-carver/src/main/resources/terra.addon.yml new file mode 100644 index 000000000..8e222fc3e --- /dev/null +++ b/common/addons/config-carver/src/main/resources/terra.addon.yml @@ -0,0 +1,11 @@ +schema-version: 1 +contributors: + - Terra contributors +id: config-carver +version: 0.1.0 +entrypoints: [] +website: + issues: https://github.com/PolyhedralDev/Terra-config-carver/issues + source: https://github.com/PolyhedralDev/Terra-config-carver + docs: https://github.com/PolyhedralDev/Terra/wiki +license: GNU LGPL v3.0 \ No newline at end of file From e96f43f3b03caab171b2bfd3a00a48beeb0b0a2c Mon Sep 17 00:00:00 2001 From: dfsek Date: Wed, 17 Nov 2021 12:20:18 -0700 Subject: [PATCH 3/6] depend on manifest addons in core addon modules --- common/addons/config-carver/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/common/addons/config-carver/build.gradle.kts b/common/addons/config-carver/build.gradle.kts index 7d82dc72f..147905b20 100644 --- a/common/addons/config-carver/build.gradle.kts +++ b/common/addons/config-carver/build.gradle.kts @@ -1,2 +1,3 @@ dependencies { + "shadedApi"(project(":common:addons:manifest-addon-loader")) } From da3a5f67fa214286777fdbdfe173f28ee9bda7a4 Mon Sep 17 00:00:00 2001 From: dfsek Date: Wed, 17 Nov 2021 16:28:40 -0700 Subject: [PATCH 4/6] format --- .../main/java/com/dfsek/terra/addons/carver/CarverCache.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java index d0cad3be9..6b8b0610f 100644 --- a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java @@ -1,7 +1,5 @@ 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; @@ -13,6 +11,7 @@ import java.util.List; import java.util.Random; import com.dfsek.terra.addons.carver.carving.Worm; +import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.util.MathUtil; import com.dfsek.terra.api.util.PopulationUtil; import com.dfsek.terra.api.util.vector.Vector3; From 1ccc2e477f4e2c22797a52495c6b111906998772 Mon Sep 17 00:00:00 2001 From: dfsek Date: Fri, 19 Nov 2021 08:47:17 -0700 Subject: [PATCH 5/6] relicense addons under MIT license --- common/addons/config-carver/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 common/addons/config-carver/LICENSE diff --git a/common/addons/config-carver/LICENSE b/common/addons/config-carver/LICENSE new file mode 100644 index 000000000..64c1cd516 --- /dev/null +++ b/common/addons/config-carver/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2021 Polyhedral Development + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From f0c343e6fa02c3114be8292f6c65619d60e2f9a4 Mon Sep 17 00:00:00 2001 From: dfsek Date: Fri, 19 Nov 2021 15:42:25 -0700 Subject: [PATCH 6/6] add license headers --- .../java/com/dfsek/terra/addons/carver/CarverCache.java | 7 +++++++ .../java/com/dfsek/terra/addons/carver/CarverFactory.java | 7 +++++++ .../java/com/dfsek/terra/addons/carver/CarverPalette.java | 7 +++++++ .../java/com/dfsek/terra/addons/carver/CarverTemplate.java | 7 +++++++ .../java/com/dfsek/terra/addons/carver/CavePopulator.java | 7 +++++++ .../com/dfsek/terra/addons/carver/UserDefinedCarver.java | 7 +++++++ .../java/com/dfsek/terra/addons/carver/carving/Carver.java | 7 +++++++ .../java/com/dfsek/terra/addons/carver/carving/Worm.java | 7 +++++++ 8 files changed, 56 insertions(+) diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java index 6b8b0610f..a67770463 100644 --- a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverCache.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + package com.dfsek.terra.addons.carver; import com.google.common.cache.CacheBuilder; diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverFactory.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverFactory.java index 9af80f7aa..e2a4fc46d 100644 --- a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverFactory.java +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverFactory.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + package com.dfsek.terra.addons.carver; import com.dfsek.paralithic.eval.parser.Scope; diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverPalette.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverPalette.java index 8920ebff8..ed6c8e10d 100644 --- a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverPalette.java +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverPalette.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + package com.dfsek.terra.addons.carver; import net.jafama.FastMath; diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverTemplate.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverTemplate.java index b1f20f6f3..d629b5586 100644 --- a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverTemplate.java +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CarverTemplate.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + package com.dfsek.terra.addons.carver; diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CavePopulator.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CavePopulator.java index 9ac8ad280..c6fd8f08e 100644 --- a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CavePopulator.java +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/CavePopulator.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + package com.dfsek.terra.addons.carver; import org.jetbrains.annotations.NotNull; diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/UserDefinedCarver.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/UserDefinedCarver.java index bfac24cd1..a31670b03 100644 --- a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/UserDefinedCarver.java +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/UserDefinedCarver.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + package com.dfsek.terra.addons.carver; import com.dfsek.paralithic.Expression; diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Carver.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Carver.java index 0eb0e3e02..c8405d9a0 100644 --- a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Carver.java +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Carver.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + package com.dfsek.terra.addons.carver.carving; import net.jafama.FastMath; diff --git a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Worm.java b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Worm.java index fb064a46b..fd75c0098 100644 --- a/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Worm.java +++ b/common/addons/config-carver/src/main/java/com/dfsek/terra/addons/carver/carving/Worm.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + package com.dfsek.terra.addons.carver.carving; import net.jafama.FastMath;