mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
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:
63
.gitmodules
vendored
Normal file
63
.gitmodules
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
[submodule "common/addons/biome-provider-image"]
|
||||
path = common/addons/biome-provider-image
|
||||
url = https://github.com/PolyhedralDev/Terra-biome-provider-image
|
||||
[submodule "common/addons/biome-provider-pipeline"]
|
||||
path = common/addons/biome-provider-pipeline
|
||||
url = https://github.com/PolyhedralDev/Terra-biome-provider-pipeline
|
||||
[submodule "common/addons/biome-provider-single"]
|
||||
path = common/addons/biome-provider-single
|
||||
url = https://github.com/PolyhedralDev/Terra-biome-provider-single
|
||||
[submodule "common/addons/chunk-generator-noise-3d"]
|
||||
path = common/addons/chunk-generator-noise-3d
|
||||
url = https://github.com/PolyhedralDev/Terra-chunk-generator-noise-3d
|
||||
[submodule "common/addons/config-biome"]
|
||||
path = common/addons/config-biome
|
||||
url = https://github.com/PolyhedralDev/Terra-config-biome
|
||||
[submodule "common/addons/config-carver"]
|
||||
path = common/addons/config-carver
|
||||
url = https://github.com/PolyhedralDev/Terra-config-carver
|
||||
[submodule "common/addons/config-distributors"]
|
||||
path = common/addons/config-distributors
|
||||
url = https://github.com/PolyhedralDev/Terra-config-distributors
|
||||
[submodule "common/addons/config-feature"]
|
||||
path = common/addons/config-feature
|
||||
url = https://github.com/PolyhedralDev/Terra-config-feature
|
||||
[submodule "common/addons/config-flora"]
|
||||
path = common/addons/config-flora
|
||||
url = https://github.com/PolyhedralDev/Terra-config-flora
|
||||
[submodule "common/addons/config-locators"]
|
||||
path = common/addons/config-locators
|
||||
url = https://github.com/PolyhedralDev/Terra-config-locators
|
||||
[submodule "common/addons/config-noise-function"]
|
||||
path = common/addons/config-noise-function
|
||||
url = https://github.com/PolyhedralDev/Terra-config-noise-function
|
||||
[submodule "common/addons/config-ore"]
|
||||
path = common/addons/config-ore
|
||||
url = https://github.com/PolyhedralDev/Terra-config-ore
|
||||
[submodule "common/addons/config-palette"]
|
||||
path = common/addons/config-palette
|
||||
url = https://github.com/PolyhedralDev/Terra-config-palette
|
||||
[submodule "common/addons/config-structure"]
|
||||
path = common/addons/config-structure
|
||||
url = https://github.com/PolyhedralDev/Terra-config-structure
|
||||
[submodule "common/addons/generation-stage-feature"]
|
||||
path = common/addons/generation-stage-feature
|
||||
url = https://github.com/PolyhedralDev/Terra-generation-stage-feature
|
||||
[submodule "common/addons/generation-stage-structure"]
|
||||
path = common/addons/generation-stage-structure
|
||||
url = https://github.com/PolyhedralDev/Terra-generation-stage-structure
|
||||
[submodule "common/addons/language-yaml"]
|
||||
path = common/addons/language-yaml
|
||||
url = https://github.com/PolyhedralDev/Terra-language-yaml
|
||||
[submodule "common/addons/manifest-addon-loader"]
|
||||
path = common/addons/manifest-addon-loader
|
||||
url = https://github.com/PolyhedralDev/Terra-manifest-addon-loader
|
||||
[submodule "common/addons/structure-sponge-loader"]
|
||||
path = common/addons/structure-sponge-loader
|
||||
url = https://github.com/PolyhedralDev/Terra-structure-sponge-loader
|
||||
[submodule "common/addons/structure-terrascript-loader"]
|
||||
path = common/addons/structure-terrascript-loader
|
||||
url = https://github.com/PolyhedralDev/Terra-structure-terrascript-loader
|
||||
[submodule "common/addons/api-addon-loader"]
|
||||
path = common/addons/api-addon-loader
|
||||
url = https://github.com/PolyhedralDev/Terra-api-addon-loader
|
||||
26
README.md
26
README.md
@@ -1,15 +1,31 @@
|
||||
|
||||
<img align="left" width="64" height="64" src="https://raw.githubusercontent.com/wiki/PolyhedralDev/Terra/images/terra_logo.png" alt="Terra Logo">
|
||||
|
||||
# Terra
|
||||
|
||||
Terra is an incredibly powerful free & open-source data-driven,
|
||||
platform-agnostic world generator. It allows you to create a world exactly to
|
||||
your specifications, with no knowledge of Java required.
|
||||
Terra is a modern world generation modding platform, primarily for Minecraft.
|
||||
Terra allows complete customization of world generation with an advanced API,
|
||||
tightly integrated with a powerful configuration system.
|
||||
|
||||
Terra consists of several parts:
|
||||
|
||||
* A voxel world generation API with emphasis on configuration and extensibility
|
||||
* Several platform implementations, the layer between the API and the platform
|
||||
it's running on.
|
||||
* An addon loader, which allows interfacing with the Terra API in a
|
||||
platform-agnostic setting
|
||||
* Several "core addons," which implement the "default" configurations of Terra.
|
||||
These addons can be thought of as the config "standard library"
|
||||
|
||||
Terra currently officially supports the Fabric mod loader and the Bukkit API
|
||||
(Paper and friends). We welcome Pull Requests implementing additional platforms!
|
||||
|
||||
## Downloads:
|
||||
|
||||
* Paper+ servers (Paper, Tuinity, Purpur,
|
||||
etc): [SpigotMC](https://www.spigotmc.org/resources/85151/)
|
||||
* Fabric: [Modrinth](https://modrinth.com/mod/terra)
|
||||
/ [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
|
||||
* Paper+ servers (Paper, Tuinity, Purpur,
|
||||
etc): [SpigotMC](https://www.spigotmc.org/resources/85151/)
|
||||
|
||||
## Building and Running Terra
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.function.Predicate
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.gradle.kotlin.dsl.extra
|
||||
import kotlin.streams.asStream
|
||||
|
||||
|
||||
@@ -23,7 +24,8 @@ fun Project.addonDir(dir: File, task: Task) {
|
||||
project(":common:addons").subprojects.forEach { addonProject ->
|
||||
val jar = (addonProject.tasks.named("jar").get() as Jar)
|
||||
|
||||
val target = File(dir, jar.archiveFileName.get())
|
||||
val boot = if (addonProject.project.extra.has("bootstrap") && addonProject.project.extra.get("bootstrap") as Boolean) "bootstrap/" else ""
|
||||
val target = File(dir, boot + jar.archiveFileName.get())
|
||||
|
||||
val base = "${jar.archiveBaseName.get()}-${project.version}"
|
||||
|
||||
@@ -36,6 +38,6 @@ fun Project.addonDir(dir: File, task: Task) {
|
||||
|
||||
fun matchingAddons(dir: File, matcher: Predicate<File>): Set<File> {
|
||||
val matching = HashSet<File>()
|
||||
dir.walk().maxDepth(1).asStream().filter(matcher).forEach(matching::add)
|
||||
dir.walk().asStream().filter(matcher).forEach(matching::add)
|
||||
return matching
|
||||
}
|
||||
|
||||
1
common/addons/api-addon-loader
Submodule
1
common/addons/api-addon-loader
Submodule
Submodule common/addons/api-addon-loader added at ae2901876b
@@ -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.
|
||||
@@ -1,2 +0,0 @@
|
||||
dependencies {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
1
common/addons/biome-provider-pipeline
Submodule
1
common/addons/biome-provider-pipeline
Submodule
Submodule common/addons/biome-provider-pipeline added at daac9d4bb6
@@ -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.
|
||||
@@ -1,2 +0,0 @@
|
||||
dependencies {
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.pipeline.api;
|
||||
|
||||
public interface Stage {
|
||||
BiomeHolder apply(BiomeHolder in, long seed);
|
||||
|
||||
boolean isExpansion();
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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)];
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -1,2 +0,0 @@
|
||||
dependencies {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -1,2 +0,0 @@
|
||||
dependencies {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# config-biome
|
||||
|
||||
Registers the default configuration for Terra Biomes, `BIOME`.
|
||||
@@ -1,2 +0,0 @@
|
||||
dependencies {
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# config-carver
|
||||
|
||||
Registers the default configuration for Terra Carvers, `CARVER`.
|
||||
@@ -1,2 +0,0 @@
|
||||
dependencies {
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
dependencies {
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user