Compare commits

...

74 Commits

Author SHA1 Message Date
dfsek e887a9f1a1 remove additional events, make Event extend Monad 2022-09-02 22:51:57 -07:00
dfsek 3077178cd2 Merge remote-tracking branch 'origin/ver/7.0.0' into dev/pure 2022-08-28 21:39:36 -07:00
dfsek a0738a3b32 Merge pull request #365 from Astrashh/dev/linear-map
Linear map normalizer
2022-08-24 11:55:08 -07:00
Zoë ee3be35359 Merge pull request #368 from duplexsystem/ver/7.0.0
git is being bad so I'm just pring
2022-08-23 12:58:36 -05:00
Zoë cb6dbe3ec9 fix format 2022-08-23 12:55:18 -05:00
Zoë c40fc4b844 Merge pull request #367 from duplexsystem/ver/7.0.0
fixes
2022-08-22 23:18:32 -05:00
Zoë 2e8bc8d561 sub structures use pos as origin 2022-08-22 22:55:28 -05:00
Zoë 08df8b1652 some fixes 2022-08-22 22:41:26 -05:00
Astrash 3dcfeb987f Add meta annotations 2022-08-23 11:06:32 +10:00
Astrash f0efb4c931 Add default 'from' values for linear map template 2022-08-23 11:02:17 +10:00
Astrash 82596a8ffd Implement linear map normalizer 2022-08-23 11:02:17 +10:00
dfsek 9aa124605c Merge pull request #364 from duplexsystem/ver/7.0.0
oop 2
2022-08-22 17:28:13 -07:00
Zoë ec7f0dacfa oop 2 2022-08-21 21:07:16 -05:00
dfsek 507895636e Merge pull request #363 from duplexsystem/ver/7.0.0
oops
2022-08-21 19:06:42 -07:00
Zoë 32ddc287f7 oops 2022-08-21 20:48:21 -05:00
dfsek 91766599c6 Merge remote-tracking branch 'origin/ver/7.0.0' into dev/pure
# Conflicts:
#	common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineAddon.java
#	common/addons/config-distributors/src/main/java/com/dfsek/terra/addons/feature/distributor/DistributorAddon.java
#	common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/LocatorAddon.java
2022-08-21 13:40:57 -07:00
dfsek 710c00b0d8 annotate initialize method @NotNull 2022-08-21 13:40:19 -07:00
dfsek b6320c95ea Merge pull request #362 from duplexsystem/dev/enviroment
Dev/enviroment
2022-08-21 13:35:02 -07:00
Zoë 0b8524b08d remove comment 2022-08-21 14:33:57 -05:00
Zoë b5d081fde4 remove more random 2022-08-21 14:29:57 -05:00
Zoë b044b2c48e Merge remote-tracking branch 'origin/ver/7.0.0' into dev/enviroment 2022-08-21 12:30:15 -05:00
Zoë b627ce6e58 Update libs and use libs.versions.toml for dep management 2022-08-21 12:21:12 -05:00
dfsek fcffefe91d clean up PluginConfig 2022-08-21 01:06:24 -07:00
dfsek ec8564df2f remove most references to ConfigPack from API 2022-08-21 01:02:10 -07:00
dfsek 997d2204c7 create config-pack addon project 2022-08-21 00:55:03 -07:00
dfsek 4f687f7587 remove ConfigPack and related interfaces 2022-08-21 00:53:03 -07:00
dfsek 620ae7d1ff make Registry immutable, remove other registry implementations 2022-08-21 00:51:26 -07:00
dfsek 6a53a0c56b Merge pull request #355 from Astrashh/dev/pipeline-reimplementation
Biome pipeline reimplementation
2022-08-20 12:34:48 -07:00
Zoë 5d5408e142 terraScript random is no more 2022-08-19 23:18:42 -05:00
Astrash 2025fe6e90 Merge branch 'ver/7.0.0' into dev/pipeline-reimplementation 2022-08-20 13:05:12 +10:00
Zoë e658a5d917 fix enum to uppcases 2022-08-19 20:36:57 -05:00
Zoë 8c16225ed1 Update ModPlatform.java 2022-08-19 20:36:51 -05:00
Zoë 2d97c776fc Dim opts 2022-08-19 20:36:41 -05:00
Zoë 6cd91bcc1d Random Changes 2022-08-19 20:36:32 -05:00
Zoë 5f5c4f85c7 Fixes 2022-08-19 20:35:01 -05:00
Zoë 1702a46fda Merge remote-tracking branch 'origin/fix/scale-pipeline-264' into ver/7.0.0 2022-08-19 20:34:39 -05:00
Astrash 97b74508f8 Merge branch 'ver/7.0.0' into dev/pipeline-reimplementation 2022-08-19 11:37:55 +10:00
dfsek b04a4850da deprecare getByID 2022-08-18 16:54:16 -07:00
dfsek c8beb0f965 clean up unneeded injects 2022-08-18 16:52:46 -07:00
dfsek 74f9c4f9b1 convert all addons to use monad initialiser 2022-08-16 14:36:03 -07:00
dfsek 45c3729392 update OreAddon to use do notation 2022-08-15 11:12:10 -07:00
dfsek 8538ee6804 add simple do notation for monadic binding 2022-08-15 10:33:25 -07:00
dfsek ee64039f5f add vavr dependency 2022-08-15 10:11:38 -07:00
dfsek 0609a7cf6b implement MonadAddonInitializer 2022-08-15 10:06:29 -07:00
dfsek 97854e3037 create monad and functor interfaces 2022-08-14 19:14:47 -07:00
dfsek a6b193503d Merge pull request #358 from Astrashh/dev/dot-product-slant
Calculate noise3d generator slant with dot product
2022-08-14 19:03:45 -07:00
Astrash 7e6b4a0b74 Calculate slant with approx dot product rather than derivative 2022-08-15 10:34:29 +10:00
Astrash af4465196c Replace sout with logger debug calls 2022-08-07 14:53:13 +10:00
Astrash 68058e7dc6 Remove test class from source 2022-08-07 12:30:22 +10:00
Astrash e30ce62d86 Ephemeral -> Placeholder 2022-08-07 12:23:51 +10:00
Astrash 227a2362af Move reimplementation classes into main package 2022-08-07 12:15:50 +10:00
Astrash eb0c40aafd Handle resolution and biome blending 2022-08-07 11:46:55 +10:00
Astrash 3835533cc9 Working state for pipeline implementation 2022-08-06 22:15:15 +10:00
dfsek b83d4c21e0 factor in resolution 2022-07-16 04:22:29 -07:00
dfsek 145eed893a fix #264 with artifacting 2022-07-16 04:22:28 -07:00
dfsek 3dd3c047b4 Merge pull request #341 from duplexsystem/dev/enviroment
Remove vanilla key, Comminfy Some code, Minor Biome Enviroment Tweaks, Port all Enviroment Settings to Bukkit, and Implment Fertilization
2022-07-14 19:51:16 -07:00
Zoë 1003304fde Reformat 2022-07-14 19:50:25 -07:00
Zoë 04c6363469 Merge remote-tracking branch 'origin/dev/enviroment' into dev/enviroment 2022-07-14 19:43:56 -07:00
Zoë 4b518c28a0 Requested changes 2022-07-14 19:43:50 -07:00
Zoë 199360b981 Update LifecycleEntryPoint.java 2022-07-14 00:45:52 -07:00
Zoë f75880acac Bukkit update 2022-07-14 00:38:54 -07:00
Zoë dd9f421972 Growing 2022-07-12 18:46:32 -07:00
Zoë 5c2998c91c remove more 2022-07-12 13:39:52 -07:00
Zoë 09c0f0acc9 Remove unused config keys 2022-07-12 13:37:28 -07:00
Zoë 970a5c60d9 clean 2022-07-12 13:09:58 -07:00
Zoë d8285bc9a7 make bukkit growing better 2022-07-12 13:04:07 -07:00
Zoë 75b545b0be Bukkit Growing 2022-07-12 01:04:55 -07:00
Zoë 50377a1b89 Fabric/Quilt fertilization support 2022-07-11 21:49:16 -07:00
Zoë ba6d4649c6 remove bukkit 1.18 2022-07-11 15:16:54 -07:00
Zoë a286e26656 Bukkit 2022-07-11 14:57:43 -07:00
Zoë 526e655a8f remove unused key 2022-07-11 13:53:38 -07:00
Zoë f26cedd613 Remove Vanilla Key 2022-07-11 13:49:55 -07:00
Zoë b1b91726ef UX tweaks to biome config 2022-07-10 20:18:49 -07:00
Zoë 796f66e708 We do a little commonifying 2022-07-10 19:38:35 -07:00
347 changed files with 5529 additions and 6532 deletions
+6 -18
View File
@@ -3,32 +3,20 @@ plugins {
kotlin("jvm") version embeddedKotlinVersion kotlin("jvm") version embeddedKotlinVersion
} }
buildscript {
configurations.all {
resolutionStrategy {
force("org.ow2.asm:asm:9.3") // TODO: remove when ShadowJar updates ASM version
force("org.ow2.asm:asm-commons:9.3")
}
}
}
repositories { repositories {
mavenCentral() mavenCentral()
gradlePluginPortal() gradlePluginPortal()
maven("https://repo.codemc.org/repository/maven-public") { maven("https://repo.codemc.org/repository/maven-public") {
name = "CodeMC" name = "CodeMC"
} }
maven("https://papermc.io/repo/repository/maven-public/") {
name = "PaperMC"
}
} }
dependencies { dependencies {
implementation("gradle.plugin.com.github.jengelman.gradle.plugins:shadow:+") implementation(libs.libraries.internal.shadow)
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.3.5")
implementation("org.ow2.asm:asm:9.3") implementation(libs.libraries.internal.asm)
implementation("org.ow2.asm:asm-tree:9.3") implementation(libs.libraries.internal.asm.tree)
implementation("com.dfsek.tectonic:common:4.2.0") implementation(libs.libraries.tectonic)
implementation("org.yaml:snakeyaml:1.27") implementation(libs.libraries.snakeyaml)
} }
+7
View File
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
+13 -6
View File
@@ -5,6 +5,8 @@ import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.getting import org.gradle.kotlin.dsl.getting
import org.gradle.kotlin.dsl.maven import org.gradle.kotlin.dsl.maven
import org.gradle.kotlin.dsl.repositories import org.gradle.kotlin.dsl.repositories
import org.gradle.api.artifacts.VersionCatalog
import org.gradle.kotlin.dsl.apply
fun Project.configureDependencies() { fun Project.configureDependencies() {
val testImplementation by configurations.getting val testImplementation by configurations.getting
@@ -15,6 +17,8 @@ fun Project.configureDependencies() {
val shaded by configurations.creating val shaded by configurations.creating
val libs = rootProject.project.versionCatalogs.libs
@Suppress("UNUSED_VARIABLE") @Suppress("UNUSED_VARIABLE")
val shadedApi by configurations.creating { val shadedApi by configurations.creating {
shaded.extendsFrom(this) shaded.extendsFrom(this)
@@ -48,14 +52,17 @@ fun Project.configureDependencies() {
maven("https://jitpack.io") { maven("https://jitpack.io") {
name = "JitPack" name = "JitPack"
} }
maven("https://api.modrinth.com/maven") {
name = "Modrinth"
}
} }
dependencies { dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0") testImplementation(libs.findLibrary("libraries.internal.junit.jupiter.api").get())
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.0") testImplementation(libs.findLibrary("libraries.internal.junit.jupiter.engine").get())
compileOnly("org.jetbrains:annotations:23.0.0") compileOnly(libs.findLibrary("libraries.internal.jetbrains.annotations").get())
compileOnly("com.google.guava:guava:30.0-jre") compileOnly(libs.findLibrary("libraries.guava").get())
testImplementation("com.google.guava:guava:30.0-jre") testImplementation(libs.findLibrary("libraries.guava").get())
} }
} }
@@ -8,7 +8,6 @@ import java.nio.file.StandardCopyOption
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.plugins.BasePluginExtension import org.gradle.api.plugins.BasePluginExtension
import org.gradle.kotlin.dsl.TaskContainerScope
import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.extra import org.gradle.kotlin.dsl.extra
@@ -88,7 +87,8 @@ fun Project.configureDistribution() {
val jar = getJarTask().archiveFileName.get() val jar = getJarTask().archiveFileName.get()
resources.computeIfAbsent( resources.computeIfAbsent(
if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "addons/bootstrap" if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "addons/bootstrap"
else "addons") { ArrayList() }.add(jar) else "addons"
) { ArrayList() }.add(jar)
} }
val options = DumperOptions() val options = DumperOptions()
@@ -109,7 +109,7 @@ fun Project.configureDistribution() {
FileWriter(manifest).use { FileWriter(manifest).use {
yaml.dump(resources, it) yaml.dump(resources, it)
} }
} }
} }
+12
View File
@@ -0,0 +1,12 @@
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.api.artifacts.VersionCatalog
import org.gradle.api.Project
import org.gradle.kotlin.dsl.*
internal
val Project.versionCatalogs: VersionCatalogsExtension
get() = the<VersionCatalogsExtension>()
internal
val VersionCatalogsExtension.libs: VersionCatalog
get() = named("libs")
-69
View File
@@ -1,69 +0,0 @@
object Versions {
object Libraries {
const val tectonic = "4.2.0"
const val paralithic = "0.7.0"
const val strata = "1.1.1"
const val cloud = "1.7.0"
const val slf4j = "1.7.36"
const val log4j_slf4j_impl = "2.14.1"
object Internal {
const val apacheText = "1.9"
const val jafama = "2.3.2"
const val apacheIO = "2.6"
const val fastutil = "8.5.6"
}
}
object Fabric {
const val fabricLoader = "0.14.8"
const val fabricAPI = "0.57.0+1.19"
}
object Quilt {
const val quiltLoader = "0.17.0"
const val fabricApi = "2.0.0-beta.4+0.57.0-1.19"
}
object Mod {
const val mixin = "0.11.2+mixin.0.8.5"
const val minecraft = "1.19"
const val yarn = "$minecraft+build.1"
const val fabricLoader = "0.14.2"
const val architecuryLoom = "0.12.0.290"
const val architecturyPlugin = "3.4-SNAPSHOT"
const val loomQuiltflower = "1.7.1"
const val lazyDfu = "0.1.2"
}
object Forge {
const val forge = "${Mod.minecraft}-41.0.63"
const val burningwave = "12.53.0"
}
object Bukkit {
const val paper = "1.18.2-R0.1-SNAPSHOT"
const val paperLib = "1.0.5"
const val minecraft = "1.19"
const val reflectionRemapper = "0.1.0-SNAPSHOT"
}
object Sponge {
const val sponge = "9.0.0-SNAPSHOT"
const val mixin = "0.8.2"
const val minecraft = "1.17.1"
}
object CLI {
const val nbt = "6.1"
const val logback = "1.2.9"
const val commonsIO = "2.7"
const val guava = "31.0.1-jre"
}
}
@@ -10,58 +10,60 @@ import com.dfsek.terra.addons.biome.extrusion.config.BiomeExtrusionTemplate;
import com.dfsek.terra.addons.biome.extrusion.config.ReplaceableBiomeLoader; import com.dfsek.terra.addons.biome.extrusion.config.ReplaceableBiomeLoader;
import com.dfsek.terra.addons.biome.extrusion.config.extrusions.ReplaceExtrusionTemplate; import com.dfsek.terra.addons.biome.extrusion.config.extrusions.ReplaceExtrusionTemplate;
import com.dfsek.terra.addons.biome.extrusion.config.extrusions.SetExtrusionTemplate; import com.dfsek.terra.addons.biome.extrusion.config.extrusions.SetExtrusionTemplate;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.Registry; import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.generic.Construct;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import org.jetbrains.annotations.NotNull;
public class BiomeExtrusionAddon implements AddonInitializer {
public class BiomeExtrusionAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<Extrusion>>> EXTRUSION_REGISTRY_KEY = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<Extrusion>>> EXTRUSION_REGISTRY_KEY = new TypeKey<>() {
}; };
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
}; };
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> { Get.platform(),
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = ((functionalEventHandler, base, platform) -> Init.ofPure(Construct.construct(() -> {
event.getPack() functionalEventHandler.register(base, ConfigPackPostLoadEvent.class)
.getOrCreateRegistry(PROVIDER_REGISTRY_KEY); .then(event -> {
providerRegistry.register(addon.key("EXTRUSION"), BiomeExtrusionTemplate::new); Registry<Biome> biomeRegistry = event.getPack().getRegistry(Biome.class);
}) event.getPack().applyLoader(ReplaceableBiome.class,
.then(event -> { new ReplaceableBiomeLoader(biomeRegistry));
CheckedRegistry<Supplier<ObjectTemplate<Extrusion>>> extrusionRegistry = event.getPack().getOrCreateRegistry( });
EXTRUSION_REGISTRY_KEY); return functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
extrusionRegistry.register(addon.key("SET"), SetExtrusionTemplate::new); .then(event -> {
extrusionRegistry.register(addon.key("REPLACE"), ReplaceExtrusionTemplate::new); Registry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry =
}) event.getPack()
.failThrough(); .createRegistry(PROVIDER_REGISTRY_KEY);
providerRegistry.register(base.key("EXTRUSION"), BiomeExtrusionTemplate::new);
platform.getEventManager() })
.getHandler(FunctionalEventHandler.class) .then(event -> {
.register(addon, ConfigPackPostLoadEvent.class) Registry<Supplier<ObjectTemplate<Extrusion>>> extrusionRegistry =
.then(event -> { event.getPack().createRegistry(
Registry<Biome> biomeRegistry = event.getPack().getRegistry(Biome.class); EXTRUSION_REGISTRY_KEY);
event.getPack().applyLoader(ReplaceableBiome.class, new ReplaceableBiomeLoader(biomeRegistry)); extrusionRegistry.register(base.key("SET"), SetExtrusionTemplate::new);
}); extrusionRegistry.register(base.key("REPLACE"), ReplaceExtrusionTemplate::new);
})
.failThrough();
}))
));
} }
} }
@@ -2,10 +2,4 @@ version = version("1.0.0")
dependencies { dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader")) compileOnlyApi(project(":common:addons:manifest-addon-loader"))
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
relocate("net.jafama", "com.dfsek.terra.addons.biome.image.lib.jafama")
} }
@@ -11,39 +11,41 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject; import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import org.jetbrains.annotations.NotNull;
public class ImageBiomeProviderAddon implements AddonInitializer {
public class ImageBiomeProviderAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
}; };
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> { Get.platform(),
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry( ((functionalEventHandler, base, platform) -> Init.ofPure(
PROVIDER_REGISTRY_KEY); functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
providerRegistry.register(addon.key("IMAGE"), .then(event -> {
() -> new ImageProviderTemplate(event.getPack().getRegistry(Biome.class))); Registry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().createRegistry(
}) PROVIDER_REGISTRY_KEY);
.failThrough(); providerRegistry.register(base.key("IMAGE"),
() -> new ImageProviderTemplate(event.getPack().getRegistry(Biome.class)));
})
.failThrough()))
);
} }
} }
@@ -2,11 +2,4 @@ version = version("1.0.1")
dependencies { dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader")) compileOnlyApi(project(":common:addons:manifest-addon-loader"))
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
relocate("net.jafama", "com.dfsek.terra.addons.biome.pipeline.lib.jafama")
} }
@@ -1,94 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeExpander;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.util.vector.Vector2;
public class BiomeHolderImpl implements BiomeHolder {
private final Vector2.Mutable origin;
private final int width;
private final int offset;
private BiomeDelegate[][] biomes;
public BiomeHolderImpl(int width, Vector2.Mutable origin) {
width += 4;
this.width = width;
biomes = new BiomeDelegate[width][width];
this.origin = origin;
this.offset = 2;
}
private BiomeHolderImpl(BiomeDelegate[][] biomes, Vector2.Mutable origin, int width, int offset) {
this.biomes = biomes;
this.origin = origin;
this.width = width;
this.offset = 2 * offset;
}
@Override
public BiomeHolder expand(BiomeExpander expander, long seed) {
BiomeDelegate[][] old = biomes;
int newWidth = width * 2 - 1;
biomes = new BiomeDelegate[newWidth][newWidth];
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
biomes[x * 2][z * 2] = old[x][z];
if(z != width - 1)
biomes[x * 2][z * 2 + 1] = expander.getBetween(x + origin.getX(), z + 1 + origin.getZ(), seed, old[x][z],
old[x][z + 1]);
if(x != width - 1)
biomes[x * 2 + 1][z * 2] = expander.getBetween(x + 1 + origin.getX(), z + origin.getZ(), seed, old[x][z],
old[x + 1][z]);
if(x != width - 1 && z != width - 1)
biomes[x * 2 + 1][z * 2 + 1] = expander.getBetween(x + 1 + origin.getX(), z + 1 + origin.getZ(), seed, old[x][z],
old[x + 1][z + 1], old[x][z + 1], old[x + 1][z]);
}
}
return new BiomeHolderImpl(biomes, origin.setX(origin.getX() * 2 - 1).setZ(origin.getZ() * 2 - 1), newWidth, offset);
}
@Override
public void mutate(BiomeMutator mutator, long seed) {
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
BiomeMutator.ViewPoint viewPoint = new BiomeMutator.ViewPoint(this, x, z);
biomes[x][z] = mutator.mutate(viewPoint, x + origin.getX(), z + origin.getZ(), seed);
}
}
}
@Override
public void fill(BiomeSource source, long seed) {
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
biomes[x][z] = source.getBiome(origin.getX() + x, origin.getZ() + z, seed);
}
}
}
@Override
public BiomeDelegate getBiome(int x, int z) {
x += offset;
z += offset;
return getBiomeRaw(x, z);
}
@Override
public BiomeDelegate getBiomeRaw(int x, int z) {
if(x >= width || z >= width || x < 0 || z < 0) return null;
return biomes[x][z];
}
}
@@ -1,83 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.util.vector.Vector2;
public class BiomePipeline {
private final BiomeSource source;
private final List<Stage> stages;
private final int size;
private final int init;
private BiomePipeline(BiomeSource source, List<Stage> stages, int size, int init) {
this.source = source;
this.stages = stages;
this.size = size;
this.init = init;
}
/**
* Get biomes in a chunk
*
* @param x Chunk X coord
* @param z Chunk Z coord
*
* @return BiomeHolder containing biomes.
*/
public BiomeHolder getBiomes(int x, int z, long seed) {
BiomeHolder holder = new BiomeHolderImpl(init, Vector2.of(x * (init - 1), z * (init - 1)).mutable());
holder.fill(source, seed);
for(Stage stage : stages) holder = stage.apply(holder, seed);
return holder;
}
public BiomeSource getSource() {
return source;
}
public List<Stage> getStages() {
return Collections.unmodifiableList(stages);
}
public int getSize() {
return size;
}
public static final class BiomePipelineBuilder {
private final int init;
private final List<Stage> stages = new ArrayList<>();
private int expand;
public BiomePipelineBuilder(int init) {
this.init = init;
expand = init;
}
public BiomePipeline build(BiomeSource source) {
for(Stage stage : stages) {
if(stage.isExpansion()) expand = expand * 2 - 1;
}
return new BiomePipeline(source, stages, expand, init);
}
public BiomePipelineBuilder addStage(Stage stage) {
stages.add(stage);
return this;
}
}
}
@@ -11,79 +11,84 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.BiomeDelegateLoader;
import com.dfsek.terra.addons.biome.pipeline.config.BiomePipelineTemplate; import com.dfsek.terra.addons.biome.pipeline.config.BiomePipelineTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.SamplerSourceTemplate; import com.dfsek.terra.addons.biome.pipeline.config.PipelineBiomeLoader;
import com.dfsek.terra.addons.biome.pipeline.config.source.SamplerSourceTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.expander.ExpanderStageTemplate; 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.BorderListStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.BorderMutatorTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.BorderStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceListMutatorTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceListStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceMutatorTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.SmoothMutatorTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.SmoothStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource; import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.Registry; import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.generic.Construct;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomePipelineAddon implements AddonInitializer { public class BiomePipelineAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<BiomeSource>>> SOURCE_REGISTRY_KEY = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<Source>>> SOURCE_REGISTRY_KEY = new TypeKey<>() {
}; };
public static final TypeKey<Supplier<ObjectTemplate<Stage>>> STAGE_REGISTRY_KEY = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<Stage>>> STAGE_REGISTRY_KEY = new TypeKey<>() {
}; };
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
}; };
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> { ((functionalEventHandler, base) -> Init.ofPure(Construct.construct(() -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry( functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
PROVIDER_REGISTRY_KEY); .then(event -> {
providerRegistry.register(addon.key("PIPELINE"), BiomePipelineTemplate::new); CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry =
}) event.getPack().getOrCreateRegistry(
.then(event -> { PROVIDER_REGISTRY_KEY);
CheckedRegistry<Supplier<ObjectTemplate<BiomeSource>>> sourceRegistry = event.getPack().getOrCreateRegistry( providerRegistry.register(base.key("PIPELINE"), BiomePipelineTemplate::new);
SOURCE_REGISTRY_KEY); })
sourceRegistry.register(addon.key("SAMPLER"), SamplerSourceTemplate::new); .then(event -> {
}) CheckedRegistry<Supplier<ObjectTemplate<Source>>> sourceRegistry =
.then(event -> { event.getPack().getOrCreateRegistry(
CheckedRegistry<Supplier<ObjectTemplate<Stage>>> stageRegistry = event.getPack().getOrCreateRegistry( SOURCE_REGISTRY_KEY);
STAGE_REGISTRY_KEY); sourceRegistry.register(base.key("SAMPLER"), SamplerSourceTemplate::new);
stageRegistry.register(addon.key("FRACTAL_EXPAND"), ExpanderStageTemplate::new); })
stageRegistry.register(addon.key("SMOOTH"), SmoothMutatorTemplate::new); .then(event -> {
stageRegistry.register(addon.key("REPLACE"), ReplaceMutatorTemplate::new); CheckedRegistry<Supplier<ObjectTemplate<Stage>>> stageRegistry =
stageRegistry.register(addon.key("REPLACE_LIST"), ReplaceListMutatorTemplate::new); event.getPack().getOrCreateRegistry(
stageRegistry.register(addon.key("BORDER"), BorderMutatorTemplate::new); STAGE_REGISTRY_KEY);
stageRegistry.register(addon.key("BORDER_LIST"), BorderListMutatorTemplate::new); stageRegistry.register(base.key("FRACTAL_EXPAND"), ExpanderStageTemplate::new);
}) stageRegistry.register(base.key("SMOOTH"), SmoothStageTemplate::new);
.failThrough(); stageRegistry.register(base.key("REPLACE"), ReplaceStageTemplate::new);
platform.getEventManager() stageRegistry.register(base.key("REPLACE_LIST"), ReplaceListStageTemplate::new);
.getHandler(FunctionalEventHandler.class) stageRegistry.register(base.key("BORDER"), BorderStageTemplate::new);
.register(addon, ConfigPackPostLoadEvent.class) stageRegistry.register(base.key("BORDER_LIST"), BorderListStageTemplate::new);
.then(event -> { })
Registry<Biome> biomeRegistry = event.getPack().getRegistry(Biome.class); .failThrough();
event.getPack().applyLoader(BiomeDelegate.class, new BiomeDelegateLoader(biomeRegistry)); return functionalEventHandler.register(base, ConfigPackPostLoadEvent.class)
}); .then(event -> {
Registry<Biome> biomeRegistry = event.getPack().getRegistry(Biome.class);
event.getPack().applyLoader(PipelineBiome.class,
new PipelineBiomeLoader(biomeRegistry));
});
})))
);
} }
} }
@@ -9,7 +9,7 @@ import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
class BiomePipelineColumn implements Column<Biome> { public class BiomePipelineColumn implements Column<Biome> {
private final int min; private final int min;
private final int max; private final int max;
@@ -1,10 +1,3 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline; package com.dfsek.terra.addons.biome.pipeline;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
@@ -13,13 +6,14 @@ import net.jafama.FastMath;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder; import com.dfsek.terra.addons.biome.pipeline.api.BiomeChunk;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate; import com.dfsek.terra.addons.biome.pipeline.api.Pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage; import com.dfsek.terra.addons.biome.pipeline.api.SeededVector;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.registry.key.StringIdentifiable; import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.util.Column; import com.dfsek.terra.api.util.Column;
@@ -27,35 +21,35 @@ import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomePipelineProvider implements BiomeProvider { public class PipelineBiomeProvider implements BiomeProvider {
private final LoadingCache<SeededVector, BiomeHolder> holderCache;
private final BiomePipeline pipeline; private final LoadingCache<SeededVector, BiomeChunk> biomeChunkCache;
private final int chunkSize;
private final int resolution; private final int resolution;
private final NoiseSampler mutator; private final NoiseSampler mutator;
private final double noiseAmp; private final double noiseAmp;
private final Set<Biome> biomes; private final Set<Biome> biomes;
public BiomePipelineProvider(BiomePipeline pipeline, int resolution, NoiseSampler mutator, double noiseAmp) { public PipelineBiomeProvider(Pipeline pipeline, int resolution, NoiseSampler mutator, double noiseAmp) {
this.resolution = resolution; this.resolution = resolution;
this.mutator = mutator; this.mutator = mutator;
this.noiseAmp = noiseAmp; this.noiseAmp = noiseAmp;
holderCache = Caffeine.newBuilder() this.chunkSize = pipeline.getChunkSize();
.maximumSize(1024) this.biomeChunkCache = Caffeine.newBuilder()
.build(key -> pipeline.getBiomes(key.x, key.z, key.seed)); .maximumSize(1024)
this.pipeline = pipeline; .build(pipeline::generateChunk);
Set<BiomeDelegate> biomeSet = new HashSet<>(); Set<PipelineBiome> biomeSet = new HashSet<>();
pipeline.getSource().getBiomes().forEach(biomeSet::add); pipeline.getSource().getBiomes().forEach(biomeSet::add);
Iterable<BiomeDelegate> result = biomeSet; Iterable<PipelineBiome> result = biomeSet;
for(Stage stage : pipeline.getStages()) { for(Stage stage : pipeline.getStages()) {
result = stage.getBiomes(result); // pass through all stages result = stage.getBiomes(result);
} }
this.biomes = new HashSet<>(); this.biomes = new HashSet<>();
Iterable<BiomeDelegate> finalResult = result; Iterable<PipelineBiome> finalResult = result;
result.forEach(biomeDelegate -> { result.forEach(pipelineBiome -> {
if(biomeDelegate.isEphemeral()) { if(pipelineBiome.isPlaceholder()) {
StringBuilder biomeList = new StringBuilder("\n"); StringBuilder biomeList = new StringBuilder("\n");
StreamSupport.stream(finalResult.spliterator(), false) StreamSupport.stream(finalResult.spliterator(), false)
.sorted(Comparator.comparing(StringIdentifiable::getID)) .sorted(Comparator.comparing(StringIdentifiable::getID))
@@ -65,11 +59,11 @@ public class BiomePipelineProvider implements BiomeProvider {
.append(':') .append(':')
.append(delegate.getClass().getCanonicalName()) .append(delegate.getClass().getCanonicalName())
.append('\n')); .append('\n'));
throw new IllegalArgumentException("Biome Pipeline leaks ephemeral biome \"" + biomeDelegate.getID() + throw new IllegalArgumentException("Biome Pipeline leaks placeholder biome \"" + pipelineBiome.getID() +
"\". Ensure there is a stage to guarantee replacement of the ephemeral biome. Biomes: " + "\". Ensure there is a stage to guarantee replacement of the placeholder biome. Biomes: " +
biomeList); biomeList);
} }
this.biomes.add(biomeDelegate.getBiome()); this.biomes.add(pipelineBiome.getBiome());
}); });
} }
@@ -79,22 +73,23 @@ public class BiomePipelineProvider implements BiomeProvider {
} }
public Biome getBiome(int x, int z, long seed) { public Biome getBiome(int x, int z, long seed) {
x += mutator.noise(seed + 1, x, z) * noiseAmp; x += mutator.noise(seed + 1, x, z) * noiseAmp;
z += mutator.noise(seed + 2, x, z) * noiseAmp; z += mutator.noise(seed + 2, x, z) * noiseAmp;
x /= resolution; x /= resolution;
z /= resolution; z /= resolution;
int fdX = FastMath.floorDiv(x, pipeline.getSize()); int chunkX = FastMath.floorDiv(x, chunkSize);
int fdZ = FastMath.floorDiv(z, pipeline.getSize()); int chunkZ = FastMath.floorDiv(z, chunkSize);
return holderCache.get(new SeededVector(fdX, fdZ, seed)).getBiome(x - fdX * pipeline.getSize(),
z - fdZ * pipeline.getSize()).getBiome(); int chunkWorldX = chunkX * chunkSize;
} int chunkWorldZ = chunkZ * chunkSize;
@Override int xInChunk = x - chunkWorldX;
public Optional<Biome> getBaseBiome(int x, int z, long seed) { int zInChunk = z - chunkWorldZ;
return Optional.of(getBiome(x, z, seed));
return biomeChunkCache.get(new SeededVector(seed, chunkWorldX, chunkWorldZ)).get(xInChunk, zInChunk).getBiome();
} }
@Override @Override
@@ -111,21 +106,4 @@ public class BiomePipelineProvider implements BiomeProvider {
public int resolution() { public int resolution() {
return resolution; return resolution;
} }
private record SeededVector(int x, int z, long seed) {
@Override
public boolean equals(Object obj) {
if(obj instanceof SeededVector that) {
return this.z == that.z && this.x == that.x && this.seed == that.seed;
}
return false;
}
@Override
public int hashCode() {
int code = x;
code = 31 * code + z;
return 31 * code + ((int) (seed ^ (seed >>> 32)));
}
}
} }
@@ -0,0 +1,10 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
public interface BiomeChunk {
PipelineBiome get(int xInChunk, int zInChunk);
}
@@ -1,26 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeExpander;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
public interface BiomeHolder {
BiomeHolder expand(BiomeExpander expander, long seed);
void mutate(BiomeMutator mutator, long seed);
void fill(BiomeSource source, long seed);
BiomeDelegate getBiome(int x, int z);
BiomeDelegate getBiomeRaw(int x, int z);
}
@@ -0,0 +1,29 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
/**
* Resizes the internal grid of a BiomeChunk when applied, serves the purpose of
* filling in null biomes as a result of this resizing.
*/
public interface Expander extends Stage {
PipelineBiome fillBiome(ViewPoint viewPoint);
@Override
default int maxRelativeReadDistance() {
return 0;
}
@Override
default PipelineBiome apply(ViewPoint viewPoint) {
PipelineBiome currentBiome = viewPoint.getBiome();
if(currentBiome == null) {
return fillBiome(viewPoint);
} else {
return currentBiome;
}
}
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import java.util.List;
public interface Pipeline {
BiomeChunk generateChunk(SeededVector worldCoordinates);
int getChunkSize();
Source getSource();
List<Stage> getStages();
}
@@ -0,0 +1,19 @@
package com.dfsek.terra.addons.biome.pipeline.api;
public record SeededVector(long seed, int x, int z) {
@Override
public boolean equals(Object obj) {
if(obj instanceof SeededVector that) {
return this.z == that.z && this.x == that.x && this.seed == that.seed;
}
return false;
}
@Override
public int hashCode() {
int code = x;
code = 31 * code + z;
return 31 * code + ((int) (seed ^ (seed >>> 32)));
}
}
@@ -0,0 +1,11 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
public interface Source {
PipelineBiome get(long seed, int x, int z);
Iterable<PipelineBiome> getBiomes();
}
@@ -0,0 +1,15 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
public interface Stage {
PipelineBiome apply(ViewPoint viewPoint);
int maxRelativeReadDistance();
default Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
return biomes;
}
}
@@ -1,14 +1,14 @@
package com.dfsek.terra.addons.biome.pipeline.api.delegate; package com.dfsek.terra.addons.biome.pipeline.api.biome;
import java.util.Set; import java.util.Set;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
final class DelegatedBiome implements BiomeDelegate { public final class DelegatedPipelineBiome implements PipelineBiome {
private final Biome biome; private final Biome biome;
public DelegatedBiome(Biome biome) { public DelegatedPipelineBiome(Biome biome) {
this.biome = biome; this.biome = biome;
} }
@@ -24,7 +24,7 @@ final class DelegatedBiome implements BiomeDelegate {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if(!(obj instanceof DelegatedBiome that)) return false; if(!(obj instanceof DelegatedPipelineBiome that)) return false;
return that.biome.equals(this.biome); return that.biome.equals(this.biome);
} }
@@ -0,0 +1,35 @@
package com.dfsek.terra.addons.biome.pipeline.api.biome;
import java.util.Set;
import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.world.biome.Biome;
public interface PipelineBiome extends StringIdentifiable {
Biome getBiome();
static PipelineBiome placeholder(String id) {
return new PlaceholderPipelineBiome(id);
}
static PipelineBiome from(Biome biome) {
return new DelegatedPipelineBiome(biome);
}
static PipelineBiome self() {
return SelfPipelineBiome.INSTANCE;
}
Set<String> getTags();
default boolean isPlaceholder() {
return false;
}
default boolean isSelf() {
return false;
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.addons.biome.pipeline.api.delegate; package com.dfsek.terra.addons.biome.pipeline.api.biome;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@@ -6,11 +6,11 @@ import java.util.Set;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
final class EphemeralBiomeDelegate implements BiomeDelegate { final class PlaceholderPipelineBiome implements PipelineBiome {
private final Set<String> tags; private final Set<String> tags;
private final String id; private final String id;
public EphemeralBiomeDelegate(String id) { public PlaceholderPipelineBiome(String id) {
this.id = id; this.id = id;
tags = new HashSet<>(); tags = new HashSet<>();
tags.add(id); tags.add(id);
@@ -19,7 +19,7 @@ final class EphemeralBiomeDelegate implements BiomeDelegate {
@Override @Override
public Biome getBiome() { public Biome getBiome() {
throw new UnsupportedOperationException("Cannot get biome from ephemeral delegate"); throw new UnsupportedOperationException("Cannot get raw biome from placeholder pipeline biome");
} }
@Override @Override
@@ -33,7 +33,7 @@ final class EphemeralBiomeDelegate implements BiomeDelegate {
} }
@Override @Override
public boolean isEphemeral() { public boolean isPlaceholder() {
return true; return true;
} }
@@ -44,7 +44,7 @@ final class EphemeralBiomeDelegate implements BiomeDelegate {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if(!(obj instanceof EphemeralBiomeDelegate that)) return false; if(!(obj instanceof PlaceholderPipelineBiome that)) return false;
return this.id.equals(that.id); return this.id.equals(that.id);
} }
@@ -1,4 +1,4 @@
package com.dfsek.terra.addons.biome.pipeline.api.delegate; package com.dfsek.terra.addons.biome.pipeline.api.biome;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
@@ -6,10 +6,10 @@ import java.util.Set;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
final class SelfDelegate implements BiomeDelegate { final class SelfPipelineBiome implements PipelineBiome {
public static final SelfDelegate INSTANCE = new SelfDelegate(); public static final SelfPipelineBiome INSTANCE = new SelfPipelineBiome();
private SelfDelegate() { private SelfPipelineBiome() {
} }
@@ -24,7 +24,7 @@ final class SelfDelegate implements BiomeDelegate {
} }
@Override @Override
public boolean isEphemeral() { public boolean isPlaceholder() {
return true; return true;
} }
@@ -1,35 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.api.delegate;
import java.util.Set;
import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.world.biome.Biome;
public interface BiomeDelegate extends StringIdentifiable {
static BiomeDelegate ephemeral(String id) {
return new EphemeralBiomeDelegate(id);
}
static BiomeDelegate from(Biome biome) {
return new DelegatedBiome(biome);
}
static BiomeDelegate self() {
return SelfDelegate.INSTANCE;
}
Biome getBiome();
Set<String> getTags();
default boolean isEphemeral() {
return false;
}
default boolean isSelf() {
return false;
}
}
@@ -1,20 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.api.stage;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
public interface Stage {
BiomeHolder apply(BiomeHolder in, long seed);
boolean isExpansion();
Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes);
}
@@ -1,15 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.api.stage.type;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
public interface BiomeExpander {
BiomeDelegate getBetween(double x, double z, long seed, BiomeDelegate... others);
}
@@ -1,37 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.api.stage.type;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
public interface BiomeMutator {
BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed);
default Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
return biomes;
}
class ViewPoint {
private final BiomeHolder biomes;
private final int offX;
private final int offZ;
public ViewPoint(BiomeHolder biomes, int offX, int offZ) {
this.biomes = biomes;
this.offX = offX;
this.offZ = offZ;
}
public BiomeDelegate getBiome(int x, int z) {
return biomes.getBiomeRaw(x + offX, z + offZ);
}
}
}
@@ -10,45 +10,50 @@ package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.api.config.template.annotations.Default; import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Description; import com.dfsek.tectonic.api.config.template.annotations.Description;
import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.List; import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.BiomePipeline; import com.dfsek.terra.addons.biome.pipeline.PipelineBiomeProvider;
import com.dfsek.terra.addons.biome.pipeline.BiomePipelineProvider; import com.dfsek.terra.addons.biome.pipeline.pipeline.PipelineImpl;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@SuppressWarnings({ "FieldMayBeFinal", "unused" }) @SuppressWarnings({ "FieldMayBeFinal", "unused" })
public class BiomePipelineTemplate extends BiomeProviderTemplate { public class BiomePipelineTemplate implements ObjectTemplate<BiomeProvider> {
@Value("pipeline.initial-size") @Value("resolution")
@Default @Default
@Description(""" @Description("""
The initial size of biome chunks. This value must be at least 2. The resolution at which to sample biomes.
<b>This is not the final size of biome chunks. Final chunks will be much larger</b>.
Larger values are quadratically faster, but produce lower quality results.
It is recommended to keep biome chunks' final size in the range of [50, 300] For example, a value of 3 would sample every 3 blocks.""")
to prevent performance issues. To calculate the size of biome chunks, simply protected @Meta int resolution = 1;
take initial-size and for each expand stage, multiply the running value by 2
and subtract 1. (The size is also printed to the server console if you
have debug mode enabled)""")
private @Meta int initialSize = 2;
@Value("pipeline.source") @Value("pipeline.source")
@Description("The Biome Source to use for initial population of biomes.") @Description("The Biome Source to use for initial population of biomes.")
private @Meta BiomeSource source; private @Meta Source source;
@Value("pipeline.stages") @Value("pipeline.stages")
@Description("A list of pipeline stages to apply to the result of #source") @Description("A list of pipeline stages to apply to the result of #source")
private @Meta List<@Meta Stage> stages; private @Meta List<@Meta Stage> stages;
@Value("blend.sampler")
@Default
@Description("A sampler to use for blending the edges of biomes via domain warping.")
protected @Meta NoiseSampler blendSampler = NoiseSampler.zero();
@Value("blend.amplitude")
@Default
@Description("The amplitude at which to perform blending.")
protected @Meta double blendAmplitude = 0d;
@Override @Override
public BiomeProvider get() { public BiomeProvider get() {
BiomePipeline.BiomePipelineBuilder biomePipelineBuilder = new BiomePipeline.BiomePipelineBuilder(initialSize); return new PipelineBiomeProvider(new PipelineImpl(source, stages, resolution, 500), resolution, blendSampler, blendAmplitude);
stages.forEach(biomePipelineBuilder::addStage);
BiomePipeline pipeline = biomePipelineBuilder.build(source);
return new BiomePipelineProvider(pipeline, resolution, blend, blendAmp);
} }
} }
@@ -1,37 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Description;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvider> {
@Value("resolution")
@Default
@Description("""
The resolution at which to sample biomes.
Larger values are quadratically faster, but produce lower quality results.
For example, a value of 3 would sample every 3 blocks.""")
protected @Meta int resolution = 1;
@Value("blend.sampler")
@Default
@Description("A sampler to use for blending the edges of biomes via domain warping.")
protected @Meta NoiseSampler blend = NoiseSampler.zero();
@Value("blend.amplitude")
@Default
@Description("The amplitude at which to perform blending.")
protected @Meta double blendAmp = 0d;
}
@@ -8,25 +8,25 @@ import org.jetbrains.annotations.NotNull;
import java.lang.reflect.AnnotatedType; import java.lang.reflect.AnnotatedType;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate; import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.registry.Registry; import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
public class BiomeDelegateLoader implements TypeLoader<BiomeDelegate> { public class PipelineBiomeLoader implements TypeLoader<PipelineBiome> {
private final Registry<Biome> biomeRegistry; private final Registry<Biome> biomeRegistry;
public BiomeDelegateLoader(Registry<Biome> biomeRegistry) { public PipelineBiomeLoader(Registry<Biome> biomeRegistry) {
this.biomeRegistry = biomeRegistry; this.biomeRegistry = biomeRegistry;
} }
@Override @Override
public BiomeDelegate load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker) public PipelineBiome load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
throws LoadException { throws LoadException {
if(c.equals("SELF")) return BiomeDelegate.self(); if(c.equals("SELF")) return PipelineBiome.self();
return biomeRegistry return biomeRegistry
.getByID((String) c) .getByID((String) c)
.map(BiomeDelegate::from) .map(PipelineBiome::from)
.orElseGet(() -> BiomeDelegate.ephemeral((String) c)); .orElseGet(() -> PipelineBiome.placeholder((String) c));
} }
} }
@@ -5,13 +5,13 @@
* reference the LICENSE file in this module's root directory. * reference the LICENSE file in this module's root directory.
*/ */
package com.dfsek.terra.addons.biome.pipeline.config; package com.dfsek.terra.addons.biome.pipeline.config.source;
import com.dfsek.tectonic.api.config.template.annotations.Description; import com.dfsek.tectonic.api.config.template.annotations.Description;
import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate; import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource; import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.source.SamplerSource; import com.dfsek.terra.addons.biome.pipeline.source.SamplerSource;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
@@ -25,10 +25,10 @@ public class SamplerSourceTemplate extends SourceTemplate {
@Value("biomes") @Value("biomes")
@Description("The biomes to be distributed.") @Description("The biomes to be distributed.")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> biomes; private @Meta ProbabilityCollection<@Meta PipelineBiome> biomes;
@Override @Override
public BiomeSource get() { public Source get() {
return new SamplerSource(biomes, noise); return new SamplerSource(biomes, noise);
} }
} }
@@ -5,13 +5,13 @@
* reference the LICENSE file in this module's root directory. * reference the LICENSE file in this module's root directory.
*/ */
package com.dfsek.terra.addons.biome.pipeline.config; package com.dfsek.terra.addons.biome.pipeline.config.source;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource; import com.dfsek.terra.addons.biome.pipeline.api.Source;
public abstract class SourceTemplate implements ObjectTemplate<BiomeSource> { public abstract class SourceTemplate implements ObjectTemplate<Source> {
} }
@@ -11,7 +11,7 @@ import com.dfsek.tectonic.api.config.template.annotations.Description;
import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
@@ -7,15 +7,14 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.expander; package com.dfsek.terra.addons.biome.pipeline.config.stage.expander;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; 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.api.Expander;
import com.dfsek.terra.addons.biome.pipeline.stages.ExpanderStage; import com.dfsek.terra.addons.biome.pipeline.stage.expander.FractalExpander;
public class ExpanderStageTemplate extends StageTemplate { public class ExpanderStageTemplate extends StageTemplate {
@Override @Override
public Stage get() { public Expander get() {
return new ExpanderStage(new FractalExpander(noise)); return new FractalExpander(noise);
} }
} }
@@ -11,17 +11,16 @@ import com.dfsek.tectonic.api.config.template.annotations.Value;
import java.util.Map; import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.BorderListMutator; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage; import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.stage.mutators.BorderListStage;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class BorderListMutatorTemplate extends StageTemplate { public class BorderListStageTemplate extends StageTemplate {
@Value("from") @Value("from")
private @Meta String from; private @Meta String from;
@@ -29,14 +28,14 @@ public class BorderListMutatorTemplate extends StageTemplate {
private @Meta String defaultReplace; private @Meta String defaultReplace;
@Value("default-to") @Value("default-to")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> defaultTo; private @Meta ProbabilityCollection<@Meta PipelineBiome> defaultTo;
@Value("replace") @Value("replace")
private @Meta Map<@Meta BiomeDelegate, @Meta ProbabilityCollection<@Meta BiomeDelegate>> replace; private @Meta Map<@Meta PipelineBiome, @Meta ProbabilityCollection<@Meta PipelineBiome>> replace;
@Override @Override
public Stage get() { public Stage get() {
return new MutatorStage(new BorderListMutator(replace, from, defaultReplace, noise, defaultTo)); return new BorderListStage(replace, from, defaultReplace, noise, defaultTo);
} }
} }
@@ -9,17 +9,16 @@ package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.BorderMutator; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage; import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.stage.mutators.BorderStage;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class BorderMutatorTemplate extends StageTemplate { public class BorderStageTemplate extends StageTemplate {
@Value("from") @Value("from")
private @Meta String from; private @Meta String from;
@@ -27,10 +26,10 @@ public class BorderMutatorTemplate extends StageTemplate {
private @Meta String replace; private @Meta String replace;
@Value("to") @Value("to")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> to; private @Meta ProbabilityCollection<@Meta PipelineBiome> to;
@Override @Override
public Stage get() { public Stage get() {
return new MutatorStage(new BorderMutator(from, replace, noise, to)); return new BorderStage(from, replace, noise, to);
} }
} }
@@ -11,28 +11,27 @@ import com.dfsek.tectonic.api.config.template.annotations.Value;
import java.util.Map; import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceListMutator; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage; import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.stage.mutators.ReplaceListStage;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class ReplaceListMutatorTemplate extends StageTemplate { public class ReplaceListStageTemplate extends StageTemplate {
@Value("default-from") @Value("default-from")
private @Meta String defaultFrom; private @Meta String defaultFrom;
@Value("default-to") @Value("default-to")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> defaultTo; private @Meta ProbabilityCollection<@Meta PipelineBiome> defaultTo;
@Value("to") @Value("to")
private @Meta Map<@Meta BiomeDelegate, @Meta ProbabilityCollection<@Meta BiomeDelegate>> replace; private @Meta Map<@Meta PipelineBiome, @Meta ProbabilityCollection<@Meta PipelineBiome>> replace;
@Override @Override
public Stage get() { public Stage get() {
return new MutatorStage(new ReplaceListMutator(replace, defaultFrom, defaultTo, noise)); return new ReplaceListStage(replace, defaultFrom, defaultTo, noise);
} }
} }
@@ -9,25 +9,24 @@ package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceMutator; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage; import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.stage.mutators.ReplaceStage;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class ReplaceMutatorTemplate extends StageTemplate { public class ReplaceStageTemplate extends StageTemplate {
@Value("from") @Value("from")
private @Meta String from; private @Meta String from;
@Value("to") @Value("to")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> to; private @Meta ProbabilityCollection<@Meta PipelineBiome> to;
@Override @Override
public Stage get() { public Stage get() {
return new MutatorStage(new ReplaceMutator(from, to, noise)); return new ReplaceStage(from, to, noise);
} }
} }
@@ -7,15 +7,14 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator; package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.SmoothMutator; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage; import com.dfsek.terra.addons.biome.pipeline.stage.mutators.SmoothStage;
public class SmoothMutatorTemplate extends StageTemplate { public class SmoothStageTemplate extends StageTemplate {
@Override @Override
public Stage get() { public Stage get() {
return new MutatorStage(new SmoothMutator(noise)); return new SmoothStage(noise);
} }
} }
@@ -1,27 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.expand;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeExpander;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil;
public class FractalExpander implements BiomeExpander {
private final NoiseSampler sampler;
public FractalExpander(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public BiomeDelegate getBetween(double x, double z, long seed, BiomeDelegate... others) {
return others[MathUtil.normalizeIndex(sampler.noise(seed, x, z), others.length)];
}
}
@@ -1,67 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class BorderListMutator implements BiomeMutator {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<BiomeDelegate> replaceDefault;
private final String defaultReplace;
private final Map<BiomeDelegate, ProbabilityCollection<BiomeDelegate>> replace;
public BorderListMutator(Map<BiomeDelegate, ProbabilityCollection<BiomeDelegate>> replace, String border, String defaultReplace,
NoiseSampler noiseSampler, ProbabilityCollection<BiomeDelegate> replaceDefault) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replaceDefault = replaceDefault;
this.defaultReplace = defaultReplace;
this.replace = replace;
}
@Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) {
BiomeDelegate origin = viewPoint.getBiome(0, 0);
if(origin.getTags().contains(defaultReplace)) {
for(int xi = -1; xi <= 1; xi++) {
for(int zi = -1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
BiomeDelegate current = viewPoint.getBiome(xi, zi);
if(current != null && current.getTags().contains(border)) {
if(replace.containsKey(origin)) {
BiomeDelegate biome = replace.get(origin).get(noiseSampler, x, z, seed);
return biome.isSelf() ? origin : biome;
}
BiomeDelegate biome = replaceDefault.get(noiseSampler, x, z, seed);
return biome.isSelf() ? origin : biome;
}
}
}
}
return origin;
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
Set<BiomeDelegate> biomeSet = new HashSet<>();
biomes.forEach(biomeSet::add);
biomeSet.addAll(replaceDefault.getContents().stream().filter(Predicate.not(BiomeDelegate::isSelf)).toList());
replace.forEach((biome, collection) -> biomeSet.addAll(collection.getContents()));
return biomeSet;
}
}
@@ -1,66 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class BorderMutator implements BiomeMutator {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<BiomeDelegate> replace;
private final String replaceTag;
public BorderMutator(String border, String replaceTag, NoiseSampler noiseSampler, ProbabilityCollection<BiomeDelegate> replace) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replace = replace;
this.replaceTag = replaceTag;
}
@Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) {
BiomeDelegate origin = viewPoint.getBiome(0, 0);
if(origin.getTags().contains(replaceTag)) {
for(int xi = -1; xi <= 1; xi++) {
for(int zi = -1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
BiomeDelegate current = viewPoint.getBiome(xi, zi);
if(current != null && current.getTags().contains(border)) {
BiomeDelegate biome = replace.get(noiseSampler, x, z, seed);
return biome.isSelf() ? origin : biome;
}
}
}
}
return origin;
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
Set<BiomeDelegate> biomeSet = new HashSet<>();
biomes.forEach(biomeSet::add);
biomeSet.addAll(
replace
.getContents()
.stream()
.filter(
Predicate.not(BiomeDelegate::isSelf)
)
.toList()
);
return biomeSet;
}
}
@@ -1,46 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.Objects;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil;
public class SmoothMutator implements BiomeMutator {
private final NoiseSampler sampler;
public SmoothMutator(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) {
BiomeDelegate top = viewPoint.getBiome(1, 0);
BiomeDelegate bottom = viewPoint.getBiome(-1, 0);
BiomeDelegate left = viewPoint.getBiome(0, 1);
BiomeDelegate right = viewPoint.getBiome(0, -1);
boolean vert = Objects.equals(top, bottom) && top != null;
boolean horiz = Objects.equals(left, right) && left != null;
if(vert && horiz) {
return MathUtil.normalizeIndex(sampler.noise(seed, x, z), 2) == 0 ? left : top;
}
if(vert) return top;
if(horiz) return left;
return viewPoint.getBiome(0, 0);
}
}
@@ -0,0 +1,218 @@
package com.dfsek.terra.addons.biome.pipeline.pipeline;
import net.jafama.FastMath;
import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.api.SeededVector;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeChunk;
import com.dfsek.terra.addons.biome.pipeline.api.Expander;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
public class BiomeChunkImpl implements BiomeChunk {
private PipelineBiome[][] biomes;
private final SeededVector worldOrigin;
private final int chunkOriginArrayIndex;
private final int worldCoordinateScale;
public BiomeChunkImpl(SeededVector worldOrigin, PipelineImpl pipeline) {
this.worldOrigin = worldOrigin;
this.chunkOriginArrayIndex = pipeline.getChunkOriginArrayIndex();
this.worldCoordinateScale = pipeline.getResolution();
int size = pipeline.getArraySize();
int expanderCount = pipeline.getExpanderCount();
int expansionsApplied = 0;
// Allocate working arrays
this.biomes = new PipelineBiome[size][size];
PipelineBiome[][] lookupArray = new PipelineBiome[size][size];
// A second lookup array is required such that stage application doesn't affect lookups, otherwise application may cascade
// Construct working grid
int gridOrigin = 0;
int gridInterval = calculateGridInterval(expanderCount, expansionsApplied);
int gridSize = (size / gridInterval);
gridSize += expanderCount > 0 ? 1 : 0; // Add an extra border if expansion occurs
// Fill working grid with initial cells
for(int gridX = 0; gridX < gridSize; gridX++) {
for(int gridZ = 0; gridZ < gridSize; gridZ++) {
int xIndex = gridOrigin + gridX * gridInterval;
int zIndex = gridOrigin + gridZ * gridInterval;
biomes[xIndex][zIndex] = pipeline.getSource().get(worldOrigin.seed(), xIndexToWorldCoordinate(xIndex), zIndexToWorldCoordinate(zIndex));
}
}
for(Stage stage : pipeline.getStages()) {
if(stage instanceof Expander) {
// Shrink working grid size, the expander will fill in null cells (as a result of shrinking the grid) during mutation
expansionsApplied++;
gridInterval = calculateGridInterval(expanderCount, expansionsApplied);
gridSize = expandSize(gridSize);
}
int stageReadDistance = stage.maxRelativeReadDistance();
if(stageReadDistance > 0) {
// Discard edges such that adjacent lookups are only ran on valid cells
gridSize = contractBordersFromSize(gridSize, stageReadDistance);
gridOrigin += stageReadDistance * gridInterval;
}
// Cycle arrays, the previously populated array is swapped to be used for lookups, and the result of the stage application
// overwrites the previous lookup array. This saves having to allocate a new array copy each time
PipelineBiome[][] tempArray = biomes;
biomes = lookupArray;
lookupArray = tempArray;
// Apply stage to working grid
for(int gridZ = 0; gridZ < gridSize; gridZ = gridZ + 1) {
for(int gridX = 0; gridX < gridSize; gridX = gridX + 1) {
int xIndex = gridOrigin + gridX * gridInterval;
int zIndex = gridOrigin + gridZ * gridInterval;
biomes[xIndex][zIndex] = stage.apply(new ViewPoint(this, gridInterval, gridX, gridZ, xIndex, zIndex, lookupArray));
}
}
}
}
@Override
public PipelineBiome get(int xInChunk, int zInChunk) {
int xIndex = xInChunk + chunkOriginArrayIndex;
int zIndex = zInChunk + chunkOriginArrayIndex;
return biomes[xIndex][zIndex];
}
private int xIndexToWorldCoordinate(int xIndex) {
return (worldOrigin.x() + xIndex - chunkOriginArrayIndex) * worldCoordinateScale;
}
private int zIndexToWorldCoordinate(int zIndex) {
return (worldOrigin.z() + zIndex - chunkOriginArrayIndex) * worldCoordinateScale;
}
protected static int initialSizeToArraySize(int expanderCount, int initialSize) {
int size = initialSize;
for(int i = 0; i < expanderCount; i++) {
size = expandSize(size);
}
return size;
}
protected static int calculateChunkOriginArrayIndex(int totalExpanderCount, List<Stage> stages) {
int finalGridOrigin = calculateFinalGridOrigin(totalExpanderCount, stages);
int initialGridInterval = calculateGridInterval(totalExpanderCount, 0);
// Round the final grid origin up to the nearest multiple of initialGridInterval, such that each
// chunk samples points on the same overall grid.
// Without this, shared chunk borders (required because of adjacent cell reads) will not be identical
// because points would be sampled on grids at different offsets, resulting in artifacts at borders.
return FastMath.ceilToInt((double) finalGridOrigin / initialGridInterval) * initialGridInterval;
}
private static int calculateFinalGridOrigin(int totalExpanderCount, List<Stage> stages) {
int gridOrigin = 0;
int expansionsApplied = 0;
int gridInterval = calculateGridInterval(totalExpanderCount, expansionsApplied);
for (Stage stage : stages) {
if (stage instanceof Expander) {
expansionsApplied++;
gridInterval = calculateGridInterval(totalExpanderCount, expansionsApplied);
}
gridOrigin += stage.maxRelativeReadDistance() * gridInterval;
}
return gridOrigin;
}
protected static int calculateChunkSize(int arraySize, int chunkOriginArrayIndex, int totalExpanderCount) {
return contractBordersFromSize(arraySize, chunkOriginArrayIndex) - (totalExpanderCount > 0 ? 1 : 0);
}
private static int expandSize(int size) {
return size * 2 - 1;
}
private static int contractBordersFromSize(int size, int border) {
return size - border * 2;
}
private static int calculateGridInterval(int totalExpansions, int expansionsApplied) {
return 1 << (totalExpansions - expansionsApplied);
}
private SeededVector getOrigin() {
return worldOrigin;
}
/**
* Represents a point on the operating grid within the biomes array
*/
public static class ViewPoint {
private final BiomeChunkImpl chunk;
private final PipelineBiome biome;
private final int gridInterval;
private final int gridX;
private final int gridZ;
private final int xIndex;
private final int zIndex;
private final PipelineBiome[][] lookupArray;
private ViewPoint(BiomeChunkImpl chunk, int gridInterval, int gridX, int gridZ, int xIndex, int zIndex, PipelineBiome[][] lookupArray) {
this.chunk = chunk;
this.gridInterval = gridInterval;
this.gridX = gridX;
this.gridZ = gridZ;
this.xIndex = xIndex;
this.zIndex = zIndex;
this.lookupArray = lookupArray;
this.biome = lookupArray[xIndex][zIndex];
}
public PipelineBiome getRelativeBiome(int x, int z) {
int lookupXIndex = this.xIndex + x * gridInterval;
int lookupZIndex = this.zIndex + z * gridInterval;
return lookupArray[lookupXIndex][lookupZIndex];
}
public PipelineBiome getBiome() {
return biome;
}
/**
* @return X position of the point relative to the operating grid
*/
public int gridX() {
return gridX;
}
/**
* @return Z position of the point relative to the operating grid
*/
public int gridZ() {
return gridZ;
}
/**
* @return X position of the point in the world
*/
public int worldX() {
return chunk.xIndexToWorldCoordinate(xIndex);
}
/**
* @return Z position of the point in the world
*/
public int worldZ() {
return chunk.zIndexToWorldCoordinate(zIndex);
}
public long worldSeed() {
return chunk.getOrigin().seed();
}
}
}
@@ -0,0 +1,92 @@
package com.dfsek.terra.addons.biome.pipeline.pipeline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeChunk;
import com.dfsek.terra.addons.biome.pipeline.api.Expander;
import com.dfsek.terra.addons.biome.pipeline.api.Pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.SeededVector;
import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
public class PipelineImpl implements Pipeline {
private static final Logger logger = LoggerFactory.getLogger(PipelineImpl.class);
private final Source source;
private final List<Stage> stages;
private final int chunkSize;
private final int expanderCount;
private final int arraySize;
private final int chunkOriginArrayIndex;
private final int resolution;
public PipelineImpl(Source source, List<Stage> stages, int resolution, int idealChunkArraySize) {
this.source = source;
this.stages = stages;
this.resolution = resolution;
this.expanderCount = (int) stages.stream().filter(s -> s instanceof Expander).count();
// Optimize for the ideal array size
int arraySize;
int chunkOriginArrayIndex;
int chunkSize;
int initialSize = 1;
while (true) {
arraySize = BiomeChunkImpl.initialSizeToArraySize(expanderCount, initialSize);
chunkOriginArrayIndex = BiomeChunkImpl.calculateChunkOriginArrayIndex(expanderCount, stages);
chunkSize = BiomeChunkImpl.calculateChunkSize(arraySize, chunkOriginArrayIndex, expanderCount);
if (chunkSize > 1 && arraySize >= idealChunkArraySize) break;
initialSize++;
}
this.arraySize = arraySize;
this.chunkOriginArrayIndex = chunkOriginArrayIndex;
this.chunkSize = chunkSize;
logger.debug("Initialized a new biome pipeline:");
logger.debug("Array size: {} (Target: {})", arraySize, idealChunkArraySize);
logger.debug("Internal array origin: {}", chunkOriginArrayIndex);
logger.debug("Chunk size: {}", chunkSize);
}
@Override
public BiomeChunk generateChunk(SeededVector worldCoordinates) {
return new BiomeChunkImpl(worldCoordinates, this);
}
@Override
public int getChunkSize() {
return chunkSize;
}
@Override
public Source getSource() {
return source;
}
@Override
public List<Stage> getStages() {
return stages;
}
protected int getExpanderCount() {
return expanderCount;
}
protected int getArraySize() {
return arraySize;
}
protected int getChunkOriginArrayIndex() {
return chunkOriginArrayIndex;
}
protected int getResolution() {
return resolution;
}
}
@@ -1,17 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.source;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
public interface BiomeSource {
BiomeDelegate getBiome(double x, double z, long seed);
Iterable<BiomeDelegate> getBiomes();
}
@@ -1,33 +1,27 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.source; package com.dfsek.terra.addons.biome.pipeline.source;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate; import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class SamplerSource implements BiomeSource { public class SamplerSource implements Source {
private final ProbabilityCollection<BiomeDelegate> biomes; private final ProbabilityCollection<PipelineBiome> biomes;
private final NoiseSampler sampler; private final NoiseSampler sampler;
public SamplerSource(ProbabilityCollection<BiomeDelegate> biomes, NoiseSampler sampler) { public SamplerSource(ProbabilityCollection<PipelineBiome> biomes, NoiseSampler sampler) {
this.biomes = biomes; this.biomes = biomes;
this.sampler = sampler; this.sampler = sampler;
} }
@Override @Override
public BiomeDelegate getBiome(double x, double z, long seed) { public PipelineBiome get(long seed, int x, int z) {
return biomes.get(sampler, x, z, seed); return biomes.get(sampler, x, z, seed);
} }
@Override @Override
public Iterable<BiomeDelegate> getBiomes() { public Iterable<PipelineBiome> getBiomes() {
return biomes.getContents(); return biomes.getContents();
} }
} }
@@ -0,0 +1,27 @@
package com.dfsek.terra.addons.biome.pipeline.source;
import java.util.Collections;
import java.util.Set;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.api.Source;
public class SingleSource implements Source {
private final PipelineBiome biome;
public SingleSource(PipelineBiome biome) {
this.biome = biome;
}
@Override
public PipelineBiome get(long seed, int x, int z) {
return biome;
}
@Override
public Set<PipelineBiome> getBiomes() {
return Collections.singleton(biome);
}
}
@@ -0,0 +1,37 @@
package com.dfsek.terra.addons.biome.pipeline.stage.expander;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Expander;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
public class FractalExpander implements Expander {
private final NoiseSampler sampler;
public FractalExpander(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public PipelineBiome fillBiome(ViewPoint viewPoint) {
int xMod2 = viewPoint.gridX() % 2;
int zMod2 = viewPoint.gridZ() % 2;
double roll = sampler.noise(viewPoint.worldSeed(), viewPoint.worldX(), viewPoint.worldZ());
if (xMod2 == 1 && zMod2 == 0) { // Pick one of 2 neighbors on X axis randomly
return roll > 0 ? viewPoint.getRelativeBiome(-1, 0) : viewPoint.getRelativeBiome(1, 0);
} else if (xMod2 == 0 && zMod2 == 1) { // Pick one of 2 neighbors on Z axis randomly
return roll > 0 ? viewPoint.getRelativeBiome(0, -1) : viewPoint.getRelativeBiome(0, 1);
} else { // Pick one of 4 corners randomly
return roll > 0 ?
roll > 0.25 ? viewPoint.getRelativeBiome(-1, 1) : viewPoint.getRelativeBiome(1, 1) :
roll > -0.25 ? viewPoint.getRelativeBiome(-1, -1) : viewPoint.getRelativeBiome(1, -1);
}
}
}
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.vector.Vector2Int;
public class BorderListStage implements Stage {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<PipelineBiome> replaceDefault;
private final String defaultReplace;
private final Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace;
private final Vector2Int[] borderPoints;
public BorderListStage(Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace, String border, String defaultReplace,
NoiseSampler noiseSampler, ProbabilityCollection<PipelineBiome> replaceDefault) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replaceDefault = replaceDefault;
this.defaultReplace = defaultReplace;
this.replace = replace;
List<Vector2Int> points = new ArrayList<>();
for(int x = -1; x <= 1; x++) {
for(int z = -1; z <= 1; z++) {
if(x == 0 && z == 0) continue;
points.add(Vector2Int.of(x, z));
}
}
this.borderPoints = points.toArray(new Vector2Int[0]);
}
@Override
public Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
Set<PipelineBiome> biomeSet = new HashSet<>();
biomes.forEach(biomeSet::add);
biomeSet.addAll(replaceDefault.getContents().stream().filter(Predicate.not(PipelineBiome::isSelf)).toList());
replace.forEach((biome, collection) -> biomeSet.addAll(collection.getContents()));
return biomeSet;
}
@Override
public PipelineBiome apply(ViewPoint viewPoint) {
PipelineBiome center = viewPoint.getBiome();
if(center.getTags().contains(defaultReplace)) {
for(Vector2Int point : borderPoints) {
PipelineBiome current = viewPoint.getRelativeBiome(point.getX(), point.getZ());
if(current != null && current.getTags().contains(border)) {
if(replace.containsKey(center)) {
PipelineBiome replacement = replace.get(center).get(noiseSampler, viewPoint.worldX(), viewPoint.worldZ(),
viewPoint.worldSeed());
return replacement.isSelf() ? center : replacement;
}
PipelineBiome replacement = replaceDefault.get(noiseSampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return replacement.isSelf() ? center : replacement;
}
}
}
return center;
}
@Override
public int maxRelativeReadDistance() {
return 1;
}
}
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.vector.Vector2Int;
public class BorderStage implements Stage {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<PipelineBiome> replace;
private final String replaceTag;
private final Vector2Int[] borderPoints;
public BorderStage(String border, String replaceTag, NoiseSampler noiseSampler, ProbabilityCollection<PipelineBiome> replace) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replace = replace;
this.replaceTag = replaceTag;
List<Vector2Int> points = new ArrayList<>();
for(int x = -1; x <= 1; x++) {
for(int z = -1; z <= 1; z++) {
if(x == 0 && z == 0) continue;
points.add(Vector2Int.of(x, z));
}
}
this.borderPoints = points.toArray(new Vector2Int[0]);
}
@Override
public PipelineBiome apply(ViewPoint viewPoint) {
PipelineBiome center = viewPoint.getBiome();
if(center.getTags().contains(replaceTag)) {
for(Vector2Int point : borderPoints) {
PipelineBiome current = viewPoint.getRelativeBiome(point.getX(), point.getZ());
if(current != null && current.getTags().contains(border)) {
PipelineBiome replacement = replace.get(noiseSampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return replacement.isSelf() ? center : replacement;
}
}
}
return center;
}
@Override
public Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
Set<PipelineBiome> biomeSet = new HashSet<>();
biomes.forEach(biomeSet::add);
biomeSet.addAll(
replace
.getContents()
.stream()
.filter(
Predicate.not(PipelineBiome::isSelf)
)
.toList()
);
return biomeSet;
}
@Override
public int maxRelativeReadDistance() {
return 1;
}
}
@@ -5,27 +5,28 @@
* reference the LICENSE file in this module's root directory. * reference the LICENSE file in this module's root directory.
*/ */
package com.dfsek.terra.addons.biome.pipeline.mutator; package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate; import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class ReplaceListMutator implements BiomeMutator { public class ReplaceListStage implements Stage {
private final Map<BiomeDelegate, ProbabilityCollection<BiomeDelegate>> replace; private final Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace;
private final NoiseSampler sampler; private final NoiseSampler sampler;
private final ProbabilityCollection<BiomeDelegate> replaceDefault; private final ProbabilityCollection<PipelineBiome> replaceDefault;
private final String defaultTag; private final String defaultTag;
public ReplaceListMutator(Map<BiomeDelegate, ProbabilityCollection<BiomeDelegate>> replace, String defaultTag, public ReplaceListStage(Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace, String defaultTag,
ProbabilityCollection<BiomeDelegate> replaceDefault, NoiseSampler sampler) { ProbabilityCollection<PipelineBiome> replaceDefault, NoiseSampler sampler) {
this.replace = replace; this.replace = replace;
this.sampler = sampler; this.sampler = sampler;
this.defaultTag = defaultTag; this.defaultTag = defaultTag;
@@ -33,24 +34,29 @@ public class ReplaceListMutator implements BiomeMutator {
} }
@Override @Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) { public PipelineBiome apply(ViewPoint viewPoint) {
BiomeDelegate center = viewPoint.getBiome(0, 0); PipelineBiome center = viewPoint.getBiome();
if(replace.containsKey(center)) { if(replace.containsKey(center)) {
BiomeDelegate biome = replace.get(center).get(sampler, x, z, seed); PipelineBiome biome = replace.get(center).get(sampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return biome.isSelf() ? viewPoint.getBiome(0, 0) : biome; return biome.isSelf() ? viewPoint.getBiome() : biome;
} }
if(viewPoint.getBiome(0, 0).getTags().contains(defaultTag)) { if(viewPoint.getBiome().getTags().contains(defaultTag)) {
BiomeDelegate biome = replaceDefault.get(sampler, x, z, seed); PipelineBiome biome = replaceDefault.get(sampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return biome.isSelf() ? viewPoint.getBiome(0, 0) : biome; return biome.isSelf() ? viewPoint.getBiome() : biome;
} }
return center; return center;
} }
@Override @Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) { public int maxRelativeReadDistance() {
Set<BiomeDelegate> biomeSet = new HashSet<>(); return 0;
}
@Override
public Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
Set<PipelineBiome> biomeSet = new HashSet<>();
Set<BiomeDelegate> reject = new HashSet<>(); Set<PipelineBiome> reject = new HashSet<>();
biomes.forEach(biome -> { biomes.forEach(biome -> {
if(!biome.getTags().contains(defaultTag) && !replace.containsKey(biome)) { if(!biome.getTags().contains(defaultTag) && !replace.containsKey(biome)) {
@@ -5,42 +5,48 @@
* reference the LICENSE file in this module's root directory. * reference the LICENSE file in this module's root directory.
*/ */
package com.dfsek.terra.addons.biome.pipeline.mutator; package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate; import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class ReplaceMutator implements BiomeMutator { public class ReplaceStage implements Stage {
private final String replaceableTag; private final String replaceableTag;
private final ProbabilityCollection<BiomeDelegate> replace; private final ProbabilityCollection<PipelineBiome> replace;
private final NoiseSampler sampler; private final NoiseSampler sampler;
public ReplaceMutator(String replaceable, ProbabilityCollection<BiomeDelegate> replace, NoiseSampler sampler) { public ReplaceStage(String replaceable, ProbabilityCollection<PipelineBiome> replace, NoiseSampler sampler) {
this.replaceableTag = replaceable; this.replaceableTag = replaceable;
this.replace = replace; this.replace = replace;
this.sampler = sampler; this.sampler = sampler;
} }
@Override @Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) { public PipelineBiome apply(ViewPoint viewPoint) {
if(viewPoint.getBiome(0, 0).getTags().contains(replaceableTag)) { if(viewPoint.getBiome().getTags().contains(replaceableTag)) {
BiomeDelegate biome = replace.get(sampler, x, z, seed); PipelineBiome biome = replace.get(sampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return biome.isSelf() ? viewPoint.getBiome(0, 0) : biome; return biome.isSelf() ? viewPoint.getBiome() : biome;
} }
return viewPoint.getBiome(0, 0); return viewPoint.getBiome();
} }
@Override @Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) { public int maxRelativeReadDistance() {
Set<BiomeDelegate> biomeSet = new HashSet<>(); return 0;
Set<BiomeDelegate> reject = new HashSet<>(); }
@Override
public Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
Set<PipelineBiome> biomeSet = new HashSet<>();
Set<PipelineBiome> reject = new HashSet<>();
biomes.forEach(biome -> { biomes.forEach(biome -> {
if(!biome.getTags().contains(replaceableTag)) { if(!biome.getTags().contains(replaceableTag)) {
biomeSet.add(biome); biomeSet.add(biome);
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.Objects;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
public class SmoothStage implements Stage {
private final NoiseSampler sampler;
public SmoothStage(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public PipelineBiome apply(ViewPoint viewPoint) {
PipelineBiome top = viewPoint.getRelativeBiome(1, 0);
PipelineBiome bottom = viewPoint.getRelativeBiome(-1, 0);
PipelineBiome left = viewPoint.getRelativeBiome(0, 1);
PipelineBiome right = viewPoint.getRelativeBiome(0, -1);
double roll = sampler.noise(viewPoint.worldSeed(), viewPoint.worldX(), viewPoint.worldZ());
boolean vert = Objects.equals(top, bottom);
boolean horiz = Objects.equals(left, right);
if(vert && horiz) {
return roll > 0 ?
roll > 0.25 ? left : right :
roll > -0.25 ? top : bottom;
}
if(vert) {
return roll > 0 ? top : bottom;
}
if(horiz) {
return roll > 0 ? left : right;
}
return viewPoint.getBiome();
}
@Override
public int maxRelativeReadDistance() {
return 1;
}
}
@@ -1,37 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stages;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeExpander;
public class ExpanderStage implements Stage {
private final BiomeExpander expander;
public ExpanderStage(BiomeExpander expander) {
this.expander = expander;
}
@Override
public BiomeHolder apply(BiomeHolder in, long seed) {
return in.expand(expander, seed);
}
@Override
public boolean isExpansion() {
return true;
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
return biomes;
}
}
@@ -1,46 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stages;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
public class MutatorStage implements Stage {
private final BiomeMutator mutator;
public MutatorStage(BiomeMutator mutator) {
this.mutator = mutator;
}
@Override
public BiomeHolder apply(BiomeHolder in, long seed) {
in.mutate(mutator, seed);
return in;
}
@Override
public boolean isExpansion() {
return false;
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
return mutator.getBiomes(biomes);
}
public enum Type {
REPLACE,
REPLACE_LIST,
BORDER,
BORDER_LIST,
SMOOTH
}
}
@@ -11,37 +11,38 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject; import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import org.jetbrains.annotations.NotNull;
public class SingleBiomeProviderAddon implements AddonInitializer {
public class SingleBiomeProviderAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
}; };
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> { Get.platform(),
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry( ((handler, base, platform) -> Init.ofPure(
PROVIDER_REGISTRY_KEY); handler.register(base, ConfigPackPreLoadEvent.class)
providerRegistry.register(addon.key("SINGLE"), SingleBiomeProviderTemplate::new); .then(event -> {
}) Registry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().createRegistry(
.failThrough(); PROVIDER_REGISTRY_KEY);
providerRegistry.register(base.key("SINGLE"), SingleBiomeProviderTemplate::new);
})
.failThrough()))
);
} }
} }
@@ -1,46 +1,48 @@
package com.dfsek.terra.addons.biome.query; package com.dfsek.terra.addons.biome.query;
import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.Collection;
import com.dfsek.terra.addons.biome.query.impl.BiomeTagFlattener; import com.dfsek.terra.addons.biome.query.impl.BiomeTagFlattener;
import com.dfsek.terra.addons.biome.query.impl.BiomeTagHolder; import com.dfsek.terra.addons.biome.query.impl.BiomeTagHolder;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.properties.Context; import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.properties.PropertyKey;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
public class BiomeQueryAPIAddon implements AddonInitializer { public class BiomeQueryAPIAddon implements MonadAddonInitializer {
public static PropertyKey<BiomeTagHolder> BIOME_TAG_KEY = Context.create(BiomeTagHolder.class); public static PropertyKey<BiomeTagHolder> BIOME_TAG_KEY = Context.create(BiomeTagHolder.class);
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
return Do.with(
platform.getEventManager() Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.getHandler(FunctionalEventHandler.class) Get.addon(),
.register(addon, ConfigPackPostLoadEvent.class) ((functionalEventHandler, base) -> Init.ofPure(
.then(event -> { functionalEventHandler.register(base, ConfigPackPostLoadEvent.class)
Collection<Biome> biomes = event .then(event -> {
.getPack() Collection<Biome> biomes = event
.getRegistry(Biome.class) .getPack()
.entries(); .getRegistry(Biome.class)
.entries();
BiomeTagFlattener flattener = new BiomeTagFlattener(biomes
.stream() BiomeTagFlattener flattener = new BiomeTagFlattener(
.flatMap(biome -> biome.getTags().stream()) biomes.stream()
.toList()); .flatMap(biome -> biome.getTags().stream())
.toList());
biomes.forEach(biome -> biome.getContext().put(BIOME_TAG_KEY, new BiomeTagHolder(biome, flattener)));
}) biomes.forEach(biome -> biome.getContext()
.global(); .put(BIOME_TAG_KEY, new BiomeTagHolder(biome, flattener)));
})
.global()
)));
} }
} }
@@ -2,11 +2,4 @@ version = version("1.1.0")
dependencies { dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader")) compileOnlyApi(project(":common:addons:manifest-addon-loader"))
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
relocate("net.jafama", "com.dfsek.terra.addons.chunkgenerator.lib.jafama")
} }
@@ -14,60 +14,58 @@ import com.dfsek.terra.addons.chunkgenerator.config.palette.BiomePaletteTemplate
import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo; import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.config.palette.SlantLayer; import com.dfsek.terra.addons.chunkgenerator.config.palette.SlantLayer;
import com.dfsek.terra.addons.chunkgenerator.generation.NoiseChunkGenerator3D; import com.dfsek.terra.addons.chunkgenerator.generation.NoiseChunkGenerator3D;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.properties.Context; import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.properties.PropertyKey;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.generic.Construct;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.chunk.generation.util.provider.ChunkGeneratorProvider;
import org.jetbrains.annotations.NotNull;
public class NoiseChunkGenerator3DAddon implements AddonInitializer { public class NoiseChunkGenerator3DAddon implements MonadAddonInitializer {
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
PropertyKey<PaletteInfo> paletteInfoPropertyKey = Context.create(PaletteInfo.class); PropertyKey<PaletteInfo> paletteInfoPropertyKey = Context.create(PaletteInfo.class);
PropertyKey<BiomeNoiseProperties> noisePropertiesPropertyKey = Context.create(BiomeNoiseProperties.class); PropertyKey<BiomeNoiseProperties> noisePropertiesPropertyKey = Context.create(BiomeNoiseProperties.class);
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.priority(1000) Get.platform(),
.then(event -> { ((handler, base, platform) -> Init.ofPure(Construct.construct(() -> {
NoiseChunkGeneratorPackConfigTemplate config = event.loadTemplate(new NoiseChunkGeneratorPackConfigTemplate()); handler.register(base, ConfigPackPreLoadEvent.class)
.priority(1000)
event.getPack() .then(event -> {
.getOrCreateRegistry(ChunkGeneratorProvider.class) NoiseChunkGeneratorPackConfigTemplate config = event.loadTemplate(new NoiseChunkGeneratorPackConfigTemplate());
.register(addon.key("NOISE_3D"),
pack -> new NoiseChunkGenerator3D(pack, platform, config.getElevationBlend(), event.getPack()
config.getHorizontalRes(), .createRegistry(ChunkGeneratorProvider.class)
config.getVerticalRes(), noisePropertiesPropertyKey, .register(base.key("NOISE_3D"),
paletteInfoPropertyKey)); pack -> new NoiseChunkGenerator3D(pack, platform, config.getElevationBlend(),
event.getPack() config.getHorizontalRes(),
.applyLoader(SlantLayer.class, SlantLayer::new); config.getVerticalRes(), noisePropertiesPropertyKey,
}) paletteInfoPropertyKey));
.failThrough(); event.getPack()
.applyLoader(SlantLayer.class, SlantLayer::new);
platform.getEventManager() })
.getHandler(FunctionalEventHandler.class) .failThrough();
.register(addon, ConfigurationLoadEvent.class) return handler.register(base, ConfigurationLoadEvent.class)
.then(event -> { .then(event -> {
if(event.is(Biome.class)) { if(event.is(Biome.class)) {
event.getLoadedObject(Biome.class).getContext().put(paletteInfoPropertyKey, event.getLoadedObject(Biome.class).getContext().put(paletteInfoPropertyKey,
event.load(new BiomePaletteTemplate(platform)).get()); event.load(new BiomePaletteTemplate(platform)).get());
event.getLoadedObject(Biome.class).getContext().put(noisePropertiesPropertyKey, event.getLoadedObject(Biome.class).getContext().put(noisePropertiesPropertyKey,
event.load(new BiomeNoiseConfigTemplate()).get()); event.load(new BiomeNoiseConfigTemplate()).get());
} }
}) })
.failThrough(); .failThrough();
}))));
} }
} }
@@ -75,15 +75,15 @@ public class BiomePaletteTemplate implements ObjectTemplate<PaletteInfo> {
} }
TreeMap<Double, PaletteHolder> slantLayers = new TreeMap<>(); TreeMap<Double, PaletteHolder> slantLayers = new TreeMap<>();
double minThreshold = Double.MAX_VALUE; double maxThreshold = Double.MIN_VALUE;
for(SlantLayer layer : slant) { for(SlantLayer layer : slant) {
double threshold = layer.getThreshold(); double threshold = layer.getThreshold();
if(threshold < minThreshold) minThreshold = threshold; if(threshold > maxThreshold) maxThreshold = threshold;
slantLayers.put(threshold, layer.getPalette()); slantLayers.put(threshold, layer.getPalette());
} }
return new PaletteInfo(builder.build(), SlantHolder.of(slantLayers, minThreshold), oceanPalette, seaLevel, slantDepth, return new PaletteInfo(builder.build(), SlantHolder.of(slantLayers, maxThreshold), oceanPalette, seaLevel, slantDepth,
updatePalette); updatePalette);
} }
} }
@@ -19,7 +19,6 @@ import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider; import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.properties.PropertyKey;
import com.dfsek.terra.api.util.Column; import com.dfsek.terra.api.util.Column;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
@@ -10,6 +10,7 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math;
import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo; import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder; import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.chunk.generation.util.Palette; import com.dfsek.terra.api.world.chunk.generation.util.Palette;
@@ -22,25 +23,32 @@ public final class PaletteUtil {
public static Palette getPalette(int x, int y, int z, Sampler3D sampler, PaletteInfo paletteInfo, int depth) { public static Palette getPalette(int x, int y, int z, Sampler3D sampler, PaletteInfo paletteInfo, int depth) {
SlantHolder slant = paletteInfo.slantHolder(); SlantHolder slant = paletteInfo.slantHolder();
if(!slant.isEmpty() && depth <= paletteInfo.maxSlantDepth()) { if(!slant.isEmpty() && depth <= paletteInfo.maxSlantDepth()) {
double slope = derivative(sampler, x, y, z); double dot = surfaceNormalDotProduct(sampler, x, y, z);
if(slope > slant.getMinSlope()) { if(dot <= slant.getMaxSlant()) {
return slant.getPalette(slope).getPalette(y); return slant.getPalette(dot).getPalette(y);
} }
} }
return paletteInfo.paletteHolder().getPalette(y); return paletteInfo.paletteHolder().getPalette(y);
} }
public static double derivative(Sampler3D sampler, double x, double y, double z) { private static final Vector3[] samplePoints = {
double baseSample = sampler.sample(x, y, z); Vector3.of(0, 0, -DERIVATIVE_DIST),
Vector3.of(0, 0, DERIVATIVE_DIST),
double xVal1 = (sampler.sample(x + DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST; Vector3.of(0, -DERIVATIVE_DIST, 0),
double xVal2 = (sampler.sample(x - DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST; Vector3.of(0, DERIVATIVE_DIST, 0),
double zVal1 = (sampler.sample(x, y, z + DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST; Vector3.of(-DERIVATIVE_DIST, 0, 0),
double zVal2 = (sampler.sample(x, y, z - DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST; Vector3.of(DERIVATIVE_DIST, 0, 0),
double yVal1 = (sampler.sample(x, y + DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST; };
double yVal2 = (sampler.sample(x, y - DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
private static final Vector3 direction = Vector3.of(0, 1, 0);
return Math.sqrt(((xVal2 - xVal1) * (xVal2 - xVal1)) + ((zVal2 - zVal1) * (zVal2 - zVal1)) + ((yVal2 - yVal1) * (yVal2 - yVal1)));
public static double surfaceNormalDotProduct(Sampler3D sampler, double x, double y, double z) {
Vector3.Mutable surfaceNormalApproximation = Vector3.Mutable.of(0, 0, 0);
for(Vector3 point : samplePoints) {
double scalar = -sampler.sample(x+point.getX(), y+point.getY(), z+point.getZ());
surfaceNormalApproximation.add(point.mutable().multiply(scalar));
}
return direction.dot(surfaceNormalApproximation.normalize());
} }
} }
@@ -7,6 +7,9 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation; package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import com.dfsek.terra.api.util.MathUtil;
/** /**
* Class for bilinear interpolation of values arranged on a unit square. * Class for bilinear interpolation of values arranged on a unit square.
*/ */
@@ -28,19 +31,6 @@ public class Interpolator {
this.v3 = v3; this.v3 = v3;
} }
/**
* 1D Linear interpolation between 2 points 1 unit apart.
*
* @param t - Distance from v0. Total distance between v0 and v1 is 1 unit.
* @param v0 - Value at v0.
* @param v1 - Value at v1.
*
* @return double - The interpolated value.
*/
public static double lerp(double t, double v0, double v1) {
return v0 + t * (v1 - v0);
}
/** /**
* 2D Bilinear interpolation between 4 points on a unit square. * 2D Bilinear interpolation between 4 points on a unit square.
* *
@@ -50,8 +40,8 @@ public class Interpolator {
* @return double - The interpolated value. * @return double - The interpolated value.
*/ */
public double bilerp(double s, double t) { public double bilerp(double s, double t) {
double v01 = lerp(s, v0, v1); double v01 = MathUtil.lerp(s, v0, v1);
double v23 = lerp(s, v2, v3); double v23 = MathUtil.lerp(s, v2, v3);
return lerp(t, v01, v23); return MathUtil.lerp(t, v01, v23);
} }
} }
@@ -7,6 +7,9 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation; package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import com.dfsek.terra.api.util.MathUtil;
/** /**
* Class for bilinear interpolation of values arranged on a unit square. * Class for bilinear interpolation of values arranged on a unit square.
*/ */
@@ -34,6 +37,6 @@ public class Interpolator3 {
} }
public double trilerp(double x, double y, double z) { public double trilerp(double x, double y, double z) {
return Interpolator.lerp(x, top.bilerp(y, z), bottom.bilerp(y, z)); return MathUtil.lerp(x, top.bilerp(y, z), bottom.bilerp(y, z));
} }
} }
@@ -1,13 +1,13 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation; package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import com.dfsek.terra.api.util.MathUtil;
import net.jafama.FastMath; import net.jafama.FastMath;
import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties;
import com.dfsek.terra.api.properties.PropertyKey; import com.dfsek.terra.api.properties.PropertyKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import static com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.Interpolator.lerp;
public class LazilyEvaluatedInterpolator { public class LazilyEvaluatedInterpolator {
private final Double[] samples; // private final Double[] samples; //
@@ -84,10 +84,10 @@ public class LazilyEvaluatedInterpolator {
double xFrac = (double) (x % horizontalRes) / horizontalRes; double xFrac = (double) (x % horizontalRes) / horizontalRes;
double zFrac = (double) (z % horizontalRes) / horizontalRes; double zFrac = (double) (z % horizontalRes) / horizontalRes;
double lerp_bottom_0 = lerp(zFrac, sample_0_0_0, sample_0_0_1); double lerp_bottom_0 = MathUtil.lerp(zFrac, sample_0_0_0, sample_0_0_1);
double lerp_bottom_1 = lerp(zFrac, sample_1_0_0, sample_1_0_1); double lerp_bottom_1 = MathUtil.lerp(zFrac, sample_1_0_0, sample_1_0_1);
double lerp_bottom = lerp(xFrac, lerp_bottom_0, lerp_bottom_1); double lerp_bottom = MathUtil.lerp(xFrac, lerp_bottom_0, lerp_bottom_1);
if(yRange) { // we can do bilerp if(yRange) { // we can do bilerp
return lerp_bottom; return lerp_bottom;
@@ -103,11 +103,11 @@ public class LazilyEvaluatedInterpolator {
double sample_1_1_0 = sample(xIndex + 1, yIndex + 1, zIndex, x + horizontalRes, y + verticalRes, z); double sample_1_1_0 = sample(xIndex + 1, yIndex + 1, zIndex, x + horizontalRes, y + verticalRes, z);
double sample_1_1_1 = sample(xIndex + 1, yIndex + 1, zIndex + 1, x + horizontalRes, y + verticalRes, z + horizontalRes); double sample_1_1_1 = sample(xIndex + 1, yIndex + 1, zIndex + 1, x + horizontalRes, y + verticalRes, z + horizontalRes);
double lerp_top_0 = lerp(zFrac, sample_0_1_0, sample_0_1_1); double lerp_top_0 = MathUtil.lerp(zFrac, sample_0_1_0, sample_0_1_1);
double lerp_top_1 = lerp(zFrac, sample_1_1_0, sample_1_1_1); double lerp_top_1 = MathUtil.lerp(zFrac, sample_1_1_0, sample_1_1_1);
double lerp_top = lerp(xFrac, lerp_top_0, lerp_top_1); double lerp_top = MathUtil.lerp(xFrac, lerp_top_0, lerp_top_1);
return lerp(yFrac, lerp_bottom, lerp_top); return MathUtil.lerp(yFrac, lerp_bottom, lerp_top);
} }
} }
@@ -14,39 +14,39 @@ import java.util.TreeMap;
public class SlantHolder { public class SlantHolder {
private final TreeMap<Double, PaletteHolder> layers; private final TreeMap<Double, PaletteHolder> layers;
private final double minSlope; private final double maxSlant;
private SlantHolder(TreeMap<Double, PaletteHolder> layers, double minSlope) { private SlantHolder(TreeMap<Double, PaletteHolder> layers, double maxSlant) {
this.layers = layers; this.layers = layers;
this.minSlope = minSlope; this.maxSlant = maxSlant;
} }
public static SlantHolder of(TreeMap<Double, PaletteHolder> layers, double minSlope) { public static SlantHolder of(TreeMap<Double, PaletteHolder> layers, double maxSlant) {
if(layers.size() == 1) { if(layers.size() == 1) {
Entry<Double, PaletteHolder> firstEntry = layers.firstEntry(); Entry<Double, PaletteHolder> firstEntry = layers.firstEntry();
return new Single(firstEntry.getValue(), minSlope); return new Single(firstEntry.getValue(), maxSlant);
} }
return new SlantHolder(layers, minSlope); return new SlantHolder(layers, maxSlant);
} }
public boolean isEmpty() { public boolean isEmpty() {
return layers.isEmpty(); return layers.isEmpty();
} }
public PaletteHolder getPalette(double slope) { public PaletteHolder getPalette(double slant) {
return layers.floorEntry(slope).getValue(); return layers.ceilingEntry(slant).getValue();
} }
public double getMinSlope() { public double getMaxSlant() {
return minSlope; return maxSlant;
} }
private static final class Single extends SlantHolder { private static final class Single extends SlantHolder {
private final PaletteHolder layers; private final PaletteHolder layers;
public Single(PaletteHolder layers, double minSlope) { public Single(PaletteHolder layers, double maxSlant) {
super(of(minSlope, layers), minSlope); super(of(maxSlant, layers), maxSlant);
this.layers = layers; this.layers = layers;
} }
@@ -57,7 +57,7 @@ public class SlantHolder {
} }
@Override @Override
public PaletteHolder getPalette(double slope) { public PaletteHolder getPalette(double slant) {
return layers; return layers;
} }
} }
@@ -3,67 +3,75 @@ package com.dfsek.terra.addons.commands.addons;
import cloud.commandframework.ArgumentDescription; import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.CommandManager; import cloud.commandframework.CommandManager;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.command.CommandSender; import com.dfsek.terra.api.command.CommandSender;
import com.dfsek.terra.api.command.arguments.RegistryArgument; import com.dfsek.terra.api.command.arguments.RegistryArgument;
import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent; import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject; import com.dfsek.terra.api.util.function.monad.Monad;
import org.jetbrains.annotations.NotNull;
public class AddonsCommandAddon implements AddonInitializer { public class AddonsCommandAddon implements MonadAddonInitializer {
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, CommandRegistrationEvent.class) Get.addon(),
.then(event -> { Get.platform(),
CommandManager<CommandSender> manager = event.getCommandManager(); ((functionalEventHandler, base, platform) -> Init.unit() /* Init.ofPure(
functionalEventHandler
manager.command( .register(base, CommandRegistrationEvent.class)
manager.commandBuilder("addons", ArgumentDescription.of("List installed Terra addons")) .then(event -> {
.permission("terra.addons") CommandManager<CommandSender> manager = event.getCommandManager();
.handler(context -> {
StringBuilder addons = new StringBuilder("Installed addons:\n"); manager.command(
platform.getAddons() manager.commandBuilder("addons", ArgumentDescription.of(
.forEach(addon -> addons "List installed Terra addons"))
.append(" - ") .permission("terra.addons")
.append(addon.getID()) .handler(context -> {
.append('@') StringBuilder addons = new StringBuilder(
.append(addon.getVersion().getFormatted()) "Installed addons:\n");
.append('\n')); platform.addons()
context.getSender().sendMessage(addons.toString()); .forEach(addon -> addons
}) .append(" - ")
) .append(addon.getID())
.command( .append('@')
manager.commandBuilder("addons") .append(addon.getVersion().getFormatted())
.argument(RegistryArgument.of("addon", platform.getAddons())) .append('\n'));
.permission("terra.addons.info") context.getSender().sendMessage(addons.toString());
.handler(context -> { })
BaseAddon addon = context.get("addon"); )
StringBuilder addonInfo = new StringBuilder("Addon ").append(addon.getID()).append('\n'); .command(
manager.commandBuilder("addons")
addonInfo.append("Version: ").append(addon.getVersion().getFormatted()).append('\n'); .argument(
RegistryArgument.of("addon", platform.addons()))
addonInfo.append("Dependencies:\n"); .permission("terra.addons.info")
addon.getDependencies().forEach((id, versions) -> addonInfo .handler(context -> {
.append(" - ") BaseAddon addon = context.get("addon");
.append(id) StringBuilder addonInfo = new StringBuilder(
.append('@') "Addon ").append(addon.getID()).append('\n');
.append(versions.getFormatted())
.append('\n')); addonInfo.append("Version: ").append(
context.getSender().sendMessage(addonInfo.toString()); addon.getVersion().getFormatted()).append('\n');
})
); addonInfo.append("Dependencies:\n");
}); addon.getDependencies().forEach(
(id, versions) -> addonInfo
.append(" - ")
.append(id)
.append('@')
.append(versions.getFormatted())
.append('\n'));
context.getSender().sendMessage(addonInfo.toString());
})
);
}))*/)
);
} }
} }
@@ -2,87 +2,87 @@ package com.dfsek.terra.addons.commands.packs;
import cloud.commandframework.ArgumentDescription; import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.CommandManager; import cloud.commandframework.CommandManager;
import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.util.function.monad.Monad;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.command.CommandSender; import com.dfsek.terra.api.command.CommandSender;
import com.dfsek.terra.api.command.arguments.RegistryArgument; import com.dfsek.terra.api.command.arguments.RegistryArgument;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent; import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
public class PacksCommandAddon implements AddonInitializer { public class PacksCommandAddon implements MonadAddonInitializer {
private static final Logger logger = LoggerFactory.getLogger(PacksCommandAddon.class); private static final Logger logger = LoggerFactory.getLogger(PacksCommandAddon.class);
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, CommandRegistrationEvent.class) Get.addon(),
.then(event -> { Get.platform(),
CommandManager<CommandSender> manager = event.getCommandManager(); ((functionalEventHandler, base, platform) -> Init.ofPure(
functionalEventHandler.register(base, CommandRegistrationEvent.class)
manager.command( .then(event -> {
manager.commandBuilder("packs", ArgumentDescription.of("List installed config packs")) CommandManager<CommandSender> manager = event.getCommandManager();
.permission("terra.packs")
.handler(context -> { manager.command(
StringBuilder packs = new StringBuilder("Installed packs:\n"); manager.commandBuilder("packs", ArgumentDescription.of("List installed config packs"))
platform.getConfigRegistry().forEach(pack -> packs.append(" - ") .permission("terra.packs")
.append(pack.getID()) .handler(context -> {
.append('@') StringBuilder packs = new StringBuilder("Installed packs:\n");
.append(pack.getVersion().getFormatted())); platform.getConfigRegistry().forEach(pack -> packs.append(" - ")
context.getSender().sendMessage(packs.toString()); .append(pack.getID())
}) .append('@')
) .append(pack.getVersion().getFormatted()));
.command( context.getSender().sendMessage(packs.toString());
manager.commandBuilder("packs") })
.literal("info", ArgumentDescription.of("Get information about a pack")) )
.permission("terra.packs.info") .command(
.argument(RegistryArgument.of("pack", platform.getConfigRegistry())) manager.commandBuilder("packs")
.handler(context -> { .literal("info", ArgumentDescription.of("Get information about a pack"))
ConfigPack pack = context.get("pack"); .permission("terra.packs.info")
StringBuilder packInfo = new StringBuilder("Pack ").append(pack.getID()).append('\n'); .argument(RegistryArgument.of("pack", platform.getConfigRegistry()))
.handler(context -> {
packInfo.append("Version: ").append(pack.getVersion().getFormatted()).append('\n'); ConfigPack pack = context.get("pack");
packInfo.append("Author: ").append(pack.getAuthor()).append('\n'); StringBuilder packInfo = new StringBuilder("Pack ").append(pack.getID()).append('\n');
packInfo.append("Addon Dependencies:\n"); packInfo.append("Version: ").append(pack.getVersion().getFormatted()).append('\n');
pack.addons().forEach((id, versions) -> packInfo packInfo.append("Author: ").append(pack.getAuthor()).append('\n');
.append(" - ")
.append(id.getID()) packInfo.append("Addon Dependencies:\n");
.append('@') pack.addons().forEach((id, versions) -> packInfo
.append(versions.getFormatted()) .append(" - ")
.append('\n')); .append(id.getID())
context.getSender().sendMessage(packInfo.toString()); .append('@')
})) .append(versions.getFormatted())
.command( .append('\n'));
manager.commandBuilder("packs") context.getSender().sendMessage(packInfo.toString());
.literal("reload", ArgumentDescription.of("Reload config packs")) }))
.permission("terra.packs.reload") .command(
.handler(context -> { manager.commandBuilder("packs")
context.getSender().sendMessage("Reloading Terra..."); .literal("reload", ArgumentDescription.of("Reload config packs"))
logger.info("Reloading Terra..."); .permission("terra.packs.reload")
if(platform.reload()) { .handler(context -> {
logger.info("Terra reloaded successfully."); context.getSender().sendMessage("Reloading Terra...");
context.getSender().sendMessage("Terra reloaded successfully."); logger.info("Reloading Terra...");
} else { if(platform.reload()) {
logger.error("Terra failed to reload."); logger.info("Terra reloaded successfully.");
context.getSender().sendMessage( context.getSender().sendMessage("Terra reloaded successfully.");
"Terra failed to reload. See logs for more information."); } else {
} logger.error("Terra failed to reload.");
})); context.getSender().sendMessage(
}); "Terra failed to reload. See logs for more information.");
}
}));
})))
);
} }
} }
@@ -2,10 +2,19 @@ package com.dfsek.terra.addons.commands.profiler;
import cloud.commandframework.ArgumentDescription; import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.CommandManager; import cloud.commandframework.CommandManager;
import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.util.function.monad.Monad;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.command.CommandSender; import com.dfsek.terra.api.command.CommandSender;
@@ -14,61 +23,58 @@ import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject; import com.dfsek.terra.api.inject.annotations.Inject;
public class ProfilerCommandAddon implements AddonInitializer { public class ProfilerCommandAddon implements MonadAddonInitializer {
private static final Logger logger = LoggerFactory.getLogger(ProfilerCommandAddon.class); private static final Logger logger = LoggerFactory.getLogger(ProfilerCommandAddon.class);
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, CommandRegistrationEvent.class) Get.addon(),
.then(event -> { Get.platform(),
CommandManager<CommandSender> manager = event.getCommandManager(); ((handler, base, platform) -> Init.ofPure(
manager handler.register(base, CommandRegistrationEvent.class)
.command( .then(event -> {
manager.commandBuilder("profiler", ArgumentDescription.of("Access the profiler")) CommandManager<CommandSender> manager = event.getCommandManager();
.literal("start", ArgumentDescription.of("Start profiling"), "st") manager
.permission("terra.profiler.start") .command(
.handler(context -> { manager.commandBuilder("profiler", ArgumentDescription.of("Access the profiler"))
platform.getProfiler().start(); .literal("start", ArgumentDescription.of("Start profiling"), "st")
context.getSender().sendMessage("Profiling started."); .permission("terra.profiler.start")
})) .handler(context -> {
.command( platform.getProfiler().start();
manager.commandBuilder("profiler", ArgumentDescription.of("Access the profiler")) context.getSender().sendMessage("Profiling started.");
.literal("stop", ArgumentDescription.of("Stop profiling"), "s") }))
.permission("terra.profiler.stop") .command(
.handler(context -> { manager.commandBuilder("profiler", ArgumentDescription.of("Access the profiler"))
platform.getProfiler().stop(); .literal("stop", ArgumentDescription.of("Stop profiling"), "s")
context.getSender().sendMessage("Profiling stopped."); .permission("terra.profiler.stop")
})) .handler(context -> {
.command( platform.getProfiler().stop();
manager.commandBuilder("profiler", ArgumentDescription.of("Access the profiler")) context.getSender().sendMessage("Profiling stopped.");
.literal("query", ArgumentDescription.of("Query profiler results"), "q") }))
.permission("terra.profiler.query") .command(
.handler(context -> { manager.commandBuilder("profiler", ArgumentDescription.of("Access the profiler"))
StringBuilder data = new StringBuilder("Terra Profiler data: \n"); .literal("query", ArgumentDescription.of("Query profiler results"), "q")
platform.getProfiler().getTimings().forEach((id, timings) -> data.append(id) .permission("terra.profiler.query")
.append(": ") .handler(context -> {
.append(timings.toString()) StringBuilder data = new StringBuilder("Terra Profiler data: \n");
.append('\n')); platform.getProfiler().getTimings().forEach((id, timings) -> data.append(id)
logger.info(data.toString()); .append(": ")
context.getSender().sendMessage("Profiling data dumped to console."); .append(timings.toString())
})) .append('\n'));
.command( logger.info(data.toString());
manager.commandBuilder("profiler", ArgumentDescription.of("Access the profiler")) context.getSender().sendMessage("Profiling data dumped to console.");
.literal("reset", ArgumentDescription.of("Reset the profiler"), "r") }))
.permission("terra.profiler.reset") .command(
.handler(context -> { manager.commandBuilder("profiler", ArgumentDescription.of("Access the profiler"))
platform.getProfiler().reset(); .literal("reset", ArgumentDescription.of("Reset the profiler"), "r")
context.getSender().sendMessage("Profiler reset."); .permission("terra.profiler.reset")
})); .handler(context -> {
}); platform.getProfiler().reset();
context.getSender().sendMessage("Profiler reset.");
}));
})))
);
} }
} }
@@ -6,62 +6,61 @@ import cloud.commandframework.arguments.standard.EnumArgument;
import cloud.commandframework.arguments.standard.LongArgument; import cloud.commandframework.arguments.standard.LongArgument;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.command.CommandSender; import com.dfsek.terra.api.command.CommandSender;
import com.dfsek.terra.api.command.arguments.RegistryArgument; import com.dfsek.terra.api.command.arguments.RegistryArgument;
import com.dfsek.terra.api.entity.Entity; import com.dfsek.terra.api.entity.Entity;
import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent; import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.Registry; import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.structure.Structure; import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.util.Rotation; import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import org.jetbrains.annotations.NotNull;
public class StructureCommandAddon implements AddonInitializer {
@Inject public class StructureCommandAddon implements MonadAddonInitializer {
private Platform platform;
@Inject
private BaseAddon addon;
private static Registry<Structure> getStructureRegistry(CommandContext<CommandSender> sender) { private static Registry<Structure> getStructureRegistry(CommandContext<CommandSender> sender) {
return sender.getSender().getEntity().orElseThrow().world().getPack().getRegistry(Structure.class); return sender.getSender().getEntity().orElseThrow().world().getPack().getRegistry(Structure.class);
} }
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, CommandRegistrationEvent.class) Get.addon(),
.then(event -> { ((handler, base) -> Init.ofPure(
CommandManager<CommandSender> manager = event.getCommandManager(); handler.register(base, CommandRegistrationEvent.class)
.then(event -> {
manager.command( CommandManager<CommandSender> manager = event.getCommandManager();
manager.commandBuilder("structures", ArgumentDescription.of("Manage or generate structures"))
.literal("generate") manager.command(
.argument(RegistryArgument.builder("structure", manager.commandBuilder("structures", ArgumentDescription.of("Manage or generate structures"))
StructureCommandAddon::getStructureRegistry, .literal("generate")
TypeKey.of(Structure.class))) .argument(RegistryArgument.builder("structure",
.argument(LongArgument.optional("seed", 0)) StructureCommandAddon::getStructureRegistry,
.argument(EnumArgument.optional(Rotation.class, "rotation", Rotation.NONE)) TypeKey.of(Structure.class)))
.handler(context -> { .argument(LongArgument.optional("seed", 0))
Structure structure = context.get("structure"); .argument(EnumArgument.optional(Rotation.class, "rotation", Rotation.NONE))
Entity sender = context.getSender().getEntity().orElseThrow(); .handler(context -> {
structure.generate( Structure structure = context.get("structure");
sender.position().toInt(), Entity sender = context.getSender().getEntity().orElseThrow();
sender.world(), structure.generate(
((Long) context.get("seed") == 0) ? new Random() : new Random(context.get("seed")), sender.position().toInt(),
context.get("rotation") sender.world(),
); context.get("rotation"));
}) })
.permission("terra.structures.generate") .permission("terra.structures.generate")
); );
}); })))
);
} }
} }
@@ -9,30 +9,35 @@ package com.dfsek.terra.addons.biome;
import com.dfsek.terra.addons.biome.holder.PaletteHolder; import com.dfsek.terra.addons.biome.holder.PaletteHolder;
import com.dfsek.terra.addons.biome.holder.PaletteHolderLoader; import com.dfsek.terra.addons.biome.holder.PaletteHolderLoader;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject; import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.util.function.monad.Monad;
import org.jetbrains.annotations.NotNull;
public class BiomeAddon implements AddonInitializer { public class BiomeAddon implements MonadAddonInitializer {
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> { Get.platform(),
event.getPack().registerConfigType(new BiomeConfigType(event.getPack()), addon.key("BIOME"), 1000); ((functionalEventHandler, base, platform) -> Init.ofPure(
event.getPack().applyLoader(PaletteHolder.class, new PaletteHolderLoader()); functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
}) .then(event -> {
.failThrough(); event.getPack().registerConfigType(new BiomeConfigType(event.getPack()),
base.key("BIOME"), 1000);
event.getPack().applyLoader(PaletteHolder.class, new PaletteHolderLoader());
})
.failThrough()
)));
} }
} }
@@ -8,9 +8,6 @@
package com.dfsek.terra.addons.biome; package com.dfsek.terra.addons.biome;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
@@ -8,8 +8,6 @@
package com.dfsek.terra.addons.biome; package com.dfsek.terra.addons.biome;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
@@ -22,6 +20,6 @@ public class BiomeFactory implements ConfigFactory<BiomeTemplate, Biome> {
@Override @Override
public Biome build(BiomeTemplate template, Platform platform) { public Biome build(BiomeTemplate template, Platform platform) {
return new UserDefinedBiome(template.getVanilla(), template); return new UserDefinedBiome(template);
} }
} }
@@ -19,9 +19,7 @@ import java.util.Set;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.AbstractableTemplate; import com.dfsek.terra.api.config.AbstractableTemplate;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.biome.PlatformBiome;
@SuppressWarnings({ "FieldMayBeFinal", "unused" }) @SuppressWarnings({ "FieldMayBeFinal", "unused" })
@@ -37,13 +35,11 @@ public class BiomeTemplate implements AbstractableTemplate, ValidatedConfigTempl
@Default @Default
private List<String> extended = Collections.emptyList(); private List<String> extended = Collections.emptyList();
@Value("vanilla")
private @Meta PlatformBiome vanilla;
@Value("color") @Value("color")
@Final @Final
@Default @Default
private @Meta int color = 0; private @Meta int color = 0;
@Value("tags") @Value("tags")
@Default @Default
private @Meta Set<@Meta String> tags = new HashSet<>(); private @Meta Set<@Meta String> tags = new HashSet<>();
@@ -77,8 +73,4 @@ public class BiomeTemplate implements AbstractableTemplate, ValidatedConfigTempl
public String getID() { public String getID() {
return id; return id;
} }
public PlatformBiome getVanilla() {
return vanilla;
}
} }
@@ -7,6 +7,7 @@
package com.dfsek.terra.addons.biome; package com.dfsek.terra.addons.biome;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import com.dfsek.terra.api.properties.Context; import com.dfsek.terra.api.properties.Context;
@@ -18,16 +19,14 @@ import com.dfsek.terra.api.world.biome.PlatformBiome;
* Class representing a config-defined biome * Class representing a config-defined biome
*/ */
public class UserDefinedBiome implements Biome { public class UserDefinedBiome implements Biome {
private final PlatformBiome vanilla;
private final String id; private final String id;
private final BiomeTemplate config; private final BiomeTemplate config;
private final int color; private final int color;
private final Set<String> tags; private final Set<String> tags;
private final Context context = new Context(); private final Context context = new Context();
private PlatformBiome platformBiome;
public UserDefinedBiome(PlatformBiome vanilla, BiomeTemplate config) { public UserDefinedBiome(BiomeTemplate config) {
this.vanilla = vanilla;
this.id = config.getID(); this.id = config.getID();
this.config = config; this.config = config;
this.color = config.getColor(); this.color = config.getColor();
@@ -41,14 +40,18 @@ public class UserDefinedBiome implements Biome {
return "{BIOME:" + getID() + "}"; return "{BIOME:" + getID() + "}";
} }
/**
* Gets the Vanilla biomes to represent the custom biome.
*
* @return Collection of biomes to represent the custom biome.
*/
@Override @Override
public PlatformBiome getPlatformBiome() { public Optional<PlatformBiome> getPlatformBiome() {
return vanilla; return Optional.ofNullable(platformBiome);
}
@Override
public void setPlatformBiome(PlatformBiome biome) {
if(platformBiome != null) {
throw new IllegalStateException("Platform biome already set");
}
this.platformBiome = biome;
} }
@Override @Override
@@ -2,11 +2,4 @@ version = version("1.0.0")
dependencies { dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader")) compileOnlyApi(project(":common:addons:manifest-addon-loader"))
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
relocate("net.jafama", "com.dfsek.terra.addons.feature.distributor.lib.jafama")
} }
@@ -14,55 +14,54 @@ import java.util.function.Supplier;
import com.dfsek.terra.addons.feature.distributor.config.AndDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.AndDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.NoDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.NoDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.OrDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.OrDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.PaddedGridDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.PaddedGridSamplerDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.PointSetDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.PointSetDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.SamplerDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.SamplerDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.XorDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.XorDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.YesDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.YesDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.util.Point; import com.dfsek.terra.addons.feature.distributor.util.Point;
import com.dfsek.terra.addons.feature.distributor.util.PointTemplate; import com.dfsek.terra.addons.feature.distributor.util.PointTemplate;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
public class DistributorAddon implements AddonInitializer { public class DistributorAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<Distributor>>> DISTRIBUTOR_TOKEN = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<Distributor>>> DISTRIBUTOR_TOKEN = new TypeKey<>() {
}; };
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> { ((functionalEventHandler, base) -> Init.ofPure(
CheckedRegistry<Supplier<ObjectTemplate<Distributor>>> distributorRegistry = event functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
.getPack() .then(event -> {
.getOrCreateRegistry(DISTRIBUTOR_TOKEN); CheckedRegistry<Supplier<ObjectTemplate<Distributor>>> distributorRegistry = event
.getPack()
distributorRegistry.register(addon.key("SAMPLER"), SamplerDistributorTemplate::new); .getOrCreateRegistry(DISTRIBUTOR_TOKEN);
distributorRegistry.register(addon.key("POINTS"), PointSetDistributorTemplate::new);
distributorRegistry.register(addon.key("PADDED_GRID"), PaddedGridDistributorTemplate::new); distributorRegistry.register(base.key("SAMPLER"), SamplerDistributorTemplate::new);
distributorRegistry.register(addon.key("AND"), AndDistributorTemplate::new); distributorRegistry.register(base.key("POINTS"), PointSetDistributorTemplate::new);
distributorRegistry.register(addon.key("OR"), OrDistributorTemplate::new); distributorRegistry.register(base.key("PADDED_GRID_SAMPLER"), PaddedGridSamplerDistributorTemplate::new);
distributorRegistry.register(addon.key("XOR"), XorDistributorTemplate::new); distributorRegistry.register(base.key("AND"), AndDistributorTemplate::new);
distributorRegistry.register(addon.key("YES"), YesDistributorTemplate::new); distributorRegistry.register(base.key("OR"), OrDistributorTemplate::new);
distributorRegistry.register(addon.key("NO"), NoDistributorTemplate::new); distributorRegistry.register(base.key("XOR"), XorDistributorTemplate::new);
distributorRegistry.register(base.key("YES"), YesDistributorTemplate::new);
event.getPack() distributorRegistry.register(base.key("NO"), NoDistributorTemplate::new);
.applyLoader(Point.class, PointTemplate::new);
}) event.getPack()
.failThrough(); .applyLoader(Point.class, PointTemplate::new);
})
.failThrough()
)));
} }
} }
@@ -3,23 +3,24 @@ package com.dfsek.terra.addons.feature.distributor.config;
import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.addons.feature.distributor.distributors.PaddedGridDistributor; import com.dfsek.terra.addons.feature.distributor.distributors.PaddedGridSamplerDistributor;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
public class PaddedGridDistributorTemplate implements ObjectTemplate<Distributor> { public class PaddedGridSamplerDistributorTemplate implements ObjectTemplate<Distributor> {
@Value("width") @Value("width")
private @Meta int width; private @Meta int width;
@Value("padding") @Value("padding")
private @Meta int padding; private @Meta int padding;
@Value("salt") @Value("sampler")
private @Meta int salt; private @Meta NoiseSampler noise;
@Override @Override
public Distributor get() { public Distributor get() {
return new PaddedGridDistributor(width, padding, salt); return new PaddedGridSamplerDistributor(noise, width, padding);
} }
} }
@@ -1,45 +0,0 @@
package com.dfsek.terra.addons.feature.distributor.distributors;
import net.jafama.FastMath;
import java.util.Random;
import com.dfsek.terra.api.structure.feature.Distributor;
import com.dfsek.terra.api.util.MathUtil;
public class PaddedGridDistributor implements Distributor {
private final int width;
private final int cellWidth;
private final int salt;
public PaddedGridDistributor(int width, int padding, int salt) {
this.width = width;
this.salt = salt;
this.cellWidth = width + padding;
}
private static long murmur64(long h) {
h ^= h >>> 33;
h *= 0xff51afd7ed558ccdL;
h ^= h >>> 33;
h *= 0xc4ceb9fe1a85ec53L;
h ^= h >>> 33;
return h;
}
@Override
public boolean matches(int x, int z, long seed) {
int cellX = FastMath.floorDiv(x, cellWidth);
int cellZ = FastMath.floorDiv(z, cellWidth);
Random random = new Random((murmur64(MathUtil.squash(cellX, cellZ)) ^ seed) + salt);
int pointX = random.nextInt(width) + cellX * cellWidth;
int pointZ = random.nextInt(width) + cellZ * cellWidth;
return x == pointX && z == pointZ;
}
}
@@ -0,0 +1,36 @@
package com.dfsek.terra.addons.feature.distributor.distributors;
import com.dfsek.terra.api.noise.NoiseSampler;
import net.jafama.FastMath;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.api.structure.feature.Distributor;
import com.dfsek.terra.api.util.MathUtil;
public class PaddedGridSamplerDistributor implements Distributor {
private final NoiseSampler sampler;
private final int width;
private final int cellWidth;
public PaddedGridSamplerDistributor(NoiseSampler sampler, int width, int padding) {
this.sampler = sampler;
this.width = width;
this.cellWidth = width + padding;
}
@Override
public boolean matches(int x, int z, long seed) {
int cellX = FastMath.floorDiv(x, cellWidth);
int cellZ = FastMath.floorDiv(z, cellWidth);
int pointX = (int) (FastMath.round(MathUtil.lerp(MathUtil.inverseLerp(sampler.noise(x, z, seed), -1, 1), 0, width)) + cellX * cellWidth);
int pointZ = (int) (FastMath.round(MathUtil.lerp(MathUtil.inverseLerp(sampler.noise(x, z, seed + 1), -1, 1), 0, width)) + cellZ * cellWidth);
return x == pointX && z == pointZ;
}
}
@@ -7,27 +7,32 @@
package com.dfsek.terra.addons.feature; package com.dfsek.terra.addons.feature;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject; import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.util.function.monad.Monad;
import org.jetbrains.annotations.NotNull;
public class FeatureAddon implements AddonInitializer { public class FeatureAddon implements MonadAddonInitializer {
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> event.getPack().registerConfigType(new FeatureConfigType(), addon.key("FEATURE"), 500)) ((functionalEventHandler, base) -> Init.ofPure(
.failThrough(); functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
.then(event -> event.getPack()
.registerConfigType(new FeatureConfigType(), base.key("FEATURE"), 500))
.failThrough()))
);
} }
} }
@@ -8,9 +8,6 @@
package com.dfsek.terra.addons.feature; package com.dfsek.terra.addons.feature;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.structure.feature.Feature; import com.dfsek.terra.api.structure.feature.Feature;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
@@ -10,7 +10,6 @@ package com.dfsek.terra.addons.feature;
import com.dfsek.tectonic.api.exception.LoadException; import com.dfsek.tectonic.api.exception.LoadException;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.structure.feature.Feature; import com.dfsek.terra.api.structure.feature.Feature;
@@ -2,10 +2,4 @@ version = version("1.0.0")
dependencies { dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader")) compileOnlyApi(project(":common:addons:manifest-addon-loader"))
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
relocate("net.jafama", "com.dfsek.terra.addons.flora.lib.jafama")
} }
@@ -9,30 +9,33 @@ package com.dfsek.terra.addons.flora;
import com.dfsek.terra.addons.flora.config.BlockLayerTemplate; import com.dfsek.terra.addons.flora.config.BlockLayerTemplate;
import com.dfsek.terra.addons.flora.flora.gen.BlockLayer; import com.dfsek.terra.addons.flora.flora.gen.BlockLayer;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject; import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.util.function.monad.Monad;
import org.jetbrains.annotations.NotNull;
public class FloraAddon implements AddonInitializer { public class FloraAddon implements MonadAddonInitializer {
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> { ((functionalEventHandler, base) -> Init.ofPure(
event.getPack().registerConfigType(new FloraConfigType(), addon.key("FLORA"), 2); functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
event.getPack().applyLoader(BlockLayer.class, BlockLayerTemplate::new); .then(event -> {
}) event.getPack().registerConfigType(new FloraConfigType(), base.key("FLORA"), 2);
.failThrough(); event.getPack().applyLoader(BlockLayer.class, BlockLayerTemplate::new);
})
.failThrough()))
);
} }
} }
@@ -8,9 +8,6 @@
package com.dfsek.terra.addons.flora; package com.dfsek.terra.addons.flora;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.structure.Structure; import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
@@ -9,7 +9,6 @@ package com.dfsek.terra.addons.flora;
import com.dfsek.terra.addons.flora.flora.gen.TerraFlora; import com.dfsek.terra.addons.flora.flora.gen.TerraFlora;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.structure.Structure; import com.dfsek.terra.api.structure.Structure;
@@ -12,7 +12,8 @@ import net.jafama.FastMath;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.block.state.properties.enums.Direction; import com.dfsek.terra.api.block.state.properties.enums.Direction;
@@ -73,7 +74,7 @@ public class TerraFlora implements Structure {
} }
@Override @Override
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { public boolean generate(Vector3Int location, WritableWorld world, Rotation rotation) {
boolean doRotation = testRotation.size() > 0; boolean doRotation = testRotation.size() > 0;
int size = layers.size(); int size = layers.size();
int c = ceiling ? -1 : 1; int c = ceiling ? -1 : 1;
@@ -86,10 +87,7 @@ public class TerraFlora implements Structure {
int lvl = (FastMath.abs(i)); int lvl = (FastMath.abs(i));
BlockState data = getStateCollection((ceiling ? lvl : size - lvl - 1)).get(distribution, location.getX(), location.getY(), BlockState data = getStateCollection((ceiling ? lvl : size - lvl - 1)).get(distribution, location.getX(), location.getY(),
location.getZ(), world.getSeed()); location.getZ(), world.getSeed());
if(doRotation) {
Direction oneFace = new ArrayList<>(faces).get(
new Random(location.getX() ^ location.getZ()).nextInt(faces.size())); // Get random face.
}
world.setBlockState(location.mutable().add(0, i + c, 0).immutable(), data, physics); world.setBlockState(location.mutable().add(0, i + c, 0).immutable(), data, physics);
} }
return true; return true;
@@ -2,11 +2,4 @@ version = version("1.1.0")
dependencies { dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader")) compileOnlyApi(project(":common:addons:manifest-addon-loader"))
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
relocate("net.jafama", "com.dfsek.terra.addons.feature.locator.lib.jafama")
} }
@@ -13,10 +13,8 @@ import java.util.function.Supplier;
import com.dfsek.terra.addons.feature.locator.config.AdjacentPatternLocatorTemplate; import com.dfsek.terra.addons.feature.locator.config.AdjacentPatternLocatorTemplate;
import com.dfsek.terra.addons.feature.locator.config.AndLocatorTemplate; import com.dfsek.terra.addons.feature.locator.config.AndLocatorTemplate;
import com.dfsek.terra.addons.feature.locator.config.GaussianRandomLocatorTemplate;
import com.dfsek.terra.addons.feature.locator.config.OrLocatorTemplate; import com.dfsek.terra.addons.feature.locator.config.OrLocatorTemplate;
import com.dfsek.terra.addons.feature.locator.config.PatternLocatorTemplate; import com.dfsek.terra.addons.feature.locator.config.PatternLocatorTemplate;
import com.dfsek.terra.addons.feature.locator.config.RandomLocatorTemplate;
import com.dfsek.terra.addons.feature.locator.config.Sampler3DLocatorTemplate; import com.dfsek.terra.addons.feature.locator.config.Sampler3DLocatorTemplate;
import com.dfsek.terra.addons.feature.locator.config.SamplerLocatorTemplate; import com.dfsek.terra.addons.feature.locator.config.SamplerLocatorTemplate;
import com.dfsek.terra.addons.feature.locator.config.SurfaceLocatorTemplate; import com.dfsek.terra.addons.feature.locator.config.SurfaceLocatorTemplate;
@@ -31,64 +29,62 @@ import com.dfsek.terra.addons.feature.locator.config.pattern.SingleBlockMatchPat
import com.dfsek.terra.addons.feature.locator.config.pattern.SolidMatchPatternTemplate; import com.dfsek.terra.addons.feature.locator.config.pattern.SolidMatchPatternTemplate;
import com.dfsek.terra.addons.feature.locator.config.pattern.XorPatternTemplate; import com.dfsek.terra.addons.feature.locator.config.pattern.XorPatternTemplate;
import com.dfsek.terra.addons.feature.locator.patterns.Pattern; import com.dfsek.terra.addons.feature.locator.patterns.Pattern;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.feature.Locator; import com.dfsek.terra.api.structure.feature.Locator;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
public class LocatorAddon implements AddonInitializer { public class LocatorAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<Locator>>> LOCATOR_TOKEN = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<Locator>>> LOCATOR_TOKEN = new TypeKey<>() {
}; };
public static final TypeKey<Supplier<ObjectTemplate<Pattern>>> PATTERN_TOKEN = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<Pattern>>> PATTERN_TOKEN = new TypeKey<>() {
}; };
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public Monad<?, Init<?>> initialize() {
platform.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> { Get.platform(),
CheckedRegistry<Supplier<ObjectTemplate<Locator>>> locatorRegistry = event.getPack().getOrCreateRegistry(LOCATOR_TOKEN); ((functionalEventHandler, base, platform) -> Init.ofPure(
locatorRegistry.register(addon.key("SURFACE"), SurfaceLocatorTemplate::new); functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
locatorRegistry.register(addon.key("TOP"), TopLocatorTemplate::new); .then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<Locator>>> locatorRegistry = event.getPack().getOrCreateRegistry(LOCATOR_TOKEN);
locatorRegistry.register(addon.key("RANDOM"), RandomLocatorTemplate::new); locatorRegistry.register(base.key("SURFACE"), SurfaceLocatorTemplate::new);
locatorRegistry.register(addon.key("GAUSSIAN_RANDOM"), GaussianRandomLocatorTemplate::new); locatorRegistry.register(base.key("TOP"), TopLocatorTemplate::new);
locatorRegistry.register(addon.key("PATTERN"), PatternLocatorTemplate::new); locatorRegistry.register(base.key("PATTERN"), PatternLocatorTemplate::new);
locatorRegistry.register(addon.key("ADJACENT_PATTERN"), AdjacentPatternLocatorTemplate::new); locatorRegistry.register(base.key("ADJACENT_PATTERN"), AdjacentPatternLocatorTemplate::new);
locatorRegistry.register(addon.key("SAMPLER"), SamplerLocatorTemplate::new); locatorRegistry.register(base.key("SAMPLER"), SamplerLocatorTemplate::new);
locatorRegistry.register(addon.key("SAMPLER_3D"), Sampler3DLocatorTemplate::new); locatorRegistry.register(base.key("SAMPLER_3D"), Sampler3DLocatorTemplate::new);
locatorRegistry.register(addon.key("AND"), AndLocatorTemplate::new); locatorRegistry.register(base.key("AND"), AndLocatorTemplate::new);
locatorRegistry.register(addon.key("OR"), OrLocatorTemplate::new); locatorRegistry.register(base.key("OR"), OrLocatorTemplate::new);
locatorRegistry.register(addon.key("XOR"), XorLocatorTemplate::new); locatorRegistry.register(base.key("XOR"), XorLocatorTemplate::new);
}) })
.then(event -> { .then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<Pattern>>> patternRegistry = event.getPack().getOrCreateRegistry(PATTERN_TOKEN); CheckedRegistry<Supplier<ObjectTemplate<Pattern>>> patternRegistry = event.getPack().getOrCreateRegistry(PATTERN_TOKEN);
patternRegistry.register(addon.key("MATCH_AIR"), AirMatchPatternTemplate::new); patternRegistry.register(base.key("MATCH_AIR"), AirMatchPatternTemplate::new);
patternRegistry.register(addon.key("MATCH_SOLID"), SolidMatchPatternTemplate::new); patternRegistry.register(base.key("MATCH_SOLID"), SolidMatchPatternTemplate::new);
patternRegistry.register(addon.key("MATCH"), SingleBlockMatchPatternTemplate::new); patternRegistry.register(base.key("MATCH"), SingleBlockMatchPatternTemplate::new);
patternRegistry.register(addon.key("MATCH_SET"), BlockSetMatchPatternTemplate::new); patternRegistry.register(base.key("MATCH_SET"), BlockSetMatchPatternTemplate::new);
patternRegistry.register(addon.key("AND"), AndPatternTemplate::new); patternRegistry.register(base.key("AND"), AndPatternTemplate::new);
patternRegistry.register(addon.key("OR"), OrPatternTemplate::new); patternRegistry.register(base.key("OR"), OrPatternTemplate::new);
patternRegistry.register(addon.key("XOR"), XorPatternTemplate::new); patternRegistry.register(base.key("XOR"), XorPatternTemplate::new);
patternRegistry.register(addon.key("NOT"), NotPatternTemplate::new); patternRegistry.register(base.key("NOT"), NotPatternTemplate::new);
}) })
.failThrough(); .failThrough()))
);
} }
} }
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.feature.locator.config;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.addons.feature.locator.locators.GaussianRandomLocator;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.structure.feature.Locator;
import com.dfsek.terra.api.util.Range;
@SuppressWarnings("FieldMayBeFinal")
public class GaussianRandomLocatorTemplate implements ObjectTemplate<Locator> {
@Value("height")
private @Meta Range height;
@Value("amount")
private @Meta Range amount;
@Value("standard-deviation")
private @Meta double standardDeviation;
@Value("salt")
@Default
private @Meta int salt = 0;
@Override
public Locator get() {
return new GaussianRandomLocator(height, amount, standardDeviation, salt);
}
}
@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.feature.locator.config;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.addons.feature.locator.locators.RandomLocator;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.structure.feature.Locator;
import com.dfsek.terra.api.util.Range;
@SuppressWarnings("FieldMayBeFinal")
public class RandomLocatorTemplate implements ObjectTemplate<Locator> {
@Value("height")
private @Meta Range height;
@Value("amount")
private @Meta Range amount;
@Value("salt")
@Default
private @Meta int salt = 0;
@Override
public Locator get() {
return new RandomLocator(height, amount, salt);
}
}
@@ -1,57 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.feature.locator.locators;
import java.util.Random;
import com.dfsek.terra.api.structure.feature.BinaryColumn;
import com.dfsek.terra.api.structure.feature.Locator;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.world.chunk.generation.util.Column;
import com.dfsek.terra.api.world.chunk.generation.util.Column.BinaryColumnBuilder;
public class GaussianRandomLocator implements Locator {
private final double mean;
private final Range points;
private final double standardDeviation;
private final int salt;
public GaussianRandomLocator(Range height, Range points, double standardDeviation, int salt) {
this.mean = (height.getMax() + height.getMin()) / 2.0;
this.points = points;
this.standardDeviation = standardDeviation;
this.salt = salt;
}
@Override
public BinaryColumn getSuitableCoordinates(Column<?> column) {
long seed = column.getWorld().getSeed();
seed = 31 * seed + column.getX();
seed = 31 * seed + column.getZ();
seed += salt;
Random r = new Random(seed);
int size = points.get(r);
BinaryColumnBuilder results = column.newBinaryColumn();
for(int i = 0; i < size; i++) {
int h = (int) r.nextGaussian(mean, standardDeviation);
if(h >= column.getMaxY() || h < column.getMinY()) continue;
results.set(h);
}
return results.build();
}
}
@@ -1,52 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.feature.locator.locators;
import java.util.Random;
import com.dfsek.terra.api.structure.feature.BinaryColumn;
import com.dfsek.terra.api.structure.feature.Locator;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.world.chunk.generation.util.Column;
import com.dfsek.terra.api.world.chunk.generation.util.Column.BinaryColumnBuilder;
public class RandomLocator implements Locator {
private final Range height;
private final Range points;
private final int salt;
public RandomLocator(Range height, Range points, int salt) {
this.height = height;
this.points = points;
this.salt = salt;
}
@Override
public BinaryColumn getSuitableCoordinates(Column<?> column) {
long seed = column.getWorld().getSeed();
seed = 31 * seed + column.getX();
seed = 31 * seed + column.getZ();
seed += salt;
Random r = new Random(seed);
int size = points.get(r);
BinaryColumnBuilder results = column.newBinaryColumn();
for(int i = 0; i < size; i++) {
int h = height.get(r);
if(h >= column.getMaxY() || h < column.getMinY()) continue;
results.set(h);
}
return results.build();
}
}
@@ -4,13 +4,4 @@ version = version("1.0.0")
dependencies { dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader")) compileOnlyApi(project(":common:addons:manifest-addon-loader"))
api("com.dfsek", "paralithic", Versions.Libraries.paralithic)
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<ShadowJar>("shadowJar") {
relocate("com.dfsek.paralithic", "com.dfsek.terra.addons.noise.lib.paralithic")
relocate("net.jafama", "com.dfsek.terra.addons.noise.lib.jafama")
} }
@@ -13,7 +13,10 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.addons.noise.config.DimensionApplicableNoiseSampler; import com.dfsek.terra.addons.noise.config.DimensionApplicableNoiseSampler;
import com.dfsek.terra.addons.noise.config.templates.BinaryArithmeticTemplate; import com.dfsek.terra.addons.noise.config.templates.BinaryArithmeticTemplate;
import com.dfsek.terra.addons.noise.config.templates.DomainWarpTemplate; import com.dfsek.terra.addons.noise.config.templates.DomainWarpTemplate;
@@ -30,6 +33,7 @@ import com.dfsek.terra.addons.noise.config.templates.noise.fractal.BrownianMotio
import com.dfsek.terra.addons.noise.config.templates.noise.fractal.PingPongTemplate; import com.dfsek.terra.addons.noise.config.templates.noise.fractal.PingPongTemplate;
import com.dfsek.terra.addons.noise.config.templates.noise.fractal.RidgedFractalTemplate; import com.dfsek.terra.addons.noise.config.templates.noise.fractal.RidgedFractalTemplate;
import com.dfsek.terra.addons.noise.config.templates.normalizer.ClampNormalizerTemplate; import com.dfsek.terra.addons.noise.config.templates.normalizer.ClampNormalizerTemplate;
import com.dfsek.terra.addons.noise.config.templates.normalizer.LinearMapNormalizerTemplate;
import com.dfsek.terra.addons.noise.config.templates.normalizer.LinearNormalizerTemplate; import com.dfsek.terra.addons.noise.config.templates.normalizer.LinearNormalizerTemplate;
import com.dfsek.terra.addons.noise.config.templates.normalizer.NormalNormalizerTemplate; import com.dfsek.terra.addons.noise.config.templates.normalizer.NormalNormalizerTemplate;
import com.dfsek.terra.addons.noise.config.templates.normalizer.PosterizationNormalizerTemplate; import com.dfsek.terra.addons.noise.config.templates.normalizer.PosterizationNormalizerTemplate;
@@ -51,97 +55,98 @@ import com.dfsek.terra.addons.noise.samplers.noise.simplex.PerlinSampler;
import com.dfsek.terra.addons.noise.samplers.noise.simplex.SimplexSampler; import com.dfsek.terra.addons.noise.samplers.noise.simplex.SimplexSampler;
import com.dfsek.terra.addons.noise.samplers.noise.value.ValueCubicSampler; import com.dfsek.terra.addons.noise.samplers.noise.value.ValueCubicSampler;
import com.dfsek.terra.addons.noise.samplers.noise.value.ValueSampler; import com.dfsek.terra.addons.noise.samplers.noise.value.ValueSampler;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import org.jetbrains.annotations.NotNull;
public class NoiseAddon implements AddonInitializer {
public class NoiseAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<NoiseSampler>>> NOISE_SAMPLER_TOKEN = new TypeKey<>() { public static final TypeKey<Supplier<ObjectTemplate<NoiseSampler>>> NOISE_SAMPLER_TOKEN = new TypeKey<>() {
}; };
@Inject
private Platform plugin;
@Inject
private BaseAddon addon;
@Override @Override
public void initialize() { public @NotNull Monad<?, Init<?>> initialize() {
plugin.getEventManager() return Do.with(
.getHandler(FunctionalEventHandler.class) Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
.register(addon, ConfigPackPreLoadEvent.class) Get.addon(),
.then(event -> { Get.platform(),
CheckedRegistry<Supplier<ObjectTemplate<NoiseSampler>>> noiseRegistry = event.getPack().getOrCreateRegistry( ((functionalEventHandler, base, platform) -> Init.ofPure(
NOISE_SAMPLER_TOKEN); functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
event.getPack() .then(event -> {
.applyLoader(CellularSampler.DistanceFunction.class, Registry<Supplier<ObjectTemplate<NoiseSampler>>> noiseRegistry = event.getPack().createRegistry(
(type, o, loader, depthTracker) -> CellularSampler.DistanceFunction.valueOf((String) o)) NOISE_SAMPLER_TOKEN);
.applyLoader(CellularSampler.ReturnType.class, event.getPack()
(type, o, loader, depthTracker) -> CellularSampler.ReturnType.valueOf((String) o)) .applyLoader(CellularSampler.DistanceFunction.class,
.applyLoader(DimensionApplicableNoiseSampler.class, DimensionApplicableNoiseSampler::new) (type, o, loader, depthTracker) -> CellularSampler.DistanceFunction.valueOf((String) o))
.applyLoader(FunctionTemplate.class, FunctionTemplate::new); .applyLoader(CellularSampler.ReturnType.class,
(type, o, loader, depthTracker) -> CellularSampler.ReturnType.valueOf((String) o))
noiseRegistry.register(addon.key("LINEAR"), LinearNormalizerTemplate::new); .applyLoader(DimensionApplicableNoiseSampler.class, DimensionApplicableNoiseSampler::new)
noiseRegistry.register(addon.key("NORMAL"), NormalNormalizerTemplate::new); .applyLoader(FunctionTemplate.class, FunctionTemplate::new);
noiseRegistry.register(addon.key("CLAMP"), ClampNormalizerTemplate::new);
noiseRegistry.register(addon.key("PROBABILITY"), ProbabilityNormalizerTemplate::new); noiseRegistry.register(base.key("LINEAR"), LinearNormalizerTemplate::new);
noiseRegistry.register(addon.key("SCALE"), ScaleNormalizerTemplate::new); noiseRegistry.register(base.key("LINEAR_MAP"), LinearMapNormalizerTemplate::new);
noiseRegistry.register(addon.key("POSTERIZATION"), PosterizationNormalizerTemplate::new); noiseRegistry.register(base.key("NORMAL"), NormalNormalizerTemplate::new);
noiseRegistry.register(base.key("CLAMP"), ClampNormalizerTemplate::new);
noiseRegistry.register(addon.key("IMAGE"), ImageSamplerTemplate::new); noiseRegistry.register(base.key("PROBABILITY"), ProbabilityNormalizerTemplate::new);
noiseRegistry.register(base.key("SCALE"), ScaleNormalizerTemplate::new);
noiseRegistry.register(addon.key("DOMAIN_WARP"), DomainWarpTemplate::new); noiseRegistry.register(base.key("POSTERIZATION"), PosterizationNormalizerTemplate::new);
noiseRegistry.register(addon.key("FBM"), BrownianMotionTemplate::new); noiseRegistry.register(base.key("IMAGE"), ImageSamplerTemplate::new);
noiseRegistry.register(addon.key("PING_PONG"), PingPongTemplate::new);
noiseRegistry.register(addon.key("RIDGED"), RidgedFractalTemplate::new); noiseRegistry.register(base.key("DOMAIN_WARP"), DomainWarpTemplate::new);
noiseRegistry.register(addon.key("OPEN_SIMPLEX_2"), () -> new SimpleNoiseTemplate(OpenSimplex2Sampler::new)); noiseRegistry.register(base.key("FBM"), BrownianMotionTemplate::new);
noiseRegistry.register(addon.key("OPEN_SIMPLEX_2S"), () -> new SimpleNoiseTemplate(OpenSimplex2SSampler::new)); noiseRegistry.register(base.key("PING_PONG"), PingPongTemplate::new);
noiseRegistry.register(addon.key("PERLIN"), () -> new SimpleNoiseTemplate(PerlinSampler::new)); noiseRegistry.register(base.key("RIDGED"), RidgedFractalTemplate::new);
noiseRegistry.register(addon.key("SIMPLEX"), () -> new SimpleNoiseTemplate(SimplexSampler::new));
noiseRegistry.register(addon.key("GABOR"), GaborNoiseTemplate::new); noiseRegistry.register(base.key("OPEN_SIMPLEX_2"), () -> new SimpleNoiseTemplate(OpenSimplex2Sampler::new));
noiseRegistry.register(base.key("OPEN_SIMPLEX_2S"), () -> new SimpleNoiseTemplate(OpenSimplex2SSampler::new));
noiseRegistry.register(base.key("PERLIN"), () -> new SimpleNoiseTemplate(PerlinSampler::new));
noiseRegistry.register(addon.key("VALUE"), () -> new SimpleNoiseTemplate(ValueSampler::new)); noiseRegistry.register(base.key("SIMPLEX"), () -> new SimpleNoiseTemplate(SimplexSampler::new));
noiseRegistry.register(addon.key("VALUE_CUBIC"), () -> new SimpleNoiseTemplate(ValueCubicSampler::new)); noiseRegistry.register(base.key("GABOR"), GaborNoiseTemplate::new);
noiseRegistry.register(addon.key("CELLULAR"), CellularNoiseTemplate::new);
noiseRegistry.register(base.key("VALUE"), () -> new SimpleNoiseTemplate(ValueSampler::new));
noiseRegistry.register(addon.key("WHITE_NOISE"), () -> new SimpleNoiseTemplate(WhiteNoiseSampler::new)); noiseRegistry.register(base.key("VALUE_CUBIC"), () -> new SimpleNoiseTemplate(ValueCubicSampler::new));
noiseRegistry.register(addon.key("POSITIVE_WHITE_NOISE"), () -> new SimpleNoiseTemplate(PositiveWhiteNoiseSampler::new));
noiseRegistry.register(addon.key("GAUSSIAN"), () -> new SimpleNoiseTemplate(GaussianNoiseSampler::new)); noiseRegistry.register(base.key("CELLULAR"), CellularNoiseTemplate::new);
noiseRegistry.register(addon.key("CONSTANT"), ConstantNoiseTemplate::new); noiseRegistry.register(base.key("WHITE_NOISE"), () -> new SimpleNoiseTemplate(WhiteNoiseSampler::new));
noiseRegistry.register(base.key("POSITIVE_WHITE_NOISE"), () -> new SimpleNoiseTemplate(PositiveWhiteNoiseSampler::new));
noiseRegistry.register(addon.key("KERNEL"), KernelTemplate::new); noiseRegistry.register(base.key("GAUSSIAN"), () -> new SimpleNoiseTemplate(GaussianNoiseSampler::new));
noiseRegistry.register(addon.key("LINEAR_HEIGHTMAP"), LinearHeightmapSamplerTemplate::new); noiseRegistry.register(base.key("CONSTANT"), ConstantNoiseTemplate::new);
noiseRegistry.register(addon.key("ADD"), () -> new BinaryArithmeticTemplate<>(AdditionSampler::new)); noiseRegistry.register(base.key("KERNEL"), KernelTemplate::new);
noiseRegistry.register(addon.key("SUB"), () -> new BinaryArithmeticTemplate<>(SubtractionSampler::new));
noiseRegistry.register(addon.key("MUL"), () -> new BinaryArithmeticTemplate<>(MultiplicationSampler::new)); noiseRegistry.register(base.key("LINEAR_HEIGHTMAP"), LinearHeightmapSamplerTemplate::new);
noiseRegistry.register(addon.key("DIV"), () -> new BinaryArithmeticTemplate<>(DivisionSampler::new));
noiseRegistry.register(addon.key("MAX"), () -> new BinaryArithmeticTemplate<>(MaxSampler::new)); noiseRegistry.register(base.key("ADD"), () -> new BinaryArithmeticTemplate<>(AdditionSampler::new));
noiseRegistry.register(addon.key("MIN"), () -> new BinaryArithmeticTemplate<>(MinSampler::new)); noiseRegistry.register(base.key("SUB"), () -> new BinaryArithmeticTemplate<>(SubtractionSampler::new));
noiseRegistry.register(base.key("MUL"), () -> new BinaryArithmeticTemplate<>(MultiplicationSampler::new));
noiseRegistry.register(base.key("DIV"), () -> new BinaryArithmeticTemplate<>(DivisionSampler::new));
Map<String, DimensionApplicableNoiseSampler> packSamplers = new LinkedHashMap<>(); noiseRegistry.register(base.key("MAX"), () -> new BinaryArithmeticTemplate<>(MaxSampler::new));
Map<String, FunctionTemplate> packFunctions = new LinkedHashMap<>(); noiseRegistry.register(base.key("MIN"), () -> new BinaryArithmeticTemplate<>(MinSampler::new));
noiseRegistry.register(addon.key("EXPRESSION"), () -> new ExpressionFunctionTemplate(packSamplers, packFunctions));
Map<String, DimensionApplicableNoiseSampler> packSamplers = new LinkedHashMap<>();
NoiseConfigPackTemplate template = event.loadTemplate(new NoiseConfigPackTemplate()); Map<String, FunctionTemplate> packFunctions = new LinkedHashMap<>();
packSamplers.putAll(template.getSamplers()); noiseRegistry.register(base.key("EXPRESSION"), () -> new ExpressionFunctionTemplate(packSamplers, packFunctions));
packFunctions.putAll(template.getFunctions());
event.getPack().getContext().put(template);
}) NoiseConfigPackTemplate template = event.loadTemplate(new NoiseConfigPackTemplate());
.priority(50) packSamplers.putAll(template.getSamplers());
.failThrough(); packFunctions.putAll(template.getFunctions());
event.getPack().getContext().put(template);
})
.priority(50)
.failThrough()))
);
} }
} }

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