Merge pull request #236 from PolyhedralDev/dev/addonification

Addonification
This commit is contained in:
dfsek 2021-07-17 18:07:36 -07:00 committed by GitHub
commit 3c4c8c62b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
668 changed files with 7322 additions and 8062 deletions

View File

@ -10,4 +10,5 @@ repositories {
dependencies {
"implementation"("com.github.jengelman.gradle.plugins:shadow:+")
"implementation"("org.yaml:snakeyaml:1.27")
}

View File

@ -0,0 +1,41 @@
package com.dfsek.terra
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.jvm.tasks.Jar
import java.io.File
import java.util.function.Predicate
import kotlin.streams.asStream
/**
* Configures a directory where addons will be put.
*/
fun Project.addonDir(dir: File, task: Task) {
task.doFirst {
dir.parentFile.mkdirs()
matchingAddons(dir) {
it.name.startsWith("Terra-") // Assume everything that starts with Terra- is a core addon.
}.forEach {
println("Deleting old addon: " + it.absolutePath)
it.delete()
}
project(":common:addons").subprojects.forEach { addonProject ->
val jar = (addonProject.tasks.named("jar").get() as Jar)
val target = File(dir, jar.archiveFileName.get())
val base = "${jar.archiveBaseName.get()}-${project.version}"
println("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base")
jar.archiveFile.orNull?.asFile?.copyTo(target)
}
}
}
fun matchingAddons(dir: File, matcher: Predicate<File>): Set<File> {
val matching = HashSet<File>()
dir.walk().maxDepth(1).asStream().filter(matcher).forEach(matching::add)
return matching
}

View File

@ -4,12 +4,20 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getPlugin
import org.gradle.kotlin.dsl.named
import org.yaml.snakeyaml.DumperOptions
import org.yaml.snakeyaml.Yaml
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.FileWriter
import java.net.URL
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
fun Project.configureDistribution() {
apply(plugin = "java-library")
@ -26,7 +34,85 @@ fun Project.configureDistribution() {
downloadPack(netherPackUrl, project)
}
}
tasks["processResources"].dependsOn(downloadDefaultPacks)
val installAddons = tasks.create("installAddons") {
group = "terra"
project(":common:addons").subprojects.forEach {
it.afterEvaluate {
dependsOn(it.tasks.getByName("build")) // Depend on addon JARs
}
}
doFirst {
// The addons are copied into a JAR because of a ShadowJar bug
// which expands *all* JARs, even resource ones, into the fat JAR.
// To get around this, we copy all addon JARs into a *new* JAR,
// then, ShadowJar expands the newly created JAR, putting the original
// JARs where they should go.
//
// https://github.com/johnrengelman/shadow/issues/111
val dest = File(buildDir, "/resources/main/addons.jar")
dest.parentFile.mkdirs()
val zip = ZipOutputStream(FileOutputStream(dest))
project(":common:addons").subprojects.forEach { addonProject ->
val jar = (addonProject.tasks.named("jar").get() as Jar)
println("Packaging addon ${jar.archiveFileName.get()} to ${dest.absolutePath}.")
val entry = ZipEntry("addons/${jar.archiveFileName.get()}")
zip.putNextEntry(entry)
FileInputStream(jar.archiveFile.get().asFile).copyTo(zip)
zip.closeEntry()
}
zip.close()
}
}
val generateResourceManifest = tasks.create("generateResourceManifest") {
group = "terra"
dependsOn(downloadDefaultPacks)
dependsOn(installAddons)
doFirst {
val resources = HashMap<String, MutableList<String>>()
val packsDir = File("${project.buildDir}/resources/main/packs/")
packsDir.walkTopDown().forEach {
if (it.isDirectory || !it.name.endsWith(".zip")) return@forEach
resources.computeIfAbsent("packs") { ArrayList() }.add(it.name)
}
val langDir = File("${project(":common:implementation").buildDir}/resources/main/lang/")
langDir.walkTopDown().forEach {
if (it.isDirectory || !it.name.endsWith(".yml")) return@forEach
resources.computeIfAbsent("lang") { ArrayList() }.add(it.name)
}
project(":common:addons").subprojects.forEach { addonProject ->
val jar = (addonProject.tasks.named("jar").get() as Jar).archiveFileName.get()
resources.computeIfAbsent("addons") { ArrayList() }.add(jar)
}
val options = DumperOptions()
options.indent = 2
options.indentWithIndicator = true
options.indicatorIndent = 2
options.isPrettyFlow = true
options.defaultFlowStyle = DumperOptions.FlowStyle.BLOCK
options.defaultScalarStyle = DumperOptions.ScalarStyle.DOUBLE_QUOTED
val yaml = Yaml(options)
val manifest = File("${project.buildDir}/resources/main/resources.yml")
if (manifest.exists()) manifest.delete()
manifest.createNewFile()
yaml.dump(resources, FileWriter(manifest))
}
}
tasks["processResources"].dependsOn(generateResourceManifest)
tasks.named<ShadowJar>("shadowJar") {
// Tell shadow to download the packs
@ -45,7 +131,6 @@ fun Project.configureDistribution() {
relocate("org.javax.annotation", "com.dfsek.terra.lib.javax.annotation")
relocate("org.json", "com.dfsek.terra.lib.json")
relocate("org.yaml", "com.dfsek.terra.lib.yaml")
minimize()
}
convention.getPlugin<BasePluginConvention>().archivesBaseName = project.name

3
common/addons/README.md Normal file
View File

@ -0,0 +1,3 @@
# Core Addons
This directory contains the modularized "core addons" that implement Terra's default behavior.

View File

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

View File

@ -0,0 +1,45 @@
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
dependencies {
"shadedApi"(project(":common:api"))
"compileOnly"("com.google.guava:guava:30.0-jre")
"testImplementation"("com.google.guava:guava:30.0-jre")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}

View File

@ -1,5 +1,6 @@
package com.dfsek.terra.api.world.biome.provider;
package com.dfsek.terra.addons.biome.image;
import com.dfsek.terra.api.util.seeded.BiomeProviderBuilder;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import net.jafama.FastMath;
@ -10,7 +11,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class ImageBiomeProvider implements BiomeProvider, BiomeProvider.BiomeProviderBuilder { // This provider does not need a seed, so it is its own builder.
public class ImageBiomeProvider implements BiomeProvider, BiomeProviderBuilder { // This provider does not need a seed, so it is its own builder.
private final Map<Color, TerraBiome> colorBiomeMap = new HashMap<>();
private final BufferedImage image;
private final int resolution;

View File

@ -1,15 +1,14 @@
package com.dfsek.terra.config.loaders.config.biome.templates.provider;
package com.dfsek.terra.addons.biome.image;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.biome.provider.ImageBiomeProvider;
import com.dfsek.terra.config.builder.BiomeBuilder;
import java.awt.image.BufferedImage;
import java.util.stream.Collectors;
public class ImageProviderTemplate extends BiomeProviderTemplate {
public class ImageProviderTemplate /*extends BiomeProviderTemplate */ {
private final Registry<BiomeBuilder> biomes;
@Value("image.name")
private BufferedImage image;
@ -17,11 +16,13 @@ public class ImageProviderTemplate extends BiomeProviderTemplate {
@Value("image.align")
private ImageBiomeProvider.Align align;
private int resolution;
public ImageProviderTemplate(Registry<BiomeBuilder> set) {
this.biomes = set;
}
@Override
//@Override
public BiomeProvider build(long seed) {
return new ImageBiomeProvider(biomes.entries().stream().map(biomeBuilder -> biomeBuilder.apply(seed)).collect(Collectors.toSet()), image, resolution, align);
}

View File

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

View File

@ -0,0 +1,45 @@
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
dependencies {
"shadedApi"(project(":common:api"))
"compileOnly"("com.google.guava:guava:30.0-jre")
"testImplementation"("com.google.guava:guava:30.0-jre")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}

View File

@ -1,17 +1,17 @@
package com.dfsek.terra.api.world.biome.pipeline;
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.api.vector.Vector2;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeExpander;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeHolder;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeSource;
public class BiomeHolderImpl implements BiomeHolder {
private final Vector2 origin;
private final int width;
private TerraBiome[][] biomes;
private final int offset;
private TerraBiome[][] biomes;
public BiomeHolderImpl(int width, Vector2 origin) {
width += 4;

View File

@ -0,0 +1,56 @@
package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.terra.addons.biome.pipeline.config.BiomePipelineTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.BiomeProviderBuilderLoader;
import com.dfsek.terra.addons.biome.pipeline.config.NoiseSourceTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.SourceBuilderLoader;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageBuilderLoader;
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.stages.ExpanderStage;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.api.TerraPlugin;
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.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.util.seeded.BiomeProviderBuilder;
import com.dfsek.terra.api.util.seeded.SourceSeeded;
import java.lang.reflect.Type;
@Addon("biome-provider-pipeline")
@Author("Terra")
@Version("1.0.0")
public class BiomePipelineAddon extends TerraAddon implements EventListener {
@Inject
private TerraPlugin main;
@Override
public void initialize() {
main.getEventManager().registerListener(this, this);
}
public void onPackLoad(ConfigPackPreLoadEvent event) {
event.getPack().applyLoader(SourceSeeded.class, new SourceBuilderLoader())
.applyLoader(StageSeeded.class, new StageBuilderLoader())
.applyLoader(ExpanderStage.Type.class, (c, o, l) -> ExpanderStage.Type.valueOf((String) o))
.applyLoader(MutatorStage.Type.class, (c, o, l) -> MutatorStage.Type.valueOf((String) o))
.applyLoader(NoiseSourceTemplate.class, NoiseSourceTemplate::new)
.applyLoader(ReplaceMutatorTemplate.class, ReplaceMutatorTemplate::new)
.applyLoader(BorderMutatorTemplate.class, BorderMutatorTemplate::new)
.applyLoader(BorderListMutatorTemplate.class, BorderListMutatorTemplate::new)
.applyLoader(ReplaceListMutatorTemplate.class, ReplaceListMutatorTemplate::new)
.applyLoader(SmoothMutatorTemplate.class, SmoothMutatorTemplate::new)
.applyLoader(ExpanderStageTemplate.class, ExpanderStageTemplate::new)
.applyLoader((Type) BiomePipelineTemplate.class, () -> new BiomePipelineTemplate(main))
.applyLoader(BiomeProviderBuilder.class, new BiomeProviderBuilderLoader());
}
}

View File

@ -1,12 +1,11 @@
package com.dfsek.terra.api.world.biome.pipeline;
package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.api.util.seeded.StageSeeded;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.vector.Vector2;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeSource;
import com.dfsek.terra.api.world.biome.generation.pipeline.Stage;
import com.dfsek.terra.vector.Vector2Impl;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -31,7 +30,7 @@ public class BiomePipelineImpl {
* @return BiomeHolder containing biomes.
*/
public BiomeHolder getBiomes(int x, int z) {
BiomeHolder holder = new BiomeHolderImpl(init, new Vector2Impl(x * (init - 1), z * (init - 1)));
BiomeHolder holder = new BiomeHolderImpl(init, new Vector2(x * (init - 1), z * (init - 1)));
holder.fill(source);
for(Stage stage : stages) holder = stage.apply(holder);
return holder;
@ -43,7 +42,7 @@ public class BiomePipelineImpl {
public static final class BiomePipelineBuilder {
private final int init;
List<StageSeeded> stages = new GlueList<>();
List<StageSeeded> stages = new ArrayList<>();
private int expand;
public BiomePipelineBuilder(int init) {

View File

@ -0,0 +1,8 @@
package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.util.seeded.SeededBuilder;
@FunctionalInterface
public interface StageSeeded extends SeededBuilder<Stage> {
}

View File

@ -1,13 +1,11 @@
package com.dfsek.terra.api.world.biome.provider;
package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.vector.Vector2;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeHolder;
import com.dfsek.terra.api.world.biome.pipeline.BiomePipelineImpl;
import com.dfsek.terra.vector.Vector2Impl;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
@ -52,6 +50,6 @@ public class StandardBiomeProvider implements BiomeProvider {
int fdX = FastMath.floorDiv(x, pipeline.getSize());
int fdZ = FastMath.floorDiv(z, pipeline.getSize());
return holderCache.getUnchecked(new Vector2Impl(fdX, fdZ)).getBiome(x - fdX * pipeline.getSize(), z - fdZ * pipeline.getSize());
return holderCache.getUnchecked(new Vector2(fdX, fdZ)).getBiome(x - fdX * pipeline.getSize(), z - fdZ * pipeline.getSize());
}
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.api.world.biome.generation.pipeline;
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.api.world.biome.TerraBiome;

View File

@ -1,6 +1,7 @@
package com.dfsek.terra.api.world.biome.generation.pipeline;
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeSource;
public interface BiomeHolder {
BiomeHolder expand(BiomeExpander expander);

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.api.world.biome.generation.pipeline;
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.api.world.biome.TerraBiome;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.api.world.biome.generation.pipeline;
package com.dfsek.terra.addons.biome.pipeline.api;
public interface Stage {
boolean isExpansion();

View File

@ -1,13 +1,13 @@
package com.dfsek.terra.config.loaders.config.biome.templates.provider;
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.BiomePipelineImpl;
import com.dfsek.terra.addons.biome.pipeline.StageSeeded;
import com.dfsek.terra.addons.biome.pipeline.StandardBiomeProvider;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.util.seeded.SourceSeeded;
import com.dfsek.terra.api.util.seeded.StageSeeded;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.biome.pipeline.BiomePipelineImpl;
import com.dfsek.terra.api.world.biome.provider.StandardBiomeProvider;
import java.util.List;

View File

@ -0,0 +1,16 @@
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 com.dfsek.terra.api.util.seeded.BiomeProviderBuilder;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Type;
public class BiomeProviderBuilderLoader implements TypeLoader<BiomeProviderBuilder> {
@Override
public BiomeProviderBuilder load(AnnotatedType t, Object c, ConfigLoader loader) throws LoadException {
return loader.loadType(BiomePipelineTemplate.class, c); // TODO: actually implement this lol
}
}

View File

@ -0,0 +1,24 @@
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.util.seeded.BiomeProviderBuilder;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProviderBuilder>, BiomeProviderBuilder {
@Value("resolution")
@Default
protected int resolution = 1;
@Value("blend.noise")
@Default
protected NoiseSeeded blend = NoiseSeeded.zero(2);
@Value("blend.amplitude")
@Default
protected double blendAmp = 0d;
@Override
public BiomeProviderBuilder get() {
return this;
}
}

View File

@ -1,11 +1,11 @@
package com.dfsek.terra.config.loaders.config.biome.templates.source;
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.addons.biome.pipeline.source.RandomSource;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeSource;
import com.dfsek.terra.api.world.biome.pipeline.source.RandomSource;
import com.dfsek.terra.config.builder.BiomeBuilder;
public class NoiseSourceTemplate extends SourceTemplate {
@Value("noise")

View File

@ -1,25 +1,25 @@
package com.dfsek.terra.config.loaders.config.biome;
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 com.dfsek.terra.api.util.seeded.SourceSeeded;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeSource;
import com.dfsek.terra.config.loaders.config.biome.templates.source.NoiseSourceTemplate;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Type;
import java.util.Map;
@SuppressWarnings("unchecked")
public class SourceBuilderLoader implements TypeLoader<SourceSeeded> {
@Override
public SourceSeeded load(Type t, Object c, ConfigLoader loader) throws LoadException {
public SourceSeeded load(AnnotatedType t, Object c, ConfigLoader loader) throws LoadException {
Map<String, Object> source = (Map<String, Object>) c;
BiomeSource.Type type = loader.loadClass(BiomeSource.Type.class, source.get("type"));
BiomeSource.Type type = loader.loadType(BiomeSource.Type.class, source.get("type"));
if(type == BiomeSource.Type.NOISE) {
return loader.loadClass(NoiseSourceTemplate.class, source);
return loader.loadType(NoiseSourceTemplate.class, source);
}
throw new LoadException("No such loader type: " + type);
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.config.loaders.config.biome.templates.source;
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.util.seeded.SourceSeeded;

View File

@ -0,0 +1,59 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.addons.biome.pipeline.StageSeeded;
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.stages.ExpanderStage;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Type;
import java.util.Map;
@SuppressWarnings("unchecked")
public class StageBuilderLoader implements TypeLoader<StageSeeded> {
@Override
public StageSeeded load(AnnotatedType t, Object c, ConfigLoader loader) throws LoadException {
Map<String, Object> raw = (Map<String, Object>) c;
if(raw.size() != 1) throw new LoadException("Illegal stage map size: " + raw.size());
Map.Entry<String, Object> entry = null;
for(Map.Entry<String, Object> e : raw.entrySet()) {
entry = e;
}
Map<String, Object> mutator = (Map<String, Object>) entry.getValue();
if(entry.getKey().equals("expand")) {
ExpanderStage.Type stageType = loader.loadType(ExpanderStage.Type.class, mutator.get("type"));
if(stageType.equals(ExpanderStage.Type.FRACTAL)) {
return loader.loadType(ExpanderStageTemplate.class, mutator);
} else throw new LoadException("No such expander \"" + stageType + "\"");
} else if(entry.getKey().equals("mutate")) {
switch(loader.loadType(MutatorStage.Type.class, mutator.get("type"))) {
case SMOOTH:
return loader.loadType(SmoothMutatorTemplate.class, mutator);
case REPLACE:
return loader.loadType(ReplaceMutatorTemplate.class, mutator);
case REPLACE_LIST:
return loader.loadType(ReplaceListMutatorTemplate.class, mutator);
case BORDER:
return loader.loadType(BorderMutatorTemplate.class, mutator);
case BORDER_LIST:
return loader.loadType(BorderListMutatorTemplate.class, mutator);
default:
throw new LoadException("No such mutator type \"" + mutator.get("type"));
}
}
throw new LoadException("No such mutator \"" + entry.getKey() + "\"");
}
}

View File

@ -1,11 +1,11 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage;
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.StageSeeded;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.util.seeded.SeededBuilder;
import com.dfsek.terra.api.util.seeded.StageSeeded;
import com.dfsek.terra.api.world.biome.generation.pipeline.Stage;
public abstract class StageTemplate implements ObjectTemplate<SeededBuilder<Stage>>, StageSeeded {
@Value("noise")

View File

@ -0,0 +1,13 @@
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 apply(Long seed) {
return new ExpanderStage(new FractalExpander(noise.apply(seed)));
}
}

View File

@ -1,11 +1,11 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.mutator.BorderListMutator;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
import com.dfsek.terra.api.world.biome.pipeline.mutator.BorderListMutator;
import com.dfsek.terra.config.builder.BiomeBuilder;
import java.util.HashMap;
import java.util.Map;

View File

@ -1,10 +1,10 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
import com.dfsek.terra.api.world.biome.pipeline.mutator.BorderMutator;
import com.dfsek.terra.config.builder.BiomeBuilder;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.mutator.BorderMutator;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
@SuppressWarnings("unused")
public class BorderMutatorTemplate extends MutatorStageTemplate {

View File

@ -0,0 +1,15 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
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.stages.MutatorStage;
public abstract class MutatorStageTemplate extends StageTemplate {
public abstract BiomeMutator build(long seed);
@Override
public Stage apply(Long seed) {
return new MutatorStage(build(seed));
}
}

View File

@ -1,11 +1,11 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceListMutator;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
import com.dfsek.terra.api.world.biome.pipeline.mutator.ReplaceListMutator;
import com.dfsek.terra.config.builder.BiomeBuilder;
import java.util.HashMap;
import java.util.Map;

View File

@ -1,10 +1,10 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
import com.dfsek.terra.api.world.biome.pipeline.mutator.ReplaceMutator;
import com.dfsek.terra.config.builder.BiomeBuilder;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceMutator;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
@SuppressWarnings("unused")
public class ReplaceMutatorTemplate extends MutatorStageTemplate {

View File

@ -0,0 +1,11 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.mutator.SmoothMutator;
public class SmoothMutatorTemplate extends MutatorStageTemplate {
@Override
public BiomeMutator build(long seed) {
return new SmoothMutator(noise.apply(seed));
}
}

View File

@ -1,9 +1,9 @@
package com.dfsek.terra.api.world.biome.pipeline.expand;
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;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeExpander;
public class FractalExpander implements BiomeExpander {
private final NoiseSampler sampler;

View File

@ -1,9 +1,9 @@
package com.dfsek.terra.api.world.biome.pipeline.mutator;
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.ProbabilityCollection;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
import java.util.Map;

View File

@ -1,9 +1,9 @@
package com.dfsek.terra.api.world.biome.pipeline.mutator;
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.ProbabilityCollection;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
public class BorderMutator implements BiomeMutator {
private final String border;

View File

@ -1,9 +1,9 @@
package com.dfsek.terra.api.world.biome.pipeline.mutator;
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.ProbabilityCollection;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
import java.util.Map;

View File

@ -1,9 +1,9 @@
package com.dfsek.terra.api.world.biome.pipeline.mutator;
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.ProbabilityCollection;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
public class ReplaceMutator implements BiomeMutator {
private final String replaceableTag;

View File

@ -1,9 +1,9 @@
package com.dfsek.terra.api.world.biome.pipeline.mutator;
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.MathUtil;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
import java.util.Objects;

View File

@ -1,7 +1,7 @@
package com.dfsek.terra.api.world.biome.pipeline.source;
package com.dfsek.terra.addons.biome.pipeline.source;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeSource;

View File

@ -1,8 +1,8 @@
package com.dfsek.terra.api.world.biome.pipeline.stages;
package com.dfsek.terra.addons.biome.pipeline.stages;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeExpander;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeHolder;
import com.dfsek.terra.api.world.biome.generation.pipeline.Stage;
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;

View File

@ -1,8 +1,8 @@
package com.dfsek.terra.api.world.biome.pipeline.stages;
package com.dfsek.terra.addons.biome.pipeline.stages;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeHolder;
import com.dfsek.terra.api.world.biome.generation.pipeline.BiomeMutator;
import com.dfsek.terra.api.world.biome.generation.pipeline.Stage;
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;

View File

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

View File

@ -0,0 +1,45 @@
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
dependencies {
"shadedApi"(project(":common:api"))
"compileOnly"("com.google.guava:guava:30.0-jre")
"testImplementation"("com.google.guava:guava:30.0-jre")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}

View File

@ -1,9 +1,10 @@
package com.dfsek.terra.api.world.biome.provider;
package com.dfsek.terra.addons.biome.single;
import com.dfsek.terra.api.util.seeded.BiomeProviderBuilder;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class SingleBiomeProvider implements BiomeProvider, BiomeProvider.BiomeProviderBuilder {
public class SingleBiomeProvider implements BiomeProvider, BiomeProviderBuilder {
private final TerraBiome biome;
public SingleBiomeProvider(TerraBiome biome) {

View File

@ -0,0 +1,22 @@
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.util.seeded.BiomeBuilder;
import com.dfsek.terra.api.util.seeded.BiomeProviderBuilder;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class SingleBiomeProviderTemplate implements ObjectTemplate<BiomeProviderBuilder>, BiomeProviderBuilder {
@Value("biome")
private BiomeBuilder biome;
@Override
public BiomeProvider build(long seed) {
return new SingleBiomeProvider(biome.apply(seed));
}
@Override
public BiomeProviderBuilder get() {
return this;
}
}

View File

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

View File

@ -0,0 +1,45 @@
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
dependencies {
"shadedApi"(project(":common:api"))
"compileOnly"("com.google.guava:guava:30.0-jre")
"testImplementation"("com.google.guava:guava:30.0-jre")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}

View File

@ -0,0 +1,29 @@
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.world.generator.Palette;
public class BiomePaletteTemplate implements ObjectTemplate<PaletteInfo> {
@Value("palette")
private PaletteHolder palette;
@Value("slant")
@Default
private SlantHolder slant = null;
@Value("ocean.level")
private int seaLevel;
@Value("ocean.palette")
private Palette oceanPalette;
@Override
public PaletteInfo get() {
return new PaletteInfo(palette, slant, oceanPalette, seaLevel);
}
}

View File

@ -0,0 +1,44 @@
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.TerraPlugin;
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.EventListener;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
import com.dfsek.terra.api.world.generator.ChunkGeneratorProvider;
@Addon("chunk-generator-noise-3d")
@Author("Terra")
@Version("1.0.0")
public class NoiseChunkGenerator3DAddon extends TerraAddon implements EventListener {
@Inject
private TerraPlugin main;
@Override
public void initialize() {
main.getEventManager().registerListener(this, this);
}
public void onPackLoad(ConfigPackPreLoadEvent event) throws DuplicateEntryException {
event.getPack().getOrCreateRegistry(ChunkGeneratorProvider.class).register("NOISE_3D", pack -> new NoiseChunkGenerator3D(pack, main));
event.getPack().applyLoader(SlantHolder.class, new SlantHolderLoader())
.applyLoader(PaletteHolder.class, new PaletteHolderLoader());
}
public void onBiomeLoad(ConfigurationLoadEvent event) {
if(event.is(BiomeBuilder.class)) {
event.getLoadedObject(BiomeBuilder.class).getContext().put(event.load(new BiomePaletteTemplate()).get());
}
}
}

View File

@ -0,0 +1,22 @@
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.Generator;
import com.dfsek.terra.api.world.generator.Palette;
import com.dfsek.terra.api.world.generator.Sampler;
public final class PaletteUtil {
public static Palette getPalette(int x, int y, int z, Generator c, Sampler sampler, PaletteInfo paletteInfo) {
SlantHolder slant = paletteInfo.getSlantHolder();
if(slant != null) {
double slope = MathUtil.derivative(sampler, x, y, z);
if(slope > slant.getMinSlope()) {
return slant.getPalette(slope).getPalette(y);
}
}
return paletteInfo.getPaletteHolder().getPalette(y);
}
}

View File

@ -0,0 +1,189 @@
package com.dfsek.terra.addons.chunkgenerator.generation.generators;
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.TerraPlugin;
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.vector.Vector3;
import com.dfsek.terra.api.world.BiomeGrid;
import com.dfsek.terra.api.world.TerraWorld;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.Generator;
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.Palette;
import com.dfsek.terra.api.world.generator.Sampler;
import com.dfsek.terra.api.world.generator.TerraChunkGenerator;
import com.dfsek.terra.api.world.generator.TerraGenerationStage;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class NoiseChunkGenerator3D implements TerraChunkGenerator {
private final ConfigPack configPack;
private final TerraPlugin main;
private final List<TerraGenerationStage> generationStages = new ArrayList<>();
private final BlockState air;
public NoiseChunkGenerator3D(ConfigPack c, TerraPlugin main) {
this.configPack = c;
this.main = main;
this.air = main.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, TerraPlugin main) {
try(ProfileFrame ignore = main.getProfiler().profile("biomes")) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
BiomeProvider grid = main.getWorld(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);
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator(world).getBiomeNoise(), cx, 0, cz));
}
}
}
}
@Override
public ConfigPack getConfigPack() {
return configPack;
}
@Override
public TerraPlugin getMain() {
return main;
}
@Override
@SuppressWarnings({"try"})
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_3d")) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
Sampler sampler = tw.getConfig().getSamplerCache().getChunk(chunkX, chunkZ);
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);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
if(paletteInfo == null) {
main.logger().info("null palette: " + biome.getID());
}
Generator generator = biome.getGenerator(world);
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, generator, sampler, paletteInfo).get(paletteLevel, cx, y, cz);
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));
justSet = false;
paletteLevel = 0;
} else {
justSet = false;
paletteLevel = 0;
}
}
}
}
return chunk;
}
}
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;
}
@Override
public void generateBiomes(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, @NotNull BiomeGrid biome) {
biomes(world, chunkX, chunkZ, biome, main);
}
@Override
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler3D(chunkX, chunkZ, provider, world, elevationSmooth);
}
@Override
public List<TerraGenerationStage> getGenerationStages() {
return generationStages;
}
@Override
public BlockState getBlock(World world, int x, int y, int z) {
TerraWorld terraWorld = main.getWorld(world);
BiomeProvider provider = terraWorld.getBiomeProvider();
TerraBiome biome = provider.getBiome(x, z);
Sampler sampler = terraWorld.getConfig().getSamplerCache().get(x, z);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
Palette palette = PaletteUtil.getPalette(x, y, z, biome.getGenerator(world), 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);
} else if(y <= paletteInfo.getSeaLevel()) {
return paletteInfo.getOcean().get(paletteInfo.getSeaLevel() - y, x, y, z);
} else return air;
}
}

View File

@ -1,11 +1,11 @@
package com.dfsek.terra.world.generation.math.interpolation;
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.vector.Vector3Impl;
import com.dfsek.terra.api.world.generator.ChunkInterpolator;
import net.jafama.FastMath;
import java.util.HashMap;
@ -68,7 +68,7 @@ public class ChunkInterpolator2D implements ChunkInterpolator {
}
public double computeNoise(Generator generator, double x, double y, double z) {
return noiseGetter.apply(generator, new Vector3Impl(x, y, z));
return noiseGetter.apply(generator, new Vector3(x, y, z));
}
/**

View File

@ -1,11 +1,11 @@
package com.dfsek.terra.world.generation.math.interpolation;
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.vector.Vector3Impl;
import com.dfsek.terra.api.world.generator.ChunkInterpolator;
import net.jafama.FastMath;
import java.util.HashMap;
@ -82,14 +82,14 @@ public class ChunkInterpolator3D implements ChunkInterpolator {
}
}
public double computeNoise(Generator generator, double x, double y, double z) {
return noiseGetter.apply(generator, new Vector3Impl(x, y, z));
}
private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0);
}
public double computeNoise(Generator generator, double x, double y, double z) {
return noiseGetter.apply(generator, new Vector3(x, y, z));
}
/**
* Gets the noise at a pair of internal chunk coordinates.
*

View File

@ -1,9 +1,8 @@
package com.dfsek.terra.world.generation.math.interpolation;
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.world.generation.WorldGenerator;
public class ElevationInterpolator {
private final double[][] values = new double[18][18];
@ -12,12 +11,12 @@ public class ElevationInterpolator {
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
WorldGenerator[][] gens = new WorldGenerator[18 + 2 * smooth][18 + 2 * smooth];
Generator[][] gens = new Generator[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] = (WorldGenerator) provider.getBiome(xOrigin + x, zOrigin + z).getGenerator(world);
gens[x + 1 + smooth][z + 1 + smooth] = provider.getBiome(xOrigin + x, zOrigin + z).getGenerator(world);
}
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.world.generation.math.interpolation;
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
/**
* Class for bilinear interpolation of values arranged on a unit square.

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.world.generation.math.interpolation;
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
/**
* Class for bilinear interpolation of values arranged on a unit square.

View File

@ -1,10 +1,10 @@
package com.dfsek.terra.world.generation.math.samplers;
package com.dfsek.terra.addons.chunkgenerator.generation.math.samplers;
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.world.generator.Sampler;
import com.dfsek.terra.world.generation.math.interpolation.ChunkInterpolator3D;
import com.dfsek.terra.world.generation.math.interpolation.ElevationInterpolator;
import net.jafama.FastMath;
public class Sampler3D implements Sampler {

View File

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

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.api.world.palette.holder;
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.terra.api.world.generator.Palette;
import net.jafama.FastMath;
@ -14,7 +14,6 @@ public class PaletteHolderBuilder {
return this;
}
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
public PaletteHolder build() {
int min = FastMath.min(paletteMap.keySet().stream().min(Integer::compareTo).orElse(0), 0);

View File

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

View File

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

View File

@ -1,6 +1,5 @@
package com.dfsek.terra.api.world.palette.slant;
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import java.util.TreeMap;

View File

@ -1,12 +1,10 @@
package com.dfsek.terra.config.loaders.palette.slant;
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 com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import com.dfsek.terra.api.world.palette.slant.SlantHolder;
import java.lang.reflect.Type;
import java.lang.reflect.AnnotatedType;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@ -14,7 +12,7 @@ import java.util.TreeMap;
@SuppressWarnings("unchecked")
public class SlantHolderLoader implements TypeLoader<SlantHolder> {
@Override
public SlantHolder load(Type type, Object o, ConfigLoader configLoader) throws LoadException {
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;
@ -22,7 +20,7 @@ public class SlantHolderLoader implements TypeLoader<SlantHolder> {
for(Map<Object, Object> layer : layers) {
double threshold = ((Number) layer.get("threshold")).doubleValue();
if(threshold < minThreshold) minThreshold = threshold;
slantLayers.put(threshold, (PaletteHolder) configLoader.loadType(PaletteHolder.class, layer.get("palette")));
slantLayers.put(threshold, configLoader.loadType(PaletteHolder.class, layer.get("palette")));
}
return new SlantHolder(slantLayers, minThreshold);

View File

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

View File

@ -0,0 +1,45 @@
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
dependencies {
"shadedApi"(project(":common:api"))
"compileOnly"("com.google.guava:guava:30.0-jre")
"testImplementation"("com.google.guava:guava:30.0-jre")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}

View File

@ -0,0 +1,30 @@
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.TerraPlugin;
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.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.injection.annotations.Inject;
@Addon("config-biome")
@Author("Terra")
@Version("1.0.0")
public class BiomeConfigAddon extends TerraAddon implements EventListener {
@Inject
private TerraPlugin main;
@Override
public void initialize() {
main.getEventManager().registerListener(this, this);
}
public void onPackLoad(ConfigPackPreLoadEvent event) {
event.getPack().registerConfigType(new BiomeConfigType(event.getPack()), "BIOME", 5);
event.getPack().applyLoader(PaletteHolder.class, new PaletteHolderLoader());
}
}

View File

@ -0,0 +1,48 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.TerraPlugin;
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.seeded.BiomeBuilder;
import java.util.function.Supplier;
public class BiomeConfigType implements ConfigType<BiomeTemplate, BiomeBuilder> {
private final ConfigPack pack;
private final BiomeFactory factory;
public BiomeConfigType(ConfigPack pack) {
this.pack = pack;
this.factory = new BiomeFactory(pack);
}
@Override
public BiomeTemplate getTemplate(ConfigPack pack, TerraPlugin main) {
return new BiomeTemplate(pack, main);
}
@Override
public ConfigFactory<BiomeTemplate, BiomeBuilder> getFactory() {
return factory;
}
@Override
public Class<BiomeBuilder> getTypeClass() {
return BiomeBuilder.class;
}
@Override
public Supplier<OpenRegistry<BiomeBuilder>> registrySupplier() {
return () -> pack.getRegistryFactory().create(registry -> (TypeLoader<BiomeBuilder>) (t, c, loader) -> {
if(c.equals("SELF")) return null;
BiomeBuilder 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;
});
}
}

View File

@ -0,0 +1,19 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
public class BiomeFactory implements ConfigFactory<BiomeTemplate, BiomeBuilder> {
private final ConfigPack pack;
public BiomeFactory(ConfigPack pack) {
this.pack = pack;
}
@Override
public BiomeBuilder build(BiomeTemplate template, TerraPlugin main) {
return new UserDefinedBiomeBuilder(template);
}
}

View File

@ -0,0 +1,242 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
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 com.dfsek.terra.addons.biome.holder.PaletteHolder;
import com.dfsek.terra.api.TerraPlugin;
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.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.generator.Palette;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SuppressWarnings({"FieldMayBeFinal", "unused"})
public class BiomeTemplate implements AbstractableTemplate, ValidatedConfigTemplate {
private final ConfigPack pack;
@Value("id")
@Final
private String id;
@Value("extends")
@Final
@Default
private List<String> extended = Collections.emptyList();
@Value("variables")
@Default
private Map<String, Double> variables = new HashMap<>();
@Value("beta.carving.equation")
@Default
private NoiseSeeded carvingEquation = NoiseSeeded.zero(3);
@Value("vanilla")
private ProbabilityCollection<Biome> vanilla;
@Value("biome-noise")
@Default
private NoiseSeeded biomeNoise = NoiseSeeded.zero(2);
@Value("blend.distance")
@Default
private int blendDistance = 3;
@Value("blend.weight")
@Default
private double blendWeight = 1;
@Value("blend.step")
@Default
private int blendStep = 4;
@Value("noise")
private NoiseSeeded noiseEquation;
@Value("ocean.level")
@Default
private int seaLevel = 62;
@Value("elevation.equation")
@Default
private NoiseSeeded elevationEquation = NoiseSeeded.zero(2);
@Value("elevation.weight")
@Default
private double elevationWeight = 1;
@Value("slabs.enable")
@Default
private boolean doSlabs = false;
@Value("slabs.threshold")
@Default
private double slabThreshold = 0.0075D;
@Value("slabs.palettes")
@Default
private Map<BlockType, Palette> slabPalettes;
@Value("slabs.stair-palettes")
@Default
private Map<BlockType, Palette> stairPalettes;
@Value("interpolate-elevation")
@Default
private boolean interpolateElevation = true;
@Value("color")
@Final
@Default
private int color = 0;
@Value("tags")
@Default
private Set<String> tags = new HashSet<>();
@Value("colors")
@Default
private Map<String, Integer> colors = new HashMap<>(); // Plain ol' map, so platforms can decide what to do with colors (if anything).
public BiomeTemplate(ConfigPack pack, TerraPlugin main) {
this.pack = pack;
}
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 boolean interpolateElevation() {
return interpolateElevation;
}
public double getSlabThreshold() {
return slabThreshold;
}
public boolean doSlabs() {
return doSlabs;
}
public Map<BlockType, Palette> getSlabPalettes() {
return slabPalettes;
}
public Map<BlockType, Palette> getStairPalettes() {
return stairPalettes;
}
public NoiseSeeded getBiomeNoise() {
return biomeNoise;
}
public NoiseSeeded getElevationEquation() {
return elevationEquation;
}
public NoiseSeeded 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 NoiseSeeded getNoiseEquation() {
return noiseEquation;
}
public double getElevationWeight() {
return elevationWeight;
}
public int getBlendStep() {
return blendStep;
}
public Map<String, Double> getVariables() {
return variables;
}
@Override
public boolean validate() throws ValidationException {
color |= 0xff000000; // Alpha adjustment
Parser tester = new Parser();
Scope testScope = new Scope();
variables.forEach(testScope::create);
testScope.addInvocationVariable("x");
testScope.addInvocationVariable("y");
testScope.addInvocationVariable("z");
//pack.getTemplate().getNoiseBuilderMap().forEach((id, builder) -> tester.registerFunction(id, new BlankFunction(builder.getDimensions()))); // Register dummy functions
try {
noiseEquation.apply(0L);
} catch(Exception e) {
throw new ValidationException("Invalid noise sampler: ", e);
}
try {
carvingEquation.apply(0L);
} catch(Exception e) {
throw new ValidationException("Invalid carving sampler: ", e);
}
try {
elevationEquation.apply(0L);
} catch(Exception e) {
throw new ValidationException("Invalid elevation sampler: ", e);
}
return true;
}
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.api.math.paralithic;
package com.dfsek.terra.addons.biome;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;

View File

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

View File

@ -1,9 +1,11 @@
package com.dfsek.terra.api.world.biome;
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.world.generation.WorldGenerator;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.Set;
@ -11,21 +13,23 @@ import java.util.Set;
* Class representing a config-defined biome
*/
public class UserDefinedBiome implements TerraBiome {
private final WorldGenerator gen;
private final UserDefinedGenerator 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;
public UserDefinedBiome(ProbabilityCollection<Biome> vanilla, WorldGenerator gen, BiomeTemplate config) {
public UserDefinedBiome(ProbabilityCollection<Biome> vanilla, UserDefinedGenerator gen, BiomeTemplate config, Context context) {
this.vanilla = vanilla;
this.gen = gen;
this.id = config.getID();
this.config = config;
this.color = config.getColor();
this.tags = config.getTags();
this.context = context;
tags.add("BIOME:" + id);
}
@ -67,4 +71,9 @@ public class UserDefinedBiome implements TerraBiome {
public String toString() {
return "{BIOME:" + getID() + "}";
}
@Override
public Context getContext() {
return context;
}
}

View File

@ -0,0 +1,43 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
import com.dfsek.terra.api.world.biome.Biome;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class UserDefinedBiomeBuilder implements BiomeBuilder {
private final BiomeTemplate template;
private final Context context = new Context();
private final Map<Long, UserDefinedBiome> biomeMap = new ConcurrentHashMap<>();
public UserDefinedBiomeBuilder(BiomeTemplate template) {
this.template = template;
}
@Override
public UserDefinedBiome apply(Long seed) {
synchronized(biomeMap) {
return biomeMap.computeIfAbsent(seed,
s -> {
UserDefinedGenerator generator = new UserDefinedGenerator(template.getNoiseEquation().apply(seed), template.getElevationEquation().apply(seed), template.getCarvingEquation().apply(seed), template.getBiomeNoise().apply(seed), template.getElevationWeight(),
template.getBlendDistance(), template.getBlendStep(), template.getBlendWeight());
return new UserDefinedBiome(template.getVanilla(), generator, template, context);
}
);
}
}
@Override
public ProbabilityCollection<Biome> getVanillaBiomes() {
return template.getVanilla();
}
@Override
public Context getContext() {
return context;
}
}

View File

@ -1,16 +1,11 @@
package com.dfsek.terra.world.generation;
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.addons.biome.holder.PaletteHolder;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.api.world.generator.Palette;
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import com.dfsek.terra.api.world.palette.slant.SlantHolder;
import com.dfsek.terra.api.world.biome.PaletteSettings;
public class WorldGenerator implements Generator {
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final PaletteHolder palettes;
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final SlantHolder slantPalettes;
public class UserDefinedGenerator implements Generator {
private final NoiseSampler noise;
private final NoiseSampler elevation;
@ -22,9 +17,7 @@ public class WorldGenerator implements Generator {
private final int blendStep;
private final double blendWeight;
public WorldGenerator(PaletteHolder palettes, SlantHolder slantPalettes, NoiseSampler noise, NoiseSampler elevation, NoiseSampler carving, NoiseSampler biomeNoise, double elevationWeight, int blendDistance, int blendStep, double blendWeight) {
this.palettes = palettes;
this.slantPalettes = slantPalettes;
public UserDefinedGenerator(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;
@ -61,16 +54,6 @@ public class WorldGenerator implements Generator {
return blendWeight;
}
/**
* Gets the BlockPalette to generate the biome with.
*
* @return BlockPalette - The biome's palette.
*/
@Override
public Palette getPalette(int y) {
return palettes.getPalette(y);
}
@Override
public NoiseSampler getBiomeNoise() {
return biomeNoise;

View File

@ -1,27 +1,31 @@
package com.dfsek.terra.api.world.locate;
package com.dfsek.terra.addons.biome.command.biome;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.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;
import com.dfsek.terra.vector.Vector3Impl;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public abstract class AsyncFeatureFinder<T> implements Runnable {
/**
* Runnable that locates a biome asynchronously
*/
public class AsyncBiomeFinder implements Runnable {
protected final BiomeProvider provider;
protected final T target;
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 TerraPlugin main;
private final Consumer<Vector3> callback;
protected int searchSize = 1;
protected final TerraPlugin main;
public AsyncFeatureFinder(BiomeProvider provider, T target, @NotNull Vector3 origin, World world, int startRadius, int maxRadius, Consumer<Vector3> callback, TerraPlugin main) {
public AsyncBiomeFinder(BiomeProvider provider, TerraBiome target, @NotNull Vector3 origin, World world, int startRadius, int maxRadius, Consumer<Vector3> callback, TerraPlugin main) {
this.provider = provider;
this.target = target;
this.main = main;
@ -33,6 +37,22 @@ public abstract class AsyncFeatureFinder<T> implements Runnable {
this.callback = callback;
}
/**
* 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 = main.getTerraConfig().getBiomeSearchResolution();
return getProvider().getBiome(x * res, z * res).equals(target);
}
public Vector3 finalizeVector(Vector3 orig) {
return orig.multiply(main.getTerraConfig().getBiomeSearchResolution());
}
@Override
public void run() {
int x = centerX;
@ -66,16 +86,11 @@ public abstract class AsyncFeatureFinder<T> implements Runnable {
run++;
toggle = !toggle;
}
Vector3 finalSpawn = found ? finalizeVector(new Vector3Impl(x, 0, z)) : null;
Vector3 finalSpawn = found ? finalizeVector(new Vector3(x, 0, z)) : null;
callback.accept(finalSpawn);
}
public abstract Vector3 finalizeVector(Vector3 orig);
public abstract boolean isValid(int x, int z, T target);
public T getTarget() {
public TerraBiome getTarget() {
return target;
}

View File

@ -1,5 +1,6 @@
package com.dfsek.terra.commands.biome;
package com.dfsek.terra.addons.biome.command.biome;
import com.dfsek.terra.addons.biome.UserDefinedBiome;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
@ -9,9 +10,7 @@ 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.injection.annotations.Inject;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.config.lang.LangUtil;
@Command(
subcommands = {
@ -40,6 +39,6 @@ public class BiomeCommand implements CommandTemplate {
BiomeProvider provider = main.getWorld(player.world()).getBiomeProvider();
UserDefinedBiome biome = (UserDefinedBiome) provider.getBiome(player.position());
LangUtil.send("command.biome.in", sender, biome.getID());
sender.sendMessage("You are standing in " + biome.getID());
}
}

View File

@ -1,16 +1,16 @@
package com.dfsek.terra.commands.biome;
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.structure.ConfiguredStructure;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.commands.biome.arg.BiomeArgumentParser;
import com.dfsek.terra.commands.biome.tab.BiomeTabCompleter;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.world.population.items.TerraStructure;
import java.util.List;
@ -41,17 +41,6 @@ public class BiomeInfoCommand implements CommandTemplate {
sender.sendMessage("------Parent Biomes-----");
bio.getExtended().forEach(id -> sender.sendMessage(" - " + id));
}
List<TerraStructure> structureConfigs = bio.getStructures();
if(structureConfigs.size() == 0) {
sender.sendMessage("No Structures");
} else {
sender.sendMessage("-------Structures-------");
for(TerraStructure c : structureConfigs) {
sender.sendMessage(" - " + c.getTemplate().getID());
}
}
}
}
}

View File

@ -1,5 +1,7 @@
package com.dfsek.terra.commands.biome;
package com.dfsek.terra.addons.biome.command.biome;
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.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Argument;
@ -13,12 +15,8 @@ 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.injection.annotations.Inject;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.locate.AsyncBiomeFinder;
import com.dfsek.terra.commands.biome.arg.BiomeArgumentParser;
import com.dfsek.terra.commands.biome.tab.BiomeTabCompleter;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.vector.Vector3Impl;
import java.util.Locale;
@ -66,11 +64,11 @@ public class BiomeLocateCommand implements CommandTemplate {
new Thread(new AsyncBiomeFinder(main.getWorld(player.world()).getBiomeProvider(), biome, player.position().clone().multiply((1D / main.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 Vector3Impl(0, player.position().getY(), 0)).distance(player.position())));
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) {
main.runPossiblyUnsafeTask(() -> player.position(new Vector3Impl(location.getX(), player.position().getY(), location.getZ())));
main.runPossiblyUnsafeTask(() -> player.position(new Vector3(location.getX(), player.position().getY(), location.getZ())));
}
} else LangUtil.send("command.biome.unable-to-locate", sender);
} else sender.sendMessage("Unable to locate biome \"" + biome.getID() + "\"");
}, main), "Biome Location Thread").start();
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.commands.biome.arg;
package com.dfsek.terra.addons.biome.command.biome.arg;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.arg.ArgumentParser;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.commands.biome.tab;
package com.dfsek.terra.addons.biome.command.biome.tab;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.tab.TabCompleter;

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.api.world.palette.holder;
package com.dfsek.terra.addons.biome.holder;
import com.dfsek.terra.api.world.generator.Palette;

View File

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

View File

@ -1,25 +1,24 @@
package com.dfsek.terra.config.loaders.palette;
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 com.dfsek.terra.api.world.generator.Palette;
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import com.dfsek.terra.api.world.palette.holder.PaletteHolderBuilder;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
@SuppressWarnings("unchecked")
public class PaletteHolderLoader implements TypeLoader<PaletteHolder> {
@SuppressWarnings("unchecked")
@Override
public PaletteHolder load(Type type, Object o, ConfigLoader configLoader) throws LoadException {
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(), (Palette) configLoader.loadType(Palette.class, entry.getKey()));
builder.add(entry.getValue(), configLoader.loadType(Palette.class, entry.getKey()));
}
}
return builder.build();

View File

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

View File

@ -0,0 +1,45 @@
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
dependencies {
"shadedApi"(project(":common:api"))
"compileOnly"("com.google.guava:guava:30.0-jre")
"testImplementation"("com.google.guava:guava:30.0-jre")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}

View File

@ -1,21 +1,19 @@
package com.dfsek.terra.carving;
package com.dfsek.terra.addons.carver;
import com.dfsek.terra.addons.carver.carving.Worm;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.util.PopulationUtil;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.carving.Worm;
import com.dfsek.terra.vector.Vector3Impl;
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;
@ -34,17 +32,20 @@ public class CarverCache {
int chunkX = (int) (key >> 32);
int chunkZ = (int) key.longValue();
BiomeProvider provider = main.getWorld(w).getBiomeProvider();
if(CarverCache.this.carver.isChunkCarved(w, chunkX, chunkZ, new FastRandom(PopulationUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed() + CarverCache.this.carver.hashCode())))) {
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 FastRandom(seed);
Worm carving = CarverCache.this.carver.getWorm(seed, new Vector3Impl((chunkX << 4) + r.nextInt(16), CarverCache.this.carver.getConfig().getHeight().get(r), (chunkZ << 4) + r.nextInt(16)));
List<Worm.WormPoint> points = new GlueList<>();
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());
/*
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;

View File

@ -1,20 +1,20 @@
package com.dfsek.terra.config.factories;
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 com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.pack.ConfigPackImpl;
import com.dfsek.terra.config.templates.CarverTemplate;
import java.util.Arrays;
import java.util.List;
public class CarverFactory implements ConfigFactory<CarverTemplate, UserDefinedCarver> {
private final ConfigPackImpl pack;
private final ConfigPack pack;
public CarverFactory(ConfigPackImpl pack) {
public CarverFactory(ConfigPack pack) {
this.pack = pack;
}
@ -26,7 +26,7 @@ public class CarverFactory implements ConfigFactory<CarverTemplate, UserDefinedC
long hash = MathUtil.hashToLong(config.getID());
UserDefinedCarver carver;
try {
carver = new UserDefinedCarver(config.getHeight(), config.getLength(), start, mutate, radius, pack.getVarScope(), hash, config.getCutTop(), config.getCutBottom(), config, main, pack.getTemplate().getNoiseBuilderMap(), pack.getTemplate().getFunctions());
carver = new UserDefinedCarver(config.getHeight(), config.getLength(), start, mutate, radius, new Scope(), hash, config.getCutTop(), config.getCutBottom(), config, main);
} catch(ParseException e) {
throw new LoadException("Unable to parse radius equations", e);
}

View File

@ -1,9 +1,9 @@
package com.dfsek.terra.carving;
package com.dfsek.terra.addons.carver;
import com.dfsek.terra.api.block.BlockData;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.util.collection.MaterialSet;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import net.jafama.FastMath;
import java.util.Map;
@ -13,8 +13,8 @@ import java.util.TreeMap;
public class CarverPalette {
private final boolean blacklist;
private final MaterialSet replace;
private final TreeMap<Integer, ProbabilityCollection<BlockData>> map = new TreeMap<>();
private ProbabilityCollection<BlockData>[] layers;
private final TreeMap<Integer, ProbabilityCollection<BlockState>> map = new TreeMap<>();
private ProbabilityCollection<BlockState>[] layers;
private int offset = 0;
public CarverPalette(MaterialSet replaceable, boolean blacklist) {
@ -22,12 +22,12 @@ public class CarverPalette {
this.replace = replaceable;
}
public CarverPalette add(ProbabilityCollection<BlockData> collection, int y) {
public CarverPalette add(ProbabilityCollection<BlockState> collection, int y) {
map.put(y, collection);
return this;
}
public ProbabilityCollection<BlockData> get(int y) {
public ProbabilityCollection<BlockState> get(int y) {
int index = y + offset;
return index >= 0
? index < layers.length
@ -49,8 +49,8 @@ public class CarverPalette {
layers = new ProbabilityCollection[map.lastKey() + 1 - min];
for(int y = min; y <= FastMath.max(map.lastKey(), max); y++) {
ProbabilityCollection<BlockData> d = null;
for(Map.Entry<Integer, ProbabilityCollection<BlockData>> e : map.entrySet()) {
ProbabilityCollection<BlockState> d = null;
for(Map.Entry<Integer, ProbabilityCollection<BlockState>> e : map.entrySet()) {
if(e.getKey() >= y) {
d = e.getValue();
break;

View File

@ -1,114 +1,94 @@
package com.dfsek.terra.config.templates;
package com.dfsek.terra.addons.carver;
import com.dfsek.tectonic.annotations.Abstractable;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Final;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.math.range.ConstantRange;
import com.dfsek.terra.api.config.AbstractableTemplate;
import com.dfsek.terra.api.util.ConstantRange;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.carving.CarverPalette;
import com.dfsek.terra.api.util.collection.MaterialSet;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
public class CarverTemplate extends AbstractableTemplate {
public class CarverTemplate implements AbstractableTemplate {
@Value("id")
@Final
private String id;
@Value("step")
@Abstractable
@Default
private int step = 2;
@Value("recalculate-magnitude")
@Default
@Abstractable
private double recaclulateMagnitude = 4;
@Value("recalculate-direction")
@Abstractable
@Default
private Range recalc = new ConstantRange(8, 10);
@Value("length")
@Abstractable
private Range length;
@Value("start.x")
@Abstractable
private double startX;
@Value("start.y")
@Abstractable
private double startY;
@Value("start.z")
@Abstractable
private double startZ;
@Value("start.radius.x")
@Abstractable
private String radMX;
@Value("start.radius.y")
@Abstractable
private String radMY;
@Value("start.radius.z")
@Abstractable
private String radMZ;
@Value("start.height")
@Abstractable
private Range height;
@Value("cut.bottom")
@Abstractable
@Default
private int cutBottom = 0;
@Value("cut.top")
@Abstractable
@Default
private int cutTop = 0;
@Value("mutate.x")
@Abstractable
private double mutateX;
@Value("mutate.y")
@Abstractable
private double mutateY;
@Value("mutate.z")
@Abstractable
private double mutateZ;
@Value("palette.top")
@Abstractable
private CarverPalette top;
@Value("palette.bottom")
@Abstractable
private CarverPalette bottom;
@Value("palette.outer")
@Abstractable
private CarverPalette outer;
@Value("palette.inner")
@Abstractable
private CarverPalette inner;
@Value("shift")
@Abstractable
@Default
private Map<BlockType, MaterialSet> shift = new HashMap<>();
@Value("update")
@Abstractable
@Default
private MaterialSet update = new MaterialSet();

View File

@ -1,8 +1,8 @@
package com.dfsek.terra.world.population;
package com.dfsek.terra.addons.carver;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.block.BlockData;
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.handle.WorldHandle;
import com.dfsek.terra.api.profiler.ProfileFrame;
@ -12,17 +12,15 @@ import com.dfsek.terra.api.world.Chunk;
import com.dfsek.terra.api.world.TerraWorld;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.generator.Chunkified;
import com.dfsek.terra.api.world.generator.TerraBlockPopulator;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.templates.CarverTemplate;
import com.dfsek.terra.api.world.generator.TerraGenerationStage;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class CavePopulator implements TerraBlockPopulator, Chunkified {
private static final Map<BlockType, BlockData> shiftStorage = new HashMap<>(); // Persist BlockData created for shifts, to avoid re-calculating each time.
public class CavePopulator implements TerraGenerationStage, Chunkified {
private static final Map<BlockType, BlockState> shiftStorage = new HashMap<>(); // Persist BlockData created for shifts, to avoid re-calculating each time.
private final TerraPlugin main;
public CavePopulator(TerraPlugin main) {
@ -34,19 +32,17 @@ public class CavePopulator implements TerraBlockPopulator, Chunkified {
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
WorldHandle handle = main.getWorldHandle();
BlockData AIR = handle.createBlockData("minecraft:air");
try(ProfileFrame ignore = main.getProfiler().profile("carving")) {
Random random = PopulationUtil.getRandom(chunk);
if(!tw.isSafe()) return;
WorldConfig config = tw.getConfig();
if(config.disableCarving()) return;
for(UserDefinedCarver c : config.getRegistry(UserDefinedCarver.class).entries()) {
CarverTemplate template = c.getConfig();
Map<Vector3, BlockData> shiftCandidate = new HashMap<>();
Map<Vector3, BlockState> shiftCandidate = new HashMap<>();
c.carve(chunk.getX(), chunk.getZ(), world, (v, type) -> {
try(ProfileFrame ignored = main.getProfiler().profile("carving:" + c.getConfig().getID())) {
BlockData m = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
BlockState m = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
BlockType re = m.getBlockType();
switch(type) {
case CENTER:
@ -76,10 +72,10 @@ public class CavePopulator implements TerraBlockPopulator, Chunkified {
}
}
});
for(Map.Entry<Vector3, BlockData> entry : shiftCandidate.entrySet()) {
for(Map.Entry<Vector3, BlockState> entry : shiftCandidate.entrySet()) {
Vector3 l = entry.getKey();
Vector3 mut = l.clone();
BlockData orig = chunk.getBlock(l.getBlockX(), l.getBlockY(), l.getBlockZ());
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 {

View File

@ -1,26 +1,16 @@
package com.dfsek.terra.carving;
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 com.dfsek.terra.addons.carver.carving.Carver;
import com.dfsek.terra.addons.carver.carving.Worm;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.paralithic.defined.UserDefinedFunction;
import com.dfsek.terra.api.math.paralithic.noise.NoiseFunction2;
import com.dfsek.terra.api.math.paralithic.noise.NoiseFunction3;
import com.dfsek.terra.api.math.range.ConstantRange;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.util.ConstantRange;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.carving.Carver;
import com.dfsek.terra.api.world.carving.Worm;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.config.templates.CarverTemplate;
import com.dfsek.terra.vector.Vector3Impl;
import net.jafama.FastMath;
import java.util.List;
@ -47,7 +37,7 @@ public class UserDefinedCarver extends Carver {
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, TerraPlugin main, Map<String, NoiseSeeded> functions, Map<String, FunctionTemplate> definedFunctions) throws ParseException {
public UserDefinedCarver(Range height, Range length, double[] start, double[] mutate, List<String> radii, Scope parent, long hash, int topCut, int bottomCut, CarverTemplate config, TerraPlugin main) throws ParseException {
super(height.getMin(), height.getMax());
this.length = length;
this.start = start;
@ -60,21 +50,6 @@ public class UserDefinedCarver extends Carver {
Parser p = new Parser();
functions.forEach((id, noise) -> {
switch(noise.getDimensions()) {
case 2:
p.registerFunction(id, new NoiseFunction2(noise.apply(hash)));
break;
case 3:
p.registerFunction(id, new NoiseFunction3(noise.apply(hash)));
break;
}
});
for(Map.Entry<String, FunctionTemplate> entry : definedFunctions.entrySet()) {
p.registerFunction(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue(), p, parent));
}
Scope s = new Scope().withParent(parent);
@ -95,7 +70,7 @@ public class UserDefinedCarver extends Carver {
@Override
public Worm getWorm(long l, Vector3 vector) {
Random r = new FastRandom(l + hash);
Random r = new Random(l + hash);
return new UserDefinedWorm(length.get(r) / 2, r, vector, topCut, bottomCut, l);
}
@ -131,10 +106,10 @@ public class UserDefinedCarver extends Carver {
@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();
/*BiomeTemplate conf = ((UserDefinedBiome) main.getWorld(w).getBiomeProvider().getBiome((chunkX << 4) + 8, (chunkZ << 4) + 8)).getConfig();
if(conf.getCarvers().get(this) != null) {
return new FastRandom(random.nextLong() + hash).nextInt(100) < conf.getCarvers().get(this);
}
return new Random(random.nextLong() + hash).nextInt(100) < conf.getCarvers().get(this);
}*/
return false;
}
@ -145,10 +120,10 @@ public class UserDefinedCarver extends Carver {
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];
private final long seed;
public UserDefinedWorm(int length, Random r, Vector3 origin, int topCut, int bottomCut, long seed) {
super(length, r, origin);
@ -156,7 +131,7 @@ public class UserDefinedCarver extends Carver {
this.seed = seed;
super.setTopCut(topCut);
super.setBottomCut(bottomCut);
direction = new Vector3Impl((r.nextDouble() - 0.5D) * start[0], (r.nextDouble() - 0.5D) * start[1], (r.nextDouble() - 0.5D) * start[2]).normalize().multiply(step);
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))});
}

View File

@ -1,4 +1,4 @@
package com.dfsek.terra.api.world.carving;
package com.dfsek.terra.addons.carver.carving;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;

View File

@ -1,8 +1,7 @@
package com.dfsek.terra.api.world.carving;
package com.dfsek.terra.addons.carver.carving;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.vector.Vector3Impl;
import net.jafama.FastMath;
import java.util.Random;
@ -98,12 +97,12 @@ public abstract class Worm {
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 Vector3Impl(x, y, z));
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 Vector3Impl(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ), Carver.CarvingType.CENTER);
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) {
@ -111,7 +110,7 @@ public abstract class Worm {
} else if(y >= yRad + 1 - topCut) {
type = Carver.CarvingType.TOP;
}
consumer.accept(new Vector3Impl(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ), type);
consumer.accept(new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ), type);
}
}
}

View File

@ -0,0 +1,3 @@
# config-flora
Registers the default configuration for Terra Flora, `FLORA`.

View File

@ -0,0 +1,45 @@
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
dependencies {
"shadedApi"(project(":common:api"))
"compileOnly"("com.google.guava:guava:30.0-jre")
"testImplementation"("com.google.guava:guava:30.0-jre")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}

View File

@ -0,0 +1,31 @@
package com.dfsek.terra.addons.flora;
import com.dfsek.terra.addons.flora.config.BlockLayerTemplate;
import com.dfsek.terra.addons.flora.flora.gen.BlockLayer;
import com.dfsek.terra.api.TerraPlugin;
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.EventListener;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
@Addon("config-flora")
@Author("Terra")
@Version("0.1.0")
public class FloraAddon extends TerraAddon implements EventListener {
@Inject
private TerraPlugin main;
@Override
public void initialize() {
main.getEventManager().registerListener(this, this);
}
public void onPackLoad(ConfigPackPreLoadEvent event) throws DuplicateEntryException {
event.getPack().registerConfigType(new FloraConfigType(event.getPack()), "FLORA", 2);
event.getPack().applyLoader(BlockLayer.class, BlockLayerTemplate::new);
}
}

View File

@ -0,0 +1,39 @@
package com.dfsek.terra.addons.flora;
import com.dfsek.terra.api.TerraPlugin;
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.world.Flora;
import java.util.function.Supplier;
public class FloraConfigType implements ConfigType<FloraTemplate, Flora> {
private final FloraFactory factory = new FloraFactory();
private final ConfigPack pack;
public FloraConfigType(ConfigPack pack) {
this.pack = pack;
}
@Override
public FloraTemplate getTemplate(ConfigPack pack, TerraPlugin main) {
return new FloraTemplate();
}
@Override
public ConfigFactory<FloraTemplate, Flora> getFactory() {
return factory;
}
@Override
public Class<Flora> getTypeClass() {
return Flora.class;
}
@Override
public Supplier<OpenRegistry<Flora>> registrySupplier() {
return pack.getRegistryFactory()::create;
}
}

View File

@ -0,0 +1,13 @@
package com.dfsek.terra.addons.flora;
import com.dfsek.terra.addons.flora.flora.gen.TerraFlora;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.world.Flora;
public class FloraFactory implements ConfigFactory<FloraTemplate, Flora> {
@Override
public TerraFlora build(FloraTemplate config, TerraPlugin main) {
return new TerraFlora(config.getLayers(), config.doPhysics(), config.isCeiling(), config.getIrrigable(), config.getSpawnable(), config.getReplaceable(), config.getRotatable(), config.getMaxPlacements(), config.getSearch(), config.isSpawnBlacklist(), config.getIrrigableOffset(), main, config.getNoiseDistribution().apply(2403L));
}
}

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