Merge remote-tracking branch 'upstream/ver/6.0.0' into architecture/slf4j-logging

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
This commit is contained in:
solonovamax
2021-11-20 20:09:40 -05:00
738 changed files with 5185 additions and 17062 deletions

View File

@@ -1,6 +0,0 @@
# biome-provider-image
Implements and registers the `IMAGE` biome provider, a biome provider which
generates biomes from an image, using the `color` attribute of biomes.
This addon registers the provider type, and all associated config options.

View File

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

View File

@@ -1,64 +0,0 @@
package com.dfsek.terra.addons.biome.image;
import net.jafama.FastMath;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class ImageBiomeProvider implements BiomeProvider {
private final Map<Color, TerraBiome> colorBiomeMap = new HashMap<>();
private final BufferedImage image;
private final int resolution;
private final Align align;
public ImageBiomeProvider(Set<TerraBiome> registry, BufferedImage image, int resolution, Align align) {
this.image = image;
this.resolution = resolution;
this.align = align;
registry.forEach(biome -> colorBiomeMap.put(new Color(biome.getColor()), biome));
}
private static int distance(Color a, Color b) {
return FastMath.abs(a.getRed() - b.getRed()) + FastMath.abs(a.getGreen() - b.getGreen()) + FastMath.abs(a.getBlue() - b.getBlue());
}
@Override
public TerraBiome getBiome(int x, int z, long seed) {
x /= resolution;
z /= resolution;
Color color = align.getColor(image, x, z);
return colorBiomeMap.get(colorBiomeMap.keySet()
.stream()
.reduce(colorBiomeMap.keySet().stream().findAny().orElseThrow(IllegalStateException::new),
(running, element) -> {
int d1 = distance(color, running);
int d2 = distance(color, element);
return d1 < d2 ? running : element;
}));
}
public enum Align {
CENTER {
@Override
public Color getColor(BufferedImage image, int x, int z) {
return new Color(image.getRGB(FastMath.floorMod(x - image.getWidth() / 2, image.getWidth()),
FastMath.floorMod(z - image.getHeight() / 2, image.getHeight())));
}
},
NONE {
@Override
public Color getColor(BufferedImage image, int x, int z) {
return new Color(image.getRGB(FastMath.floorMod(x, image.getWidth()), FastMath.floorMod(z, image.getHeight())));
}
};
public abstract Color getColor(BufferedImage image, int x, int z);
}
}

View File

@@ -1,43 +0,0 @@
package com.dfsek.terra.addons.biome.image;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@Addon("biome-provider-image")
@Author("Terra")
@Version("1.0.0")
public class ImageBiomeProviderAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
};
@Inject
private Platform platform;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
PROVIDER_REGISTRY_KEY);
providerRegistry.register("IMAGE", () -> new ImageProviderTemplate(event.getPack().getRegistry(TerraBiome.class)));
})
.failThrough();
}
}

View File

@@ -1,33 +0,0 @@
package com.dfsek.terra.addons.biome.image;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class ImageProviderTemplate implements ObjectTemplate<BiomeProvider> {
private final Registry<TerraBiome> biomes;
@Value("resolution")
@Default
private int resolution = 1;
@Value("image.name")
private BufferedImage image;
@Value("image.align")
private ImageBiomeProvider.Align align;
public ImageProviderTemplate(Registry<TerraBiome> set) {
this.biomes = set;
}
@Override
public BiomeProvider get() {
return new ImageBiomeProvider(new HashSet<>(biomes.entries()), image, resolution, align);
}
}

View File

@@ -1,7 +0,0 @@
# biome-provider-pipeline
Implements the Biome Pipeline, a procedural biome provider that uses a series
of "stages" to apply "mutations" to a 2D grid of biomes.
This addon registers the `PIPELINE` biome provider type, and all associated
configurations.

View File

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

View File

@@ -1,87 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeExpander;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class BiomeHolderImpl implements BiomeHolder {
private final Vector2 origin;
private final int width;
private final int offset;
private TerraBiome[][] biomes;
public BiomeHolderImpl(int width, Vector2 origin) {
width += 4;
this.width = width;
biomes = new TerraBiome[width][width];
this.origin = origin;
this.offset = 2;
}
private BiomeHolderImpl(TerraBiome[][] biomes, Vector2 origin, int width, int offset) {
this.biomes = biomes;
this.origin = origin;
this.width = width;
this.offset = 2 * offset;
}
@Override
public BiomeHolder expand(BiomeExpander expander, long seed) {
TerraBiome[][] old = biomes;
int newWidth = width * 2 - 1;
biomes = new TerraBiome[newWidth][newWidth];
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
biomes[x * 2][z * 2] = old[x][z];
if(z != width - 1)
biomes[x * 2][z * 2 + 1] = expander.getBetween(x + origin.getX(), z + 1 + origin.getZ(), seed, old[x][z],
old[x][z + 1]);
if(x != width - 1)
biomes[x * 2 + 1][z * 2] = expander.getBetween(x + 1 + origin.getX(), z + origin.getZ(), seed, old[x][z],
old[x + 1][z]);
if(x != width - 1 && z != width - 1)
biomes[x * 2 + 1][z * 2 + 1] = expander.getBetween(x + 1 + origin.getX(), z + 1 + origin.getZ(), seed, old[x][z],
old[x + 1][z + 1], old[x][z + 1], old[x + 1][z]);
}
}
return new BiomeHolderImpl(biomes, origin.setX(origin.getX() * 2 - 1).setZ(origin.getZ() * 2 - 1), newWidth, offset);
}
@Override
public void mutate(BiomeMutator mutator, long seed) {
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
BiomeMutator.ViewPoint viewPoint = new BiomeMutator.ViewPoint(this, x, z);
biomes[x][z] = mutator.mutate(viewPoint, x + origin.getX(), z + origin.getZ(), seed);
}
}
}
@Override
public void fill(BiomeSource source, long seed) {
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
biomes[x][z] = source.getBiome(origin.getX() + x, origin.getZ() + z, seed);
}
}
}
@Override
public TerraBiome getBiome(int x, int z) {
x += offset;
z += offset;
return getBiomeRaw(x, z);
}
@Override
public TerraBiome getBiomeRaw(int x, int z) {
if(x >= width || z >= width || x < 0 || z < 0) return null;
return biomes[x][z];
}
}

View File

@@ -1,67 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline;
import java.util.ArrayList;
import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.util.vector.Vector2;
public class BiomePipeline {
private final BiomeSource source;
private final List<Stage> stages;
private final int size;
private final int init;
private BiomePipeline(BiomeSource source, List<Stage> stages, int size, int init) {
this.source = source;
this.stages = stages;
this.size = size;
this.init = init;
}
/**
* Get biomes in a chunk
*
* @param x Chunk X coord
* @param z Chunk Z coord
*
* @return BiomeHolder containing biomes.
*/
public BiomeHolder getBiomes(int x, int z, long seed) {
BiomeHolder holder = new BiomeHolderImpl(init, new Vector2(x * (init - 1), z * (init - 1)));
holder.fill(source, seed);
for(Stage stage : stages) holder = stage.apply(holder, seed);
return holder;
}
public int getSize() {
return size;
}
public static final class BiomePipelineBuilder {
private final int init;
private final List<Stage> stages = new ArrayList<>();
private int expand;
public BiomePipelineBuilder(int init) {
this.init = init;
expand = init;
}
public BiomePipeline build(BiomeSource source) {
for(Stage stage : stages) {
if(stage.isExpansion()) expand = expand * 2 - 1;
}
return new BiomePipeline(source, stages, expand, init);
}
public BiomePipelineBuilder addStage(Stage stage) {
stages.add(stage);
return this;
}
}
}

View File

@@ -1,71 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.BiomePipelineTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.NoiseSourceTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.expander.ExpanderStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.BorderListMutatorTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.BorderMutatorTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceListMutatorTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceMutatorTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.SmoothMutatorTemplate;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@Addon("biome-provider-pipeline")
@Author("Terra")
@Version("1.0.0")
public class BiomePipelineAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<BiomeSource>>> SOURCE_REGISTRY_KEY = new TypeKey<>() {
};
public static final TypeKey<Supplier<ObjectTemplate<Stage>>> STAGE_REGISTRY_KEY = new TypeKey<>() {
};
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
};
@Inject
private Platform platform;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
PROVIDER_REGISTRY_KEY);
providerRegistry.register("PIPELINE", () -> new BiomePipelineTemplate(platform));
})
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeSource>>> sourceRegistry = event.getPack().getOrCreateRegistry(
SOURCE_REGISTRY_KEY);
sourceRegistry.register("NOISE", NoiseSourceTemplate::new);
})
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<Stage>>> stageRegistry = event.getPack().getOrCreateRegistry(STAGE_REGISTRY_KEY);
stageRegistry.register("FRACTAL_EXPAND", ExpanderStageTemplate::new);
stageRegistry.register("SMOOTH", SmoothMutatorTemplate::new);
stageRegistry.register("REPLACE", ReplaceMutatorTemplate::new);
stageRegistry.register("REPLACE_LIST", ReplaceListMutatorTemplate::new);
stageRegistry.register("BORDER", BorderMutatorTemplate::new);
stageRegistry.register("BORDER_LIST", BorderListMutatorTemplate::new);
})
.failThrough();
}
}

View File

@@ -1,84 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomePipelineProvider implements BiomeProvider {
private final LoadingCache<SeededVector, BiomeHolder> holderCache;
private final BiomePipeline pipeline;
private final int resolution;
private final NoiseSampler mutator;
private final double noiseAmp;
public BiomePipelineProvider(BiomePipeline pipeline, Platform platform, int resolution, NoiseSampler mutator, double noiseAmp) {
this.resolution = resolution;
this.mutator = mutator;
this.noiseAmp = noiseAmp;
holderCache = CacheBuilder.newBuilder()
.maximumSize(platform == null ? 32 : platform.getTerraConfig().getProviderCache())
.build(
new CacheLoader<>() {
@Override
public BiomeHolder load(@NotNull SeededVector key) {
return pipeline.getBiomes(key.x, key.z, key.seed);
}
}
);
this.pipeline = pipeline;
}
@Override
public TerraBiome getBiome(int x, int z, long seed) {
x += mutator.getNoiseSeeded(seed + 1, x, z) * noiseAmp;
z += mutator.getNoiseSeeded(seed + 2, x, z) * noiseAmp;
x = FastMath.floorToInt(FastMath.floorDiv(x, resolution));
z = FastMath.floorToInt(FastMath.floorDiv(z, resolution));
int fdX = FastMath.floorDiv(x, pipeline.getSize());
int fdZ = FastMath.floorDiv(z, pipeline.getSize());
return holderCache.getUnchecked(new SeededVector(fdX, fdZ, seed)).getBiome(x - fdX * pipeline.getSize(),
z - fdZ * pipeline.getSize());
}
private static final class SeededVector {
private final int x;
private final int z;
private final long seed;
private SeededVector(int x, int z, long seed) {
this.x = x;
this.z = z;
this.seed = seed;
}
@Override
public int hashCode() {
int result = 0;
result = 31 * result + ((int) (seed ^ (seed >>> 32)));
result = 31 * result + x;
result = 31 * result + z;
return result;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof SeededVector)) return false;
SeededVector that = (SeededVector) obj;
return this.seed == that.seed && this.x == that.x && this.z == that.z;
}
}
}

View File

@@ -1,8 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.api.world.biome.TerraBiome;
public interface BiomeExpander {
TerraBiome getBetween(double x, double z, long seed, TerraBiome... others);
}

View File

@@ -1,17 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.world.biome.TerraBiome;
public interface BiomeHolder {
BiomeHolder expand(BiomeExpander expander, long seed);
void mutate(BiomeMutator mutator, long seed);
void fill(BiomeSource source, long seed);
TerraBiome getBiome(int x, int z);
TerraBiome getBiomeRaw(int x, int z);
}

View File

@@ -1,25 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.api.world.biome.TerraBiome;
public interface BiomeMutator {
TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed);
class ViewPoint {
private final BiomeHolder biomes;
private final int offX;
private final int offZ;
public ViewPoint(BiomeHolder biomes, int offX, int offZ) {
this.biomes = biomes;
this.offX = offX;
this.offZ = offZ;
}
public TerraBiome getBiome(int x, int z) {
return biomes.getBiomeRaw(x + offX, z + offZ);
}
}
}

View File

@@ -1,8 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.api;
public interface Stage {
BiomeHolder apply(BiomeHolder in, long seed);
boolean isExpansion();
}

View File

@@ -1,41 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.BiomePipeline;
import com.dfsek.terra.addons.biome.pipeline.BiomePipelineProvider;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@SuppressWarnings({ "FieldMayBeFinal", "unused" })
public class BiomePipelineTemplate extends BiomeProviderTemplate {
private final Platform platform;
@Value("pipeline.initial-size")
@Default
private @Meta int initialSize = 2;
@Value("pipeline.stages")
private @Meta List<@Meta Stage> stages;
@Value("pipeline.source")
private @Meta BiomeSource source;
public BiomePipelineTemplate(Platform platform) {
this.platform = platform;
}
@Override
public BiomeProvider get() {
BiomePipeline.BiomePipelineBuilder biomePipelineBuilder = new BiomePipeline.BiomePipelineBuilder(initialSize);
stages.forEach(biomePipelineBuilder::addStage);
BiomePipeline pipeline = biomePipelineBuilder.build(source);
return new BiomePipelineProvider(pipeline, platform, resolution, blend, blendAmp);
}
}

View File

@@ -1,18 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import java.lang.reflect.AnnotatedType;
import com.dfsek.terra.addons.biome.pipeline.BiomePipelineProvider;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomeProviderLoader implements TypeLoader<BiomeProvider> {
@Override
public BiomeProvider load(AnnotatedType t, Object c, ConfigLoader loader) throws LoadException {
return loader.loadType(BiomePipelineProvider.class, c); // TODO: actually implement this lol
}
}

View File

@@ -1,22 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvider> {
@Value("resolution")
@Default
protected @Meta int resolution = 1;
@Value("blend.noise")
@Default
protected @Meta NoiseSampler blend = NoiseSampler.zero();
@Value("blend.amplitude")
@Default
protected @Meta double blendAmp = 0d;
}

View File

@@ -1,24 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.addons.biome.pipeline.source.NoiseSource;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class NoiseSourceTemplate extends SourceTemplate {
@Value("noise")
private @Meta NoiseSampler noise;
@Value("biomes")
private @Meta ProbabilityCollection<@Meta TerraBiome> biomes;
@Override
public BiomeSource get() {
return new NoiseSource(biomes, noise);
}
}

View File

@@ -1,10 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
public abstract class SourceTemplate implements ObjectTemplate<BiomeSource> {
}

View File

@@ -1,14 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
public abstract class StageTemplate implements ObjectTemplate<Stage> {
@Value("noise")
protected @Meta NoiseSampler noise;
}

View File

@@ -1,14 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.expander;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.expand.FractalExpander;
import com.dfsek.terra.addons.biome.pipeline.stages.ExpanderStage;
public class ExpanderStageTemplate extends StageTemplate {
@Override
public Stage get() {
return new ExpanderStage(new FractalExpander(noise));
}
}

View File

@@ -1,35 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.BorderListMutator;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
@SuppressWarnings("unused")
public class BorderListMutatorTemplate extends StageTemplate {
@Value("from")
private @Meta String from;
@Value("default-replace")
private @Meta String defaultReplace;
@Value("default-to")
private @Meta ProbabilityCollection<@Meta TerraBiome> defaultTo;
@Value("replace")
private @Meta Map<@Meta TerraBiome, @Meta ProbabilityCollection<@Meta TerraBiome>> replace;
@Override
public Stage get() {
return new MutatorStage(new BorderListMutator(replace, from, defaultReplace, noise, defaultTo));
}
}

View File

@@ -1,29 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.BorderMutator;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
@SuppressWarnings("unused")
public class BorderMutatorTemplate extends StageTemplate {
@Value("from")
private @Meta String from;
@Value("replace")
private @Meta String replace;
@Value("to")
private @Meta ProbabilityCollection<@Meta TerraBiome> to;
@Override
public Stage get() {
return new MutatorStage(new BorderMutator(from, replace, noise, to));
}
}

View File

@@ -1,31 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceListMutator;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
@SuppressWarnings("unused")
public class ReplaceListMutatorTemplate extends StageTemplate {
@Value("default-from")
private @Meta String defaultFrom;
@Value("default-to")
private @Meta ProbabilityCollection<@Meta TerraBiome> defaultTo;
@Value("to")
private @Meta Map<@Meta TerraBiome, @Meta ProbabilityCollection<@Meta TerraBiome>> replace;
@Override
public Stage get() {
return new MutatorStage(new ReplaceListMutator(replace, defaultFrom, defaultTo, noise));
}
}

View File

@@ -1,26 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceMutator;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
@SuppressWarnings("unused")
public class ReplaceMutatorTemplate extends StageTemplate {
@Value("from")
private @Meta String from;
@Value("to")
private @Meta ProbabilityCollection<@Meta TerraBiome> to;
@Override
public Stage get() {
return new MutatorStage(new ReplaceMutator(from, to, noise));
}
}

View File

@@ -1,14 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.SmoothMutator;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage;
public class SmoothMutatorTemplate extends StageTemplate {
@Override
public Stage get() {
return new MutatorStage(new SmoothMutator(noise));
}
}

View File

@@ -1,20 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.expand;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeExpander;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class FractalExpander implements BiomeExpander {
private final NoiseSampler sampler;
public FractalExpander(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public TerraBiome getBetween(double x, double z, long seed, TerraBiome... others) {
return others[MathUtil.normalizeIndex(sampler.getNoiseSeeded(seed, x, z), others.length)];
}
}

View File

@@ -1,49 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class BorderListMutator implements BiomeMutator {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<TerraBiome> replaceDefault;
private final String defaultReplace;
private final Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace;
public BorderListMutator(Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace, String border, String defaultReplace,
NoiseSampler noiseSampler, ProbabilityCollection<TerraBiome> replaceDefault) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replaceDefault = replaceDefault;
this.defaultReplace = defaultReplace;
this.replace = replace;
}
@Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
TerraBiome origin = viewPoint.getBiome(0, 0);
if(origin.getTags().contains(defaultReplace)) {
for(int xi = -1; xi <= 1; xi++) {
for(int zi = -1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
TerraBiome current = viewPoint.getBiome(xi, zi);
if(current == null) continue;
if(current.getTags().contains(border)) {
if(replace.containsKey(origin)) {
TerraBiome biome = replace.get(origin).get(noiseSampler, x, z, seed);
return biome == null ? origin : biome;
}
TerraBiome biome = replaceDefault.get(noiseSampler, x, z, seed);
return biome == null ? origin : biome;
}
}
}
}
return origin;
}
}

View File

@@ -1,40 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.mutator;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class BorderMutator implements BiomeMutator {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<TerraBiome> replace;
private final String replaceTag;
public BorderMutator(String border, String replaceTag, NoiseSampler noiseSampler, ProbabilityCollection<TerraBiome> replace) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replace = replace;
this.replaceTag = replaceTag;
}
@Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
TerraBiome origin = viewPoint.getBiome(0, 0);
if(origin.getTags().contains(replaceTag)) {
for(int xi = -1; xi <= 1; xi++) {
for(int zi = -1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
TerraBiome current = viewPoint.getBiome(xi, zi);
if(current == null) continue;
if(current.getTags().contains(border)) {
TerraBiome biome = replace.get(noiseSampler, x, z, seed);
return biome == null ? origin : biome;
}
}
}
}
return origin;
}
}

View File

@@ -1,38 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class ReplaceListMutator implements BiomeMutator {
private final Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace;
private final NoiseSampler sampler;
private final ProbabilityCollection<TerraBiome> replaceDefault;
private final String defaultTag;
public ReplaceListMutator(Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace, String defaultTag,
ProbabilityCollection<TerraBiome> replaceDefault, NoiseSampler sampler) {
this.replace = replace;
this.sampler = sampler;
this.defaultTag = defaultTag;
this.replaceDefault = replaceDefault;
}
@Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
TerraBiome center = viewPoint.getBiome(0, 0);
if(replace.containsKey(center)) {
TerraBiome biome = replace.get(center).get(sampler, x, z, seed);
return biome == null ? viewPoint.getBiome(0, 0) : biome;
}
if(viewPoint.getBiome(0, 0).getTags().contains(defaultTag)) {
TerraBiome biome = replaceDefault.get(sampler, x, z, seed);
return biome == null ? viewPoint.getBiome(0, 0) : biome;
}
return center;
}
}

View File

@@ -1,28 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.mutator;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class ReplaceMutator implements BiomeMutator {
private final String replaceableTag;
private final ProbabilityCollection<TerraBiome> replace;
private final NoiseSampler sampler;
public ReplaceMutator(String replaceable, ProbabilityCollection<TerraBiome> replace, NoiseSampler sampler) {
this.replaceableTag = replaceable;
this.replace = replace;
this.sampler = sampler;
}
@Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
if(viewPoint.getBiome(0, 0).getTags().contains(replaceableTag)) {
TerraBiome biome = replace.get(sampler, x, z, seed);
return biome == null ? viewPoint.getBiome(0, 0) : biome;
}
return viewPoint.getBiome(0, 0);
}
}

View File

@@ -1,39 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.Objects;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class SmoothMutator implements BiomeMutator {
private final NoiseSampler sampler;
public SmoothMutator(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
TerraBiome top = viewPoint.getBiome(1, 0);
TerraBiome bottom = viewPoint.getBiome(-1, 0);
TerraBiome left = viewPoint.getBiome(0, 1);
TerraBiome right = viewPoint.getBiome(0, -1);
boolean vert = Objects.equals(top, bottom) && top != null;
boolean horiz = Objects.equals(left, right) && left != null;
if(vert && horiz) {
return MathUtil.normalizeIndex(sampler.getNoiseSeeded(seed, x, z), 2) == 0 ? left : top;
}
if(vert) return top;
if(horiz) return left;
return viewPoint.getBiome(0, 0);
}
}

View File

@@ -1,8 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.source;
import com.dfsek.terra.api.world.biome.TerraBiome;
public interface BiomeSource {
TerraBiome getBiome(double x, double z, long seed);
}

View File

@@ -1,21 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.source;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class NoiseSource implements BiomeSource {
private final ProbabilityCollection<TerraBiome> biomes;
private final NoiseSampler sampler;
public NoiseSource(ProbabilityCollection<TerraBiome> biomes, NoiseSampler sampler) {
this.biomes = biomes;
this.sampler = sampler;
}
@Override
public TerraBiome getBiome(double x, double z, long seed) {
return biomes.get(sampler, x, z, seed);
}
}

View File

@@ -1,28 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.stages;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeExpander;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
public class ExpanderStage implements Stage {
private final BiomeExpander expander;
public ExpanderStage(BiomeExpander expander) {
this.expander = expander;
}
@Override
public BiomeHolder apply(BiomeHolder in, long seed) {
return in.expand(expander, seed);
}
@Override
public boolean isExpansion() {
return true;
}
public enum Type {
FRACTAL
}
}

View File

@@ -1,33 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.stages;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
public class MutatorStage implements Stage {
private final BiomeMutator mutator;
public MutatorStage(BiomeMutator mutator) {
this.mutator = mutator;
}
@Override
public BiomeHolder apply(BiomeHolder in, long seed) {
in.mutate(mutator, seed);
return in;
}
@Override
public boolean isExpansion() {
return false;
}
public enum Type {
REPLACE,
REPLACE_LIST,
BORDER,
BORDER_LIST,
SMOOTH
}
}

View File

@@ -1,4 +0,0 @@
# biome-provider-single
Registers and configures the `SINGLE` biome provider, a biome provider which
accepts a single biome to generate continuously.

View File

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

View File

@@ -1,18 +0,0 @@
package com.dfsek.terra.addons.biome.single;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class SingleBiomeProvider implements BiomeProvider {
private final TerraBiome biome;
public SingleBiomeProvider(TerraBiome biome) {
this.biome = biome;
}
@Override
public TerraBiome getBiome(int x, int z, long seed) {
return biome;
}
}

View File

@@ -1,42 +0,0 @@
package com.dfsek.terra.addons.biome.single;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@Addon("biome-provider-single")
@Author("Terra")
@Version("1.0.0")
public class SingleBiomeProviderAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
};
@Inject
private Platform platform;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
PROVIDER_REGISTRY_KEY);
providerRegistry.register("SINGLE", SingleBiomeProviderTemplate::new);
})
.failThrough();
}
}

View File

@@ -1,19 +0,0 @@
package com.dfsek.terra.addons.biome.single;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class SingleBiomeProviderTemplate implements ObjectTemplate<BiomeProvider> {
@Value("biome")
private @Meta TerraBiome biome;
@Override
public BiomeProvider get() {
return new SingleBiomeProvider(biome);
}
}

View File

@@ -1,4 +0,0 @@
# chunk-generator-noise-3d
Registers the `NOISE_3D` chunk generator, a chunk generator which uses biomes'
samplers in 3D to generate chunk data.

View File

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

View File

@@ -1,30 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.generator.Palette;
public class BiomePaletteTemplate implements ObjectTemplate<PaletteInfo> {
@Value("slant")
@Default
private @Meta SlantHolder slant;
@Value("palette")
private @Meta PaletteHolder palette;
@Value("ocean.level")
private @Meta int seaLevel;
@Value("ocean.palette")
private @Meta Palette oceanPalette;
@Override
public PaletteInfo get() {
return new PaletteInfo(palette, slant, oceanPalette, seaLevel);
}
}

View File

@@ -1,53 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator;
import com.dfsek.terra.addons.chunkgenerator.generation.generators.NoiseChunkGenerator3D;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolderLoader;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolderLoader;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generator.ChunkGeneratorProvider;
@Addon("chunk-generator-noise-3d")
@Author("Terra")
@Version("1.0.0")
public class NoiseChunkGenerator3DAddon extends TerraAddon {
@Inject
private Platform platform;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> {
event.getPack().getOrCreateRegistry(ChunkGeneratorProvider.class).register("NOISE_3D",
pack -> new NoiseChunkGenerator3D(pack,
platform));
event.getPack()
.applyLoader(SlantHolder.class, new SlantHolderLoader())
.applyLoader(PaletteHolder.class, new PaletteHolderLoader());
})
.failThrough();
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigurationLoadEvent.class)
.then(event -> {
if(event.is(TerraBiome.class)) {
event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomePaletteTemplate()).get());
}
})
.failThrough();
}
}

View File

@@ -1,23 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.generator.Palette;
import com.dfsek.terra.api.util.math.Sampler;
public final class PaletteUtil {
public static Palette getPalette(int x, int y, int z, GenerationSettings c, Sampler sampler, PaletteInfo paletteInfo) {
SlantHolder slant = paletteInfo.getSlantHolder();
if(slant != null) {
double slope = MathUtil.derivative(sampler, x, y, z);
if(slope > slant.getMinSlope()) {
return slant.getPalette(slope).getPalette(y);
}
}
return paletteInfo.getPaletteHolder().getPalette(y);
}
}

View File

@@ -1,197 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.generation.generators;
import com.dfsek.terra.api.Platform;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.dfsek.terra.addons.chunkgenerator.PaletteUtil;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.block.state.properties.base.Properties;
import com.dfsek.terra.api.block.state.properties.enums.Direction;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.profiler.ProfileFrame;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.BiomeGrid;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.ChunkData;
import com.dfsek.terra.api.world.generator.ChunkGenerator;
import com.dfsek.terra.api.world.generator.GenerationStage;
import com.dfsek.terra.api.world.generator.Palette;
import com.dfsek.terra.api.util.math.Sampler;
public class NoiseChunkGenerator3D implements ChunkGenerator {
private static final Logger logger = LoggerFactory.getLogger(NoiseChunkGenerator3D.class);
private final ConfigPack configPack;
private final Platform platform;
private final List<GenerationStage> generationStages = new ArrayList<>();
private final BlockState air;
public NoiseChunkGenerator3D(ConfigPack c, Platform platform) {
this.configPack = c;
this.platform = platform;
this.air = platform.getWorldHandle().air();
c.getStages().forEach(stage -> generationStages.add(stage.newInstance(c)));
}
@SuppressWarnings("try")
static void biomes(@NotNull World world, int chunkX, int chunkZ, @NotNull BiomeGrid biome, Platform platform) {
try(ProfileFrame ignore = platform.getProfiler().profile("biomes")) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
long seed = world.getSeed();
BiomeProvider grid = world.getBiomeProvider();
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
int cx = xOrig + (x << 2);
int cz = zOrig + (z << 2);
TerraBiome b = grid.getBiome(cx, cz, seed);
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator().getBiomeNoise(), cx, 0, cz, world.getSeed()));
}
}
}
}
@Override
@SuppressWarnings("try")
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
try(ProfileFrame ignore = platform.getProfiler().profile("chunk_base_3d")) {
BiomeProvider grid = world.getBiomeProvider();
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
Sampler sampler = world.getConfig().getSamplerCache().getChunk(chunkX, chunkZ);
long seed = world.getSeed();
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
int paletteLevel = 0;
int cx = xOrig + x;
int cz = zOrig + z;
TerraBiome biome = grid.getBiome(cx, cz, seed);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
if(paletteInfo == null) {
logger.info("null palette: {}", biome.getID());
}
GenerationSettings generationSettings = biome.getGenerator();
int sea = paletteInfo.getSeaLevel();
Palette seaPalette = paletteInfo.getOcean();
boolean justSet = false;
BlockState data = null;
for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) {
if(sampler.sample(x, y, z) > 0) {
justSet = true;
data = PaletteUtil.getPalette(x, y, z, generationSettings, sampler, paletteInfo).get(paletteLevel, cx, y, cz,
seed);
chunk.setBlock(x, y, z, data);
paletteLevel++;
} else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig, seed));
justSet = false;
paletteLevel = 0;
} else {
justSet = false;
paletteLevel = 0;
}
}
}
}
return chunk;
}
}
@Override
public void generateBiomes(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, @NotNull BiomeGrid biome) {
biomes(world, chunkX, chunkZ, biome, platform);
}
@Override
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler3D(chunkX, chunkZ, provider, world, elevationSmooth);
}
@Override
public ConfigPack getConfigPack() {
return configPack;
}
@Override
public Platform getPlatform() {
return platform;
}
@Override
public List<GenerationStage> getGenerationStages() {
return generationStages;
}
@Override
public BlockState getBlock(World world, int x, int y, int z) {
BiomeProvider provider = world.getBiomeProvider();
TerraBiome biome = provider.getBiome(x, z, world.getSeed());
Sampler sampler = world.getConfig().getSamplerCache().get(x, z);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
Palette palette = PaletteUtil.getPalette(x, y, z, biome.getGenerator(), sampler, paletteInfo);
int fdX = FastMath.floorMod(x, 16);
int fdZ = FastMath.floorMod(z, 16);
double noise = sampler.sample(fdX, y, fdZ);
if(noise > 0) {
int level = 0;
for(int yi = world.getMaxHeight() - 1; yi > y; yi--) {
if(sampler.sample(fdX, yi, fdZ) > 0) level++;
else level = 0;
}
return palette.get(level, x, y, z, world.getSeed());
} else if(y <= paletteInfo.getSeaLevel()) {
return paletteInfo.getOcean().get(paletteInfo.getSeaLevel() - y, x, y, z, world.getSeed());
} else return air;
}
private boolean placeStair(BlockState orig, ChunkData chunk, Vector3 block, double thresh, Sampler sampler, BlockState stairNew) {
if(sampler.sample(block.getBlockX() - 0.55, block.getY(), block.getZ()) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.WEST);
} else if(sampler.sample(block.getBlockX(), block.getY(), block.getZ() - 0.55) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.NORTH);
} else if(sampler.sample(block.getBlockX(), block.getY(), block.getZ() + 0.55) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.SOUTH);
} else if(sampler.sample(block.getX() + 0.55, block.getY(), block.getZ()) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.EAST);
} else stairNew = null;
if(stairNew != null) {
stairNew.setIfPresent(Properties.WATERLOGGED, orig.getBlockType().isWater());
chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), stairNew);
return true;
}
return false;
}
}

View File

@@ -1,97 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.ChunkInterpolator;
/**
* Class to abstract away the Interpolators needed to generate a chunk.<br>
* Contains method to get interpolated noise at a coordinate within the chunk.
*/
public class ChunkInterpolator2D implements ChunkInterpolator {
private final Interpolator[][] interpGrid = new Interpolator[4][4];
private final BiFunction<GenerationSettings, Vector3, Double> noiseGetter;
/**
* Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates.
*
* @param chunkX X coordinate of the chunk.
* @param chunkZ Z coordinate of the chunk.
* @param provider Biome Provider to use for biome fetching.
*/
public ChunkInterpolator2D(World w, int chunkX, int chunkZ, BiomeProvider provider,
BiFunction<GenerationSettings, Vector3, Double> noiseGetter) {
this.noiseGetter = noiseGetter;
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
long seed = w.getSeed();
double[][] noiseStorage = new double[5][5];
for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) {
GenerationSettings generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed).getGenerator();
Map<GenerationSettings, MutableInteger> genMap = new HashMap<>();
int step = generationSettings.getBlendStep();
int blend = generationSettings.getBlendDistance();
for(int xi = -blend; xi <= blend; xi++) {
for(int zi = -blend; zi <= blend; zi++) {
genMap.computeIfAbsent(
provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed).getGenerator(),
g -> new MutableInteger(0)).increment(); // Increment by 1
}
}
noiseStorage[x][z] = computeNoise(genMap, (x << 2) + xOrigin, 0, (z << 2) + zOrigin);
}
}
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
interpGrid[x][z] = new Interpolator(
noiseStorage[x][z],
noiseStorage[x + 1][z],
noiseStorage[x][z + 1],
noiseStorage[x + 1][z + 1]);
}
}
}
private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0);
}
public double computeNoise(GenerationSettings generationSettings, double x, double y, double z) {
return noiseGetter.apply(generationSettings, new Vector3(x, y, z));
}
/**
* Gets the noise at a pair of internal chunk coordinates.
*
* @param x The internal X coordinate (0-15).
* @param z The internal Z coordinate (0-15).
*
* @return double - The interpolated noise at the coordinates.
*/
@Override
public double getNoise(double x, double y, double z) {
return interpGrid[reRange(((int) x) / 4, 3)][reRange(((int) z) / 4, 3)].bilerp((x % 4) / 4, (z % 4) / 4);
}
public double getNoise(int x, int y, int z) {
return interpGrid[x / 4][z / 4].bilerp((double) (x % 4) / 4, (double) (z % 4) / 4);
}
}

View File

@@ -1,118 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.ChunkInterpolator;
/**
* Class to abstract away the Interpolators needed to generate a chunk.<br>
* Contains method to get interpolated noise at a coordinate within the chunk.
*/
public class ChunkInterpolator3D implements ChunkInterpolator {
private final Interpolator3[][][] interpGrid;
private final BiFunction<GenerationSettings, Vector3, Double> noiseGetter;
private final int min;
private final int max;
/**
* Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates.
*
* @param chunkX X coordinate of the chunk.
* @param chunkZ Z coordinate of the chunk.
* @param provider Biome Provider to use for biome fetching.
*/
public ChunkInterpolator3D(World w, int chunkX, int chunkZ, BiomeProvider provider,
BiFunction<GenerationSettings, Vector3, Double> noiseGetter) {
this.noiseGetter = noiseGetter;
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
this.max = w.getMaxHeight();
this.min = w.getMinHeight();
int range = max - min + 1;
int size = range >> 2;
interpGrid = new Interpolator3[4][size][4];
double[][][] noiseStorage = new double[5][5][size + 1];
long seed = w.getSeed();
for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) {
GenerationSettings generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed).getGenerator();
Map<GenerationSettings, MutableInteger> genMap = new HashMap<>();
int step = generationSettings.getBlendStep();
int blend = generationSettings.getBlendDistance();
for(int xi = -blend; xi <= blend; xi++) {
for(int zi = -blend; zi <= blend; zi++) {
genMap.computeIfAbsent(
provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed).getGenerator(),
g -> new MutableInteger(0)).increment(); // Increment by 1
}
}
for(int y = 0; y < size + 1; y++) {
noiseStorage[x][z][y] = computeNoise(genMap, (x << 2) + xOrigin, (y << 2) + min, (z << 2) + zOrigin);
}
}
}
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
for(int y = 0; y < size; y++) {
interpGrid[x][y][z] = new Interpolator3(
noiseStorage[x][z][y],
noiseStorage[x + 1][z][y],
noiseStorage[x][z][y + 1],
noiseStorage[x + 1][z][y + 1],
noiseStorage[x][z + 1][y],
noiseStorage[x + 1][z + 1][y],
noiseStorage[x][z + 1][y + 1],
noiseStorage[x + 1][z + 1][y + 1]);
}
}
}
}
private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0);
}
public double computeNoise(GenerationSettings generationSettings, double x, double y, double z) {
return noiseGetter.apply(generationSettings, new Vector3(x, y, z));
}
/**
* Gets the noise at a pair of internal chunk coordinates.
*
* @param x The internal X coordinate (0-15).
* @param z The internal Z coordinate (0-15).
*
* @return double - The interpolated noise at the coordinates.
*/
@Override
public double getNoise(double x, double y, double z) {
return interpGrid[reRange(((int) x) / 4, 3)][(FastMath.max(FastMath.min(((int) y), max), min) - min) / 4][reRange(((int) z) / 4,
3)].trilerp(
(x % 4) / 4, (y % 4) / 4, (z % 4) / 4);
}
public double getNoise(int x, int y, int z) {
return interpGrid[x / 4][(y - min) / 4][z / 4].trilerp((double) (x % 4) / 4, (double) (y % 4) / 4, (double) (z % 4) / 4);
}
}

View File

@@ -1,45 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class ElevationInterpolator {
private final double[][] values = new double[18][18];
public ElevationInterpolator(World world, int chunkX, int chunkZ, BiomeProvider provider, int smooth) {
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
long seed = world.getSeed();
GenerationSettings[][] gens = new GenerationSettings[18 + 2 * smooth][18 + 2 * smooth];
// Precompute generators.
for(int x = -1 - smooth; x <= 16 + smooth; x++) {
for(int z = -1 - smooth; z <= 16 + smooth; z++) {
gens[x + 1 + smooth][z + 1 + smooth] = provider.getBiome(xOrigin + x, zOrigin + z, seed).getGenerator();
}
}
for(int x = -1; x <= 16; x++) {
for(int z = -1; z <= 16; z++) {
double noise = 0;
double div = 0;
for(int xi = -smooth; xi <= smooth; xi++) {
for(int zi = -smooth; zi <= smooth; zi++) {
GenerationSettings gen = gens[x + 1 + smooth + xi][z + 1 + smooth + zi];
noise += gen.getElevationSampler().getNoiseSeeded(seed, xOrigin + x, zOrigin + z) * gen.getElevationWeight();
div += gen.getElevationWeight();
}
}
values[x + 1][z + 1] = noise / div;
}
}
}
public double getElevation(int x, int z) {
return values[x + 1][z + 1];
}
}

View File

@@ -1,50 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
/**
* Class for bilinear interpolation of values arranged on a unit square.
*/
public class Interpolator {
private final double v0, v1, v2, v3;
/**
* Constructs an interpolator with given values as vertices of a unit square.
*
* @param v0 - (0,0)
* @param v1 - (1,0)
* @param v2 - (0,1)
* @param v3 - (1,1)
*/
public Interpolator(double v0, double v1, double v2, double v3) {
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
}
/**
* 1D Linear interpolation between 2 points 1 unit apart.
*
* @param t - Distance from v0. Total distance between v0 and v1 is 1 unit.
* @param v0 - Value at v0.
* @param v1 - Value at v1.
*
* @return double - The interpolated value.
*/
public static double lerp(double t, double v0, double v1) {
return v0 + t * (v1 - v0);
}
/**
* 2D Bilinear interpolation between 4 points on a unit square.
*
* @param s - X value
* @param t - Z value
*
* @return double - The interpolated value.
*/
public double bilerp(double s, double t) {
double v01 = lerp(s, v0, v1);
double v23 = lerp(s, v2, v3);
return lerp(t, v01, v23);
}
}

View File

@@ -1,32 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
/**
* Class for bilinear interpolation of values arranged on a unit square.
*/
public class Interpolator3 {
private final Interpolator bottom;
private final Interpolator top;
/**
* Constructs an interpolator with given values as vertices of a unit cube.
* * @param _000 The value at <code>(t, u, v) = (0, 0, 0)</code>.
* * @param _100 The value at <code>(t, u, v) = (1, 0, 0)</code>.
* * @param _010 The value at <code>(t, u, v) = (0, 1, 0)</code>.
* * @param _110 The value at <code>(t, u, v) = (1, 1, 0)</code>.
* * @param _001 The value at <code>(t, u, v) = (0, 0, 1)</code>.
* * @param _101 The value at <code>(t, u, v) = (1, 0, 1)</code>.
* * @param _011 The value at <code>(t, u, v) = (0, 1, 1)</code>.
* * @param _111 The value at <code>(t, u, v) = (1, 1, 1)</code>.
*/
public Interpolator3(double _000, double _100,
double _010, double _110,
double _001, double _101,
double _011, double _111) {
this.top = new Interpolator(_000, _010, _001, _011);
this.bottom = new Interpolator(_100, _110, _101, _111);
}
public double trilerp(double x, double y, double z) {
return Interpolator.lerp(x, top.bilerp(y, z), bottom.bilerp(y, z));
}
}

View File

@@ -1,32 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.samplers;
import net.jafama.FastMath;
import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ChunkInterpolator3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ElevationInterpolator;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.util.math.Sampler;
public class Sampler3D implements Sampler {
private final ChunkInterpolator3D interpolator;
private final ElevationInterpolator elevationInterpolator;
public Sampler3D(int x, int z, BiomeProvider provider, World world, int elevationSmooth) {
this.interpolator = new ChunkInterpolator3D(world, x, z, provider, (generator, coord) -> generator.getBaseSampler()
.getNoiseSeeded(coord,
world.getSeed()));
this.elevationInterpolator = new ElevationInterpolator(world, x, z, provider, elevationSmooth);
}
@Override
public double sample(double x, double y, double z) {
return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));
}
@Override
public double sample(int x, int y, int z) {
return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));
}
}

View File

@@ -1,23 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolder {
private final Palette[] palettes;
private final int offset;
protected PaletteHolder(Palette[] palettes, int offset) {
this.palettes = palettes;
this.offset = offset;
}
public Palette getPalette(int y) {
int index = y + offset;
return index >= 0
? index < palettes.length
? palettes[index]
: palettes[palettes.length - 1]
: palettes[0];
}
}

View File

@@ -1,38 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.palette;
import net.jafama.FastMath;
import java.util.Map;
import java.util.TreeMap;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderBuilder {
private final TreeMap<Integer, Palette> paletteMap = new TreeMap<>();
public PaletteHolderBuilder add(int y, Palette palette) {
paletteMap.put(y, palette);
return this;
}
public PaletteHolder build() {
int min = FastMath.min(paletteMap.keySet().stream().min(Integer::compareTo).orElse(0), 0);
int max = FastMath.max(paletteMap.keySet().stream().max(Integer::compareTo).orElse(255), 255);
Palette[] palettes = new Palette[paletteMap.lastKey() + 1 - min];
for(int y = min; y <= FastMath.max(paletteMap.lastKey(), max); y++) {
Palette d = null;
for(Map.Entry<Integer, Palette> e : paletteMap.entrySet()) {
if(e.getKey() >= y) {
d = e.getValue();
break;
}
}
if(d == null) throw new IllegalArgumentException("No palette for Y=" + y);
palettes[y - min] = d;
}
return new PaletteHolder(palettes, -min);
}
}

View File

@@ -1,27 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import java.lang.reflect.AnnotatedType;
import java.util.List;
import java.util.Map;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderLoader implements TypeLoader<PaletteHolder> {
@SuppressWarnings("unchecked")
@Override
public PaletteHolder load(AnnotatedType type, Object o, ConfigLoader configLoader) throws LoadException {
List<Map<String, Integer>> palette = (List<Map<String, Integer>>) o;
PaletteHolderBuilder builder = new PaletteHolderBuilder();
for(Map<String, Integer> layer : palette) {
for(Map.Entry<String, Integer> entry : layer.entrySet()) {
builder.add(entry.getValue(), configLoader.loadType(Palette.class, entry.getKey()));
}
}
return builder.build();
}
}

View File

@@ -1,36 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.terra.api.properties.Properties;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteInfo implements Properties {
private final PaletteHolder paletteHolder;
private final SlantHolder slantHolder;
private final Palette ocean;
private final int seaLevel;
public PaletteInfo(PaletteHolder paletteHolder, SlantHolder slantHolder, Palette ocean, int seaLevel) {
this.paletteHolder = paletteHolder;
this.slantHolder = slantHolder;
this.ocean = ocean;
this.seaLevel = seaLevel;
}
public Palette getOcean() {
return ocean;
}
public PaletteHolder getPaletteHolder() {
return paletteHolder;
}
public SlantHolder getSlantHolder() {
return slantHolder;
}
public int getSeaLevel() {
return seaLevel;
}
}

View File

@@ -1,23 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.palette;
import java.util.TreeMap;
public class SlantHolder {
private final TreeMap<Double, PaletteHolder> layers;
private final double minSlope;
public SlantHolder(TreeMap<Double, PaletteHolder> layers, double minSlope) {
this.layers = layers;
this.minSlope = minSlope;
}
public PaletteHolder getPalette(double slope) {
return layers.floorEntry(slope).getValue();
}
public double getMinSlope() {
return minSlope;
}
}

View File

@@ -1,29 +0,0 @@
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import java.lang.reflect.AnnotatedType;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@SuppressWarnings("unchecked")
public class SlantHolderLoader implements TypeLoader<SlantHolder> {
@Override
public SlantHolder load(AnnotatedType type, Object o, ConfigLoader configLoader) throws LoadException {
List<Map<Object, Object>> layers = (List<Map<Object, Object>>) o;
TreeMap<Double, PaletteHolder> slantLayers = new TreeMap<>();
double minThreshold = Double.MAX_VALUE;
for(Map<Object, Object> layer : layers) {
double threshold = ((Number) layer.get("threshold")).doubleValue();
if(threshold < minThreshold) minThreshold = threshold;
slantLayers.put(threshold, configLoader.loadType(PaletteHolder.class, layer.get("palette")));
}
return new SlantHolder(slantLayers, minThreshold);
}
}

View File

@@ -1,3 +0,0 @@
# config-biome
Registers the default configuration for Terra Biomes, `BIOME`.

View File

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

View File

@@ -1,33 +0,0 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.addons.biome.holder.PaletteHolder;
import com.dfsek.terra.addons.biome.holder.PaletteHolderLoader;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
@Addon("config-biome")
@Author("Terra")
@Version("1.0.0")
public class BiomeAddon extends TerraAddon {
@Inject
private Platform platform;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> {
event.getPack().registerConfigType(new BiomeConfigType(event.getPack()), "BIOME", 5);
event.getPack().applyLoader(PaletteHolder.class, new PaletteHolderLoader());
})
.failThrough();
}
}

View File

@@ -1,51 +0,0 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.TypeLoader;
import java.util.function.Supplier;
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.config.ConfigType;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class BiomeConfigType implements ConfigType<BiomeTemplate, TerraBiome> {
public static final TypeKey<TerraBiome> BIOME_TYPE_TOKEN = new TypeKey<>() {
};
private final BiomeFactory factory;
public BiomeConfigType(ConfigPack pack) {
this.factory = new BiomeFactory(pack);
}
@Override
public Supplier<OpenRegistry<TerraBiome>> registrySupplier(ConfigPack pack) {
return () -> pack.getRegistryFactory().create(registry -> (TypeLoader<TerraBiome>) (t, c, loader) -> {
if(c.equals("SELF")) return null;
TerraBiome obj = registry.get((String) c);
if(obj == null)
throw new LoadException("No such " + t.getType().getTypeName() + " matching \"" + c + "\" was found in this registry.");
return obj;
});
}
@Override
public BiomeTemplate getTemplate(ConfigPack pack, Platform platform) {
return new BiomeTemplate(pack, platform);
}
@Override
public ConfigFactory<BiomeTemplate, TerraBiome> getFactory() {
return factory;
}
@Override
public TypeKey<TerraBiome> getTypeKey() {
return BIOME_TYPE_TOKEN;
}
}

View File

@@ -1,26 +0,0 @@
package com.dfsek.terra.addons.biome;
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.world.biome.TerraBiome;
public class BiomeFactory implements ConfigFactory<BiomeTemplate, TerraBiome> {
private final ConfigPack pack;
public BiomeFactory(ConfigPack pack) {
this.pack = pack;
}
@Override
public TerraBiome build(BiomeTemplate template, Platform platform) {
UserDefinedGenerationSettings generator = new UserDefinedGenerationSettings(template.getNoiseEquation(),
template.getElevationEquation(),
template.getCarvingEquation(), template.getBiomeNoise(),
template.getElevationWeight(),
template.getBlendDistance(), template.getBlendStep(),
template.getBlendWeight());
return new UserDefinedBiome(template.getVanilla(), generator, template);
}
}

View File

@@ -1,213 +0,0 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Final;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.config.AbstractableTemplate;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.generator.Palette;
@SuppressWarnings({ "FieldMayBeFinal", "unused" })
public class BiomeTemplate implements AbstractableTemplate, ValidatedConfigTemplate {
private final ConfigPack pack;
@Value("id")
@Final
private @Meta String id;
@Value("extends")
@Final
@Default
private List<String> extended = Collections.emptyList();
@Value("variables")
@Default
private @Meta Map<String, @Meta Double> variables = new HashMap<>();
@Value("beta.carving.equation")
@Default
private @Meta NoiseSampler carvingEquation = NoiseSampler.zero();
@Value("vanilla")
private @Meta ProbabilityCollection<Biome> vanilla;
@Value("biome-noise")
@Default
private @Meta NoiseSampler biomeNoise = NoiseSampler.zero();
@Value("blend.distance")
@Default
private @Meta int blendDistance = 3;
@Value("blend.weight")
@Default
private @Meta double blendWeight = 1;
@Value("blend.step")
@Default
private @Meta int blendStep = 4;
@Value("noise")
private @Meta NoiseSampler noiseEquation;
@Value("ocean.level")
@Default
private @Meta int seaLevel = 62;
@Value("elevation.equation")
@Default
private @Meta NoiseSampler elevationEquation = NoiseSampler.zero();
@Value("elevation.weight")
@Default
private @Meta double elevationWeight = 1;
@Value("slabs.enable")
@Default
private @Meta boolean doSlabs = false;
@Value("slabs.threshold")
@Default
private @Meta double slabThreshold = 0.0075D;
@Value("slabs.palettes")
@Default
private @Meta Map<@Meta BlockType, @Meta Palette> slabPalettes;
@Value("slabs.stair-palettes")
@Default
private @Meta Map<@Meta BlockType, @Meta Palette> stairPalettes;
@Value("interpolate-elevation")
@Default
private @Meta boolean interpolateElevation = true;
@Value("color")
@Final
@Default
private @Meta int color = 0;
@Value("tags")
@Default
private @Meta Set<@Meta String> tags = new HashSet<>();
@Value("colors")
@Default
private @Meta Map<String, @Meta Integer> colors = new HashMap<>();
// Plain ol' map, so platforms can decide what to do with colors (if anything).
public BiomeTemplate(ConfigPack pack, Platform platform) {
this.pack = pack;
}
public boolean interpolateElevation() {
return interpolateElevation;
}
public boolean doSlabs() {
return doSlabs;
}
@Override
public boolean validate() throws ValidationException {
color |= 0xff000000; // Alpha adjustment
return true;
}
public List<String> getExtended() {
return extended;
}
public Set<String> getTags() {
return tags;
}
public Map<String, Integer> getColors() {
return colors;
}
public double getBlendWeight() {
return blendWeight;
}
public int getColor() {
return color;
}
public int getBlendDistance() {
return blendDistance;
}
public double getSlabThreshold() {
return slabThreshold;
}
public Map<BlockType, Palette> getSlabPalettes() {
return slabPalettes;
}
public Map<BlockType, Palette> getStairPalettes() {
return stairPalettes;
}
public NoiseSampler getBiomeNoise() {
return biomeNoise;
}
public NoiseSampler getElevationEquation() {
return elevationEquation;
}
public NoiseSampler getCarvingEquation() {
return carvingEquation;
}
public ConfigPack getPack() {
return pack;
}
public int getSeaLevel() {
return seaLevel;
}
public String getID() {
return id;
}
public ProbabilityCollection<Biome> getVanilla() {
return vanilla;
}
public NoiseSampler getNoiseEquation() {
return noiseEquation;
}
public double getElevationWeight() {
return elevationWeight;
}
public int getBlendStep() {
return blendStep;
}
public Map<String, Double> getVariables() {
return variables;
}
}

View File

@@ -1,19 +0,0 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.addons.biome.holder.PaletteHolder;
import com.dfsek.terra.api.world.biome.PaletteSettings;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteSettingsImpl implements PaletteSettings {
private final PaletteHolder palette;
public PaletteSettingsImpl(PaletteHolder palette) {
this.palette = palette;
}
@Override
public Palette getPalette(int y) {
return palette.getPalette(y);
}
}

View File

@@ -1,78 +0,0 @@
package com.dfsek.terra.addons.biome;
import java.util.Set;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.TerraBiome;
/**
* Class representing a config-defined biome
*/
public class UserDefinedBiome implements TerraBiome {
private final UserDefinedGenerationSettings gen;
private final ProbabilityCollection<Biome> vanilla;
private final String id;
private final BiomeTemplate config;
private final int color;
private final Set<String> tags;
private final Context context = new Context();
public UserDefinedBiome(ProbabilityCollection<Biome> vanilla, UserDefinedGenerationSettings gen, BiomeTemplate config) {
this.vanilla = vanilla;
this.gen = gen;
this.id = config.getID();
this.config = config;
this.color = config.getColor();
this.tags = config.getTags();
tags.add("BIOME:" + id);
}
@Override
public String toString() {
return "{BIOME:" + getID() + "}";
}
/**
* Gets the Vanilla biomes to represent the custom biome.
*
* @return Collection of biomes to represent the custom biome.
*/
@Override
public ProbabilityCollection<Biome> getVanillaBiomes() {
return vanilla;
}
@Override
public GenerationSettings getGenerator() {
return gen;
}
@Override
public int getColor() {
return color;
}
@Override
public Set<String> getTags() {
return tags;
}
@Override
public String getID() {
return id;
}
public BiomeTemplate getConfig() {
return config;
}
@Override
public Context getContext() {
return context;
}
}

View File

@@ -1,71 +0,0 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.GenerationSettings;
public class UserDefinedGenerationSettings implements GenerationSettings {
private final NoiseSampler noise;
private final NoiseSampler elevation;
private final NoiseSampler carving;
private final NoiseSampler biomeNoise;
private final double elevationWeight;
private final int blendDistance;
private final int blendStep;
private final double blendWeight;
public UserDefinedGenerationSettings(NoiseSampler noise, NoiseSampler elevation, NoiseSampler carving, NoiseSampler biomeNoise,
double elevationWeight, int blendDistance, int blendStep, double blendWeight) {
this.noise = noise;
this.elevation = elevation;
this.carving = carving;
this.biomeNoise = biomeNoise;
this.elevationWeight = elevationWeight;
this.blendDistance = blendDistance;
this.blendStep = blendStep;
this.blendWeight = blendWeight;
}
@Override
public NoiseSampler getBaseSampler() {
return noise;
}
@Override
public NoiseSampler getElevationSampler() {
return elevation;
}
@Override
public NoiseSampler getCarver() {
return carving;
}
@Override
public int getBlendDistance() {
return blendDistance;
}
@Override
public double getWeight() {
return blendWeight;
}
@Override
public NoiseSampler getBiomeNoise() {
return biomeNoise;
}
@Override
public double getElevationWeight() {
return elevationWeight;
}
@Override
public int getBlendStep() {
return blendStep;
}
}

View File

@@ -1,117 +0,0 @@
package com.dfsek.terra.addons.biome.command.biome;
import com.dfsek.terra.api.Platform;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
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;
/**
* Runnable that locates a biome asynchronously
*/
public class AsyncBiomeFinder implements Runnable {
protected final BiomeProvider provider;
protected final TerraBiome target;
protected final int startRadius;
protected final int maxRadius;
protected final int centerX;
protected final int centerZ;
protected final World world;
protected final Platform platform;
private final Consumer<Vector3> callback;
protected int searchSize = 1;
public AsyncBiomeFinder(BiomeProvider provider, TerraBiome target, @NotNull Vector3 origin, World world, int startRadius, int maxRadius,
Consumer<Vector3> callback, Platform platform) {
this.provider = provider;
this.target = target;
this.platform = platform;
this.startRadius = startRadius;
this.maxRadius = maxRadius;
this.centerX = origin.getBlockX();
this.centerZ = origin.getBlockZ();
this.world = world;
this.callback = callback;
}
public Vector3 finalizeVector(Vector3 orig) {
return orig.multiply(platform.getTerraConfig().getBiomeSearchResolution());
}
@Override
public void run() {
int x = centerX;
int z = centerZ;
x /= searchSize;
z /= searchSize;
int run = 1;
boolean toggle = true;
boolean found = false;
main:
for(int i = startRadius; i < maxRadius; i++) {
for(int j = 0; j < run; j++) {
if(isValid(x, z, target)) {
found = true;
break main;
}
if(toggle) x += 1;
else x -= 1;
}
for(int j = 0; j < run; j++) {
if(isValid(x, z, target)) {
found = true;
break main;
}
if(toggle) z += 1;
else z -= 1;
}
run++;
toggle = !toggle;
}
Vector3 finalSpawn = found ? finalizeVector(new Vector3(x, 0, z)) : null;
callback.accept(finalSpawn);
}
/**
* Helper method to get biome at location
*
* @param x X coordinate
* @param z Z coordinate
*
* @return TerraBiome at coordinates
*/
public boolean isValid(int x, int z, TerraBiome target) {
int res = platform.getTerraConfig().getBiomeSearchResolution();
return getProvider().getBiome(x * res, z * res, world.getSeed()).equals(target);
}
public TerraBiome getTarget() {
return target;
}
public World getWorld() {
return world;
}
public BiomeProvider getProvider() {
return provider;
}
public int getSearchSize() {
return searchSize;
}
public void setSearchSize(int searchSize) {
this.searchSize = searchSize;
}
}

View File

@@ -1,37 +0,0 @@
package com.dfsek.terra.addons.biome.command.biome;
import com.dfsek.terra.addons.biome.UserDefinedBiome;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.Subcommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.entity.CommandSender;
import com.dfsek.terra.api.entity.Player;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@Command(
subcommands = {
@Subcommand(value = "info", aliases = "i", clazz = BiomeInfoCommand.class),
@Subcommand(value = "locate", aliases = "l", clazz = BiomeLocateCommand.class)
},
usage = "/terra biome"
)
@WorldCommand
@PlayerCommand
public class BiomeCommand implements CommandTemplate {
@Inject
private Platform platform;
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
BiomeProvider provider = player.world().getBiomeProvider();
UserDefinedBiome biome = (UserDefinedBiome) provider.getBiome(player.position(), player.world().getSeed());
sender.sendMessage("You are standing in " + biome.getID());
}
}

View File

@@ -1,40 +0,0 @@
package com.dfsek.terra.addons.biome.command.biome;
import com.dfsek.terra.addons.biome.BiomeTemplate;
import com.dfsek.terra.addons.biome.UserDefinedBiome;
import com.dfsek.terra.addons.biome.command.biome.arg.BiomeArgumentParser;
import com.dfsek.terra.addons.biome.command.biome.tab.BiomeTabCompleter;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Argument;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
import com.dfsek.terra.api.entity.CommandSender;
import com.dfsek.terra.api.world.biome.TerraBiome;
@Command(arguments = @Argument(
value = "biome",
tabCompleter = BiomeTabCompleter.class,
argumentParser = BiomeArgumentParser.class
))
public class BiomeInfoCommand implements CommandTemplate {
@ArgumentTarget("biome")
private TerraBiome biome;
@Override
public void execute(CommandSender sender) {
sender.sendMessage("Biome info for \"" + biome.getID() + "\".");
sender.sendMessage("Vanilla biome: " + biome.getVanillaBiomes());
if(biome instanceof UserDefinedBiome) {
BiomeTemplate bio = ((UserDefinedBiome) biome).getConfig();
if(bio.getExtended().size() == 0) {
sender.sendMessage("No Parent Biomes");
} else {
sender.sendMessage("------Parent Biomes-----");
bio.getExtended().forEach(id -> sender.sendMessage(" - " + id));
}
}
}
}

View File

@@ -1,77 +0,0 @@
package com.dfsek.terra.addons.biome.command.biome;
import java.util.Locale;
import com.dfsek.terra.addons.biome.command.biome.arg.BiomeArgumentParser;
import com.dfsek.terra.addons.biome.command.biome.tab.BiomeTabCompleter;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Argument;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.Switch;
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
import com.dfsek.terra.api.command.annotation.inject.SwitchTarget;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.command.arg.IntegerArgumentParser;
import com.dfsek.terra.api.entity.CommandSender;
import com.dfsek.terra.api.entity.Player;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.biome.TerraBiome;
@PlayerCommand
@WorldCommand
@Command(arguments = {
@Argument(
value = "biome",
tabCompleter = BiomeTabCompleter.class,
argumentParser = BiomeArgumentParser.class
),
@Argument(
value = "radius",
required = false,
defaultValue = "1000",
argumentParser = IntegerArgumentParser.class
)
}, switches = @Switch(
value = "teleport",
aliases = { "t", "tp" }
))
public class BiomeLocateCommand implements CommandTemplate {
@ArgumentTarget("radius")
private Integer radius;
@ArgumentTarget("biome")
private TerraBiome biome;
@SwitchTarget("teleport")
private boolean teleport;
@Inject
private Platform platform;
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
new Thread(new AsyncBiomeFinder(player.world().getBiomeProvider(), biome,
player.position().clone().multiply((1D / platform.getTerraConfig().getBiomeSearchResolution())),
player.world(), 0, radius, location -> {
if(location != null) {
sender.sendMessage(
String.format("The nearest %s is at [%d, ~, %d] (%.1f blocks away)", biome.getID().toLowerCase(Locale.ROOT),
location.getBlockX(), location.getBlockZ(),
location.add(new Vector3(0, player.position().getY(), 0)).distance(player.position())));
if(teleport) {
platform.runPossiblyUnsafeTask(
() -> player.position(new Vector3(location.getX(), player.position().getY(), location.getZ())));
}
} else sender.sendMessage("Unable to locate biome \"" + biome.getID() + "\"");
}, platform), "Biome Location Thread").start();
}
}

View File

@@ -1,20 +0,0 @@
package com.dfsek.terra.addons.biome.command.biome.arg;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.command.arg.ArgumentParser;
import com.dfsek.terra.api.entity.CommandSender;
import com.dfsek.terra.api.entity.Player;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class BiomeArgumentParser implements ArgumentParser<TerraBiome> {
@Inject
private Platform platform;
@Override
public TerraBiome parse(CommandSender sender, String arg) {
Player player = (Player) sender;
return player.world().getConfig().getRegistry(TerraBiome.class).get(arg);
}
}

View File

@@ -1,24 +0,0 @@
package com.dfsek.terra.addons.biome.command.biome.tab;
import java.util.List;
import java.util.stream.Collectors;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.command.tab.TabCompleter;
import com.dfsek.terra.api.entity.CommandSender;
import com.dfsek.terra.api.entity.Player;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome;
public class BiomeTabCompleter implements TabCompleter {
@Inject
private Platform platform;
@Override
public List<String> complete(CommandSender sender) {
Player player = (Player) sender;
return player.world().getConfig().getRegistry(TerraBiome.class).entries().stream().map(TerraBiome::getID).collect(
Collectors.toList());
}
}

View File

@@ -1,23 +0,0 @@
package com.dfsek.terra.addons.biome.holder;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolder {
private final Palette[] palettes;
private final int offset;
protected PaletteHolder(Palette[] palettes, int offset) {
this.palettes = palettes;
this.offset = offset;
}
public Palette getPalette(int y) {
int index = y + offset;
return index >= 0
? index < palettes.length
? palettes[index]
: palettes[palettes.length - 1]
: palettes[0];
}
}

View File

@@ -1,38 +0,0 @@
package com.dfsek.terra.addons.biome.holder;
import net.jafama.FastMath;
import java.util.Map;
import java.util.TreeMap;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderBuilder {
private final TreeMap<Integer, Palette> paletteMap = new TreeMap<>();
public PaletteHolderBuilder add(int y, Palette palette) {
paletteMap.put(y, palette);
return this;
}
public PaletteHolder build() {
int min = FastMath.min(paletteMap.keySet().stream().min(Integer::compareTo).orElse(0), 0);
int max = FastMath.max(paletteMap.keySet().stream().max(Integer::compareTo).orElse(255), 255);
Palette[] palettes = new Palette[paletteMap.lastKey() + 1 - min];
for(int y = min; y <= FastMath.max(paletteMap.lastKey(), max); y++) {
Palette d = null;
for(Map.Entry<Integer, Palette> e : paletteMap.entrySet()) {
if(e.getKey() >= y) {
d = e.getValue();
break;
}
}
if(d == null) throw new IllegalArgumentException("No palette for Y=" + y);
palettes[y - min] = d;
}
return new PaletteHolder(palettes, -min);
}
}

View File

@@ -1,27 +0,0 @@
package com.dfsek.terra.addons.biome.holder;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import java.lang.reflect.AnnotatedType;
import java.util.List;
import java.util.Map;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderLoader implements TypeLoader<PaletteHolder> {
@SuppressWarnings("unchecked")
@Override
public PaletteHolder load(AnnotatedType type, Object o, ConfigLoader configLoader) throws LoadException {
List<Map<String, Integer>> palette = (List<Map<String, Integer>>) o;
PaletteHolderBuilder builder = new PaletteHolderBuilder();
for(Map<String, Integer> layer : palette) {
for(Map.Entry<String, Integer> entry : layer.entrySet()) {
builder.add(entry.getValue(), configLoader.loadType(Palette.class, entry.getKey()));
}
}
return builder.build();
}
}

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];
}
}
}

View File

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

View File

@@ -1,56 +0,0 @@
package com.dfsek.terra.addons.feature.distributor;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.addons.feature.distributor.config.AndDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.NoiseDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.OrDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.PointSetDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.YesDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.util.Point;
import com.dfsek.terra.addons.feature.distributor.util.PointTemplate;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.feature.Distributor;
import com.dfsek.terra.api.util.reflection.TypeKey;
@Addon("config-distributors")
@Version("1.0.0")
@Author("Terra")
public class DistributorAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<Distributor>>> DISTRIBUTOR_TOKEN = new TypeKey<>() {
};
@Inject
private Platform platform;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<Distributor>>> distributorRegistry = event.getPack().getOrCreateRegistry(
DISTRIBUTOR_TOKEN);
distributorRegistry.register("NOISE", NoiseDistributorTemplate::new);
distributorRegistry.register("POINTS", PointSetDistributorTemplate::new);
distributorRegistry.register("AND", AndDistributorTemplate::new);
distributorRegistry.register("OR", OrDistributorTemplate::new);
distributorRegistry.register("YES", YesDistributorTemplate::new);
distributorRegistry.register("NO", NoiseDistributorTemplate::new);
event.getPack()
.applyLoader(Point.class, PointTemplate::new);
})
.failThrough();
}
}

View File

@@ -1,33 +0,0 @@
package com.dfsek.terra.addons.feature.distributor.config;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.List;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.structure.feature.Distributor;
public class AndDistributorTemplate implements ObjectTemplate<Distributor>, ValidatedConfigTemplate {
@Value("distributors")
private @Meta List<@Meta Distributor> distributors;
@Override
public Distributor get() {
Distributor current = distributors.remove(0);
while(!distributors.isEmpty()) {
current = current.and(distributors.remove(0));
}
return current;
}
@Override
public boolean validate() throws ValidationException {
if(distributors.isEmpty()) throw new ValidationException("AND Distributor must specify at least 1 distributor.");
return true;
}
}

View File

@@ -1,13 +0,0 @@
package com.dfsek.terra.addons.feature.distributor.config;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.structure.feature.Distributor;
public class NoDistributorTemplate implements ObjectTemplate<Distributor> {
@Override
public Distributor get() {
return Distributor.no();
}
}

View File

@@ -1,24 +0,0 @@
package com.dfsek.terra.addons.feature.distributor.config;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.addons.feature.distributor.distributors.NoiseDistributor;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.structure.feature.Distributor;
public class NoiseDistributorTemplate implements ObjectTemplate<Distributor> {
@Value("threshold")
@Default
private @Meta double threshold = 0;
@Value("distribution")
private @Meta NoiseSampler noise;
@Override
public Distributor get() {
return new NoiseDistributor(noise, threshold);
}
}

View File

@@ -1,33 +0,0 @@
package com.dfsek.terra.addons.feature.distributor.config;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.List;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.structure.feature.Distributor;
public class OrDistributorTemplate implements ObjectTemplate<Distributor>, ValidatedConfigTemplate {
@Value("distributors")
private @Meta List<@Meta Distributor> distributors;
@Override
public Distributor get() {
Distributor current = distributors.remove(0);
while(!distributors.isEmpty()) {
current = current.or(distributors.remove(0));
}
return current;
}
@Override
public boolean validate() throws ValidationException {
if(distributors.isEmpty()) throw new ValidationException("AND Distributor must specify at least 1 distributor.");
return true;
}
}

View File

@@ -1,22 +0,0 @@
package com.dfsek.terra.addons.feature.distributor.config;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.Set;
import com.dfsek.terra.addons.feature.distributor.distributors.PointSetDistributor;
import com.dfsek.terra.addons.feature.distributor.util.Point;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.structure.feature.Distributor;
public class PointSetDistributorTemplate implements ObjectTemplate<Distributor> {
@Value("points")
private @Meta Set<@Meta Point> points;
@Override
public Distributor get() {
return new PointSetDistributor(points);
}
}

View File

@@ -1,13 +0,0 @@
package com.dfsek.terra.addons.feature.distributor.config;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.structure.feature.Distributor;
public class YesDistributorTemplate implements ObjectTemplate<Distributor> {
@Override
public Distributor get() {
return Distributor.yes();
}
}

View File

@@ -1,21 +0,0 @@
package com.dfsek.terra.addons.feature.distributor.distributors;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.structure.feature.Distributor;
public class NoiseDistributor implements Distributor {
private final NoiseSampler sampler;
private final double threshold;
public NoiseDistributor(NoiseSampler sampler, double threshold) {
this.sampler = sampler;
this.threshold = threshold;
}
@Override
public boolean matches(int x, int z, long seed) {
return sampler.getNoiseSeeded(seed, x, z) > threshold;
}
}

View File

@@ -1,20 +0,0 @@
package com.dfsek.terra.addons.feature.distributor.distributors;
import java.util.Set;
import com.dfsek.terra.addons.feature.distributor.util.Point;
import com.dfsek.terra.api.structure.feature.Distributor;
public class PointSetDistributor implements Distributor {
private final Set<Point> points;
public PointSetDistributor(Set<Point> points) {
this.points = points;
}
@Override
public boolean matches(int x, int z, long seed) {
return points.contains(new Point(x, z));
}
}

Some files were not shown because too many files have changed in this diff Show More