Compare commits

..

189 Commits

Author SHA1 Message Date
dfsek 839f429806 documentation 2021-02-18 20:34:36 -07:00
dfsek e533180dab add GaussianNoiseSampler 2021-02-18 19:51:25 -07:00
dfsek 40b9c6c08c Add KernelSampler 2021-02-18 16:04:22 -07:00
dfsek c8c9247dfe cleanup 2021-02-17 22:14:03 -07:00
dfsek 7f8749239f add ConstantNoiseTemplate, bump version 2021-02-17 18:35:49 -07:00
dfsek 2b84967e05 fix freq issues 2021-02-17 17:39:14 -07:00
dfsek 6446f9b4a7 Merge remote-tracking branch 'origin/ver/4.3.0' into ver/4.3.0 2021-02-17 17:13:36 -07:00
dfsek 5933f97f93 add ExpressionFunction 2021-02-17 17:13:28 -07:00
dfsek d670fc904f Merge branch 'master' into ver/4.3.0 2021-02-17 10:37:14 -07:00
dfsek 33371675e1 add event priorities 2021-02-17 10:35:38 -07:00
dfsek bd91506069 remove unneeded setSeed call 2021-02-17 01:50:13 -07:00
dfsek 393a92730f fix frequency issues 2021-02-17 01:40:31 -07:00
dfsek 5ff016ea1f finish new noise options, remove FastNoise 2021-02-17 01:30:52 -07:00
dfsek 84b8df6d96 calculate bounding in fractal types. 2021-02-17 00:16:54 -07:00
dfsek 353999aa45 cleanup 2021-02-17 00:15:49 -07:00
dfsek 4a4e7e42cc split up FastNoise 2021-02-16 15:35:13 -07:00
dfsek 06cd1dc562 use event API for registration of Bukkit trees 2021-02-16 12:57:35 -07:00
dfsek 48296fb14a Add separate publishing for Bukkit impl 2021-02-16 10:43:13 -07:00
dfsek b3a4c3af19 Merge pull request #76 from PolyhedralDev/functionregistry
Function Registry and Event System
2021-02-16 10:12:48 -07:00
dfsek c0773be780 add getters for all registries to ConfigPack 2021-02-15 22:38:57 -07:00
dfsek 79df7eed21 cleanup 2021-02-15 21:12:18 -07:00
dfsek 14ce12f08e Finish event system 2021-02-15 21:11:10 -07:00
dfsek 7cfa96f925 implement Event API 2021-02-15 19:56:55 -07:00
dfsek 4131b45c6f Merge pull request #72 from PolyhedralDev/asmparser
Implement Paralithic expression parser
2021-02-15 18:01:00 -07:00
dfsek 4bf31d863e bump paralithic version 2021-02-15 15:53:59 -07:00
dfsek 92db30e181 move expressions to registry 2021-02-14 23:08:43 -07:00
dfsek 0f152f9281 remove tstructure yelling 2021-02-14 22:15:26 -07:00
dfsek 7ca779f845 improve logging 2021-02-14 22:15:09 -07:00
dfsek 76a2d08906 remove debug logging 2021-02-14 21:45:15 -07:00
dfsek 161b047c39 cleanup 2021-02-14 16:27:45 -07:00
dfsek 8309ad665e refactor registries 2021-02-14 14:31:14 -07:00
dfsek b6e414f944 completely redo biome loading 2021-02-14 14:19:45 -07:00
dfsek 36db83b253 Merge remote-tracking branch 'origin/master' into asmparser
# Conflicts:
#	build.gradle.kts
2021-02-12 14:30:28 -07:00
dfsek c4e641069d Merge remote-tracking branch 'origin/asmparser' into asmparser 2021-02-12 14:29:50 -07:00
dfsek 5e40fbbf07 add image align options 2021-02-12 14:29:39 -07:00
dfsek 8a47a01dd8 bump listener to highest priority 2021-02-12 14:17:14 -07:00
dfsek e41587dbd9 fix user defined functions 2021-02-11 08:35:13 -07:00
dfsek d5de91a864 fix minor sapling issues 2021-02-07 22:15:42 -07:00
dfsek f8cf61e281 bump version for patch config update 2021-02-07 18:00:51 -07:00
dfsek 7323b051db remove debug logging 2021-02-07 16:30:33 -07:00
dfsek 72f86e68e8 Merge remote-tracking branch 'origin/master' into asmparser 2021-02-07 16:18:02 -07:00
dfsek 5f9b21ea09 apparently this got removed somehow 2021-02-07 15:49:33 -07:00
dfsek dd44839bd3 Merge pull request #57 from PolyhedralDev/biome
Biome Stuff
2021-02-07 15:40:45 -07:00
dfsek b8cec40317 cleanup again 2021-02-07 13:58:17 -07:00
dfsek 19f781af31 fix Directional rotations 2021-02-07 00:52:18 -07:00
dfsek af825761c7 update to latest Paralithic 2021-02-06 22:41:42 -07:00
dfsek 490fed8c2c Merge branch 'biome' into asmparser
# Conflicts:
#	platforms/bukkit/build.gradle.kts
2021-02-06 22:28:53 -07:00
dfsek 85efa44673 cleanup 2021-02-06 22:03:46 -07:00
dfsek 985443e228 remove unneeded config file 2021-02-06 20:14:39 -07:00
dfsek 213182e2ab re-implement noise carvers 2021-02-06 19:14:07 -07:00
dfsek 76eb0f3fe0 respect function loading order 2021-02-05 23:30:46 -07:00
M3RGeo a2f3752c31 Update afr_sa.yml (#73) 2021-02-05 13:21:54 -07:00
dfsek 4aebb83b0c improve biome mutation noise functions 2021-02-05 11:07:12 -07:00
dfsek 7418d67b09 update to latest paralithic 2021-02-04 00:03:57 -07:00
dfsek 565266992f paralithic implementation 2021-02-03 23:15:36 -07:00
dfsek 1863ba29fc implement UserDefinedFunction 2021-01-31 01:41:05 -07:00
dfsek e600b50a11 refactor biome templates 2021-01-30 21:34:55 -07:00
dfsek 762c3064d9 use fancy new tectonic stuff for biome stage loading 2021-01-30 15:23:29 -07:00
dfsek b99fabcf1d redo noise config loading with new tectonic object goodies 2021-01-30 12:02:06 -07:00
dfsek af248ee14a begin refactoring with Tectonic Object Templates 2021-01-30 03:22:13 -07:00
dfsek c834d80206 refactor NoiseSampler 2021-01-30 00:16:16 -07:00
dfsek 66fb481ac2 cleanup 2021-01-29 10:54:04 -07:00
dfsek 7858cc34c2 add DomainWarpedSampler 2021-01-29 10:30:03 -07:00
dfsek e306a0fd09 ImageSampler implementation 2021-01-29 10:09:19 -07:00
dfsek 02d61d0764 completely redo noise config loading (mostly keeps parity with old configs) 2021-01-29 01:52:12 -07:00
dfsek dddf644c34 Remove 2d base eq options. Closes #70. 2021-01-29 00:46:55 -07:00
dfsek a8266f99b1 implement NormalNormalizer 2021-01-28 15:26:17 -07:00
dfsek 2fb30322ff actually register overridden vars 2021-01-27 20:06:40 -07:00
snake d05fdeb94c Update ja_jp (#64) 2021-01-27 16:39:42 -07:00
dfsek dfec463765 add biome specific vars 2021-01-27 00:37:30 -07:00
dfsek f6967be95f biome cleanup 2021-01-26 21:50:56 -07:00
dfsek 82fa9abe15 more refactoring 2021-01-25 23:29:15 -07:00
dfsek 1d6cdf9eaa refactor 2021-01-25 19:34:29 -07:00
dfsek 89f52a22c8 fix domain warp frequency issue 2021-01-25 11:12:20 -07:00
dfsek dca0891e00 basic noise carver implementation 2021-01-24 21:14:21 -07:00
dfsek bd4812ef2b clean up noise eqs 2021-01-24 02:56:50 -07:00
dfsek ce62f1d7ac implement ChunkAccess 2021-01-24 01:58:51 -07:00
dfsek da5d3fe0ce refactor API 2021-01-24 01:46:01 -07:00
dfsek 3318161c44 cleanup biome config loading 2021-01-21 22:20:40 -07:00
dfsek 25acda4410 add rotation and rotationDegrees functions 2021-01-21 20:35:52 -07:00
dfsek 115bb414c0 configurable blend weight 2021-01-21 20:29:25 -07:00
dfsek 708ef16a1c reduce pipeline boilerplate 2021-01-21 20:00:51 -07:00
dfsek 8b501ddcde redo biome blending 2021-01-21 18:18:43 -07:00
dfsek 5b8beebaa3 fix fabric stuff 2021-01-20 18:49:45 -07:00
dfsek 7b6d195615 fix BiomeTest 2021-01-19 23:38:23 -07:00
dfsek 9e830abb90 image to biome stuff 2021-01-18 23:56:46 -07:00
dfsek 01d0d4c00a Merge pull request #59 from PolyhedralDev/structurelocate
StructureLocateEvent implementation
2021-01-18 14:53:15 -07:00
dfsek 4b21fcd80a add elevation weight, add "self" biome opt 2021-01-17 21:55:08 -07:00
dfsek af5b316326 fix minor biome issues 2021-01-17 04:05:30 -07:00
dfsek beb18c6e2c Merge branch 'structurelocate' into biome
# Conflicts:
#	build.gradle.kts
2021-01-17 01:25:28 -07:00
dfsek 09c1957ab6 StructureLocateEvent implementation 2021-01-16 17:30:11 -07:00
dfsek b2c3498a32 create DistributionTest 2021-01-16 14:37:00 -07:00
dfsek 20de531c8f custom noise functions per palette layer 2021-01-15 15:08:59 -07:00
dfsek 6d1dd3acbf terrascript should be thread safe now 2021-01-15 00:59:04 -07:00
dfsek 346a8826aa add domain warp controls to FastNoiseLite 2021-01-15 00:03:01 -07:00
dfsek 25f6f3dbe1 debug log structure exception 2021-01-14 21:26:05 -07:00
dfsek 87f7af1e1b fix tree determinism issues 2021-01-14 20:48:07 -07:00
dfsek 764344b4ef synchronize maps 2021-01-14 20:40:57 -07:00
dfsek d327909389 implement multiple vanilla biomes per custom biome 2021-01-14 20:28:52 -07:00
dfsek c1fdfa94f1 improve elevation interp (TEMP DISABLE CARVING) 2021-01-14 18:40:03 -07:00
LeoDog896 d65c700bb9 [ImgBot] Optimize images (#53)
/platforms/fabric/src/main/resources/assets/terra/icon.png -- 142.09kb -> 126.82kb (10.75%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>

Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2021-01-14 11:24:13 -07:00
dfsek cbc2885c16 replace dumb caches with guava caches 2021-01-14 00:34:23 -07:00
dfsek 8fd3530653 configurable cache sizes 2021-01-13 23:51:23 -07:00
dfsek 244f0fba11 protect against biome cell overflow 2021-01-13 22:12:18 -07:00
dfsek 56a0d5d15b Revert "use getUngeneratedBlock for trees"
This reverts commit ca8cc8bc
2021-01-13 20:03:01 -07:00
dfsek ca8cc8bc66 use getUngeneratedBlock for trees 2021-01-13 20:02:34 -07:00
dfsek 627f1b75d6 add BorderMutator to config 2021-01-13 19:02:51 -07:00
dfsek 18731a5aa0 remove unused biome opts 2021-01-13 19:02:38 -07:00
dfsek 4bd943ae7b implement getUngeneratedBlock 2021-01-13 17:48:30 -07:00
dfsek e04d363123 fix minor issues 2021-01-13 17:10:29 -07:00
dfsek d1c018690d minor perf improvements 2021-01-13 14:03:52 -07:00
dfsek 54f732176d implement biome pipeline config loader 2021-01-13 10:48:45 -07:00
dfsek fb32531584 implementation of BiomePipeline 2021-01-13 00:19:57 -07:00
dfsek 5c9a9c7dfa implement BiomePipeline 2021-01-12 22:36:16 -07:00
dfsek fc46c8bd4d fix border issues 2021-01-12 21:10:46 -07:00
dfsek f28759d07a add BorderMutator 2021-01-12 19:25:01 -07:00
dfsek 93c33ca455 refactor TerraBiome 2021-01-12 17:39:26 -07:00
dfsek 9c50dc2ef9 smoothing stuff 2021-01-12 17:22:49 -07:00
dfsek 883124d8ab basic framework 2021-01-12 16:32:21 -07:00
dfsek 1ee2b180d4 bump version 2021-01-12 11:10:17 -07:00
dfsek e6e2c62474 Merge pull request #50 from PolyhedralDev/palette
Noise config additions
2021-01-12 10:34:42 -07:00
dfsek 5df511a940 white noise micro opt 2021-01-11 22:00:10 -07:00
dfsek 462b0af225 normalization options 2021-01-11 20:23:41 -07:00
dfsek 5c469ed378 noise function flora and tree dist 2021-01-11 17:07:25 -07:00
dfsek c59ab5d917 fix lookup issue 2021-01-11 16:28:53 -07:00
dfsek 8a10a9807d allow configuration of 2d/3d noise in palettes 2021-01-11 14:37:56 -07:00
dfsek 623a4dea4f allow configuration of cellular lookup function 2021-01-11 13:34:53 -07:00
dfsek 18d7408f53 customizable palette noise 2021-01-11 13:31:19 -07:00
dfsek 462b6f4198 add publishing stuff 2021-01-10 20:44:56 -07:00
dfsek 1049bb901d complain about tstructure files 2021-01-10 18:08:41 -07:00
dfsek 999c9b565d fix biomegrid wackiness 2021-01-10 17:20:21 -07:00
dfsek 27aeb73157 fix minor version issues 2021-01-10 16:55:49 -07:00
dfsek 12ff9cc146 give gradle more memory 2021-01-10 16:19:16 -07:00
dfsek f114baebd6 better tab completion, fix testWithPaper task 2021-01-10 14:37:44 -07:00
dfsek 11a6546064 oops 2021-01-10 00:01:53 -07:00
dfsek 771e42d1a8 Add Terra name classifier to Jars 2021-01-09 23:58:46 -07:00
dfsek 5e3c12298b oops forgot nether trees 2021-01-09 23:14:16 -07:00
dfsek a5dd4a63d1 minor fixes/improvements 2021-01-09 22:26:39 -07:00
dfsek 9fbe117f78 fix fabric stuff 2021-01-09 12:00:18 -07:00
dfsek 3429165aca Merge pull request #43 from PolyhedralDev/agnostic
Platform-agnostic engine & TerraScript structures
2021-01-09 11:30:34 -07:00
dfsek 9310114c0e cleanup 2021-01-09 02:58:02 -07:00
dfsek 141b4f86ae cleanup 2021-01-09 02:25:48 -07:00
dfsek 67ffd91641 add enchantment to loot tables 2021-01-09 02:25:36 -07:00
dfsek 9a94485c91 add white noise to FastNoiseLite 2021-01-08 11:51:07 -07:00
dfsek 28b6fe49bb rework image stuff 2021-01-07 22:04:35 -07:00
dfsek 308ba887a3 add getOrigin functions 2021-01-07 17:18:38 -07:00
dfsek d2a1901f44 add max structure recursion depth 2021-01-07 16:38:07 -07:00
dfsek 64391f3abc remove unused random parameter from populators 2021-01-07 10:33:23 -07:00
dfsek e47b3f0397 add message to export command, more cleanup 2021-01-07 09:45:40 -07:00
dfsek c6ff808cce fix //regen and cleanup 2021-01-06 21:07:57 -07:00
dfsek e9d0c14eee cleanup biomegrids 2021-01-06 13:32:46 -07:00
dfsek 23d8a0aeeb skip over buffer when pasting trees 2021-01-06 11:56:17 -07:00
dfsek 512edae9c6 Multi-version support for 1.13-1.16 2021-01-06 10:57:34 -07:00
dfsek 25ae2b3c9b drastically increase script loading speed via optimised token pipeline 2021-01-06 01:11:13 -07:00
dfsek 44176f7ee6 fix Marks 2021-01-05 22:19:11 -07:00
dfsek 47cad8a30b refactor, cleanup, and perf improvements 2021-01-05 19:21:42 -07:00
dfsek 4ad2db3ca8 improve state function IDs 2021-01-05 14:51:49 -07:00
Roan-V 24a5a9425e Added dutch translation (#45) 2021-01-05 11:20:13 -07:00
DeltaRays 1cdf4478b8 Italian translation (#44)
* Created italian translation

* Revert "Created italian translation"

This reverts commit 74fe8ffe13.

* Created the italian translation file

(and translated everything in it to italian)
2021-01-05 10:15:52 -07:00
dfsek b67814d68a update to latest tectonic 2021-01-05 02:25:06 -07:00
dfsek 5a64424b16 reimplement ender eye redirection 2021-01-05 02:04:05 -07:00
dfsek 32b3b4cd3f fix StructureScript return issues 2021-01-05 02:00:01 -07:00
dfsek d0a24f7041 add spawner state info 2021-01-05 01:23:54 -07:00
dfsek aa406d9b8b properly handle BufferedStateManipulator application exception 2021-01-05 01:07:58 -07:00
dfsek a38eba2916 implement StateFunction 2021-01-05 01:04:15 -07:00
dfsek aec1d671fa fix StructureScript#test 2021-01-04 21:59:29 -07:00
dfsek 26504d6d83 revert some stuff 2021-01-04 10:52:51 -07:00
dfsek 87a1b0bf5a multithreaded jankiness 2021-01-04 09:39:39 -07:00
dfsek bd0726db37 implement properties in janky pregen 2021-01-04 01:58:25 -07:00
dfsek 75fbda5a9f continue work on janky pregenerator 2021-01-04 01:29:51 -07:00
dfsek ee093397d3 begin work on janky pregenerator 2021-01-04 00:21:49 -07:00
dfsek 3c12a98ef3 update .gitignore 2021-01-03 21:52:11 -07:00
dfsek fff918e0ee Add CheckBlockFunction, which mustn't be discussed without mentioning that it shall be covered with disclaimers. 2021-01-03 20:29:10 -07:00
dfsek 1536a13d3c fix minor issues & cleanup 2021-01-03 20:16:59 -07:00
dfsek b26847f250 implement BiomeFunction 2021-01-03 19:49:15 -07:00
dfsek c7d3e5294a fix mem leak 2021-01-03 19:43:26 -07:00
dfsek 86d42a03a0 decrease default cache size 2021-01-03 13:57:47 -07:00
dfsek bf4a831781 fix GridSpawn salt 2021-01-03 13:33:03 -07:00
dfsek 90cc88f05f set min heap size in testWithPaper 2021-01-03 13:28:10 -07:00
dfsek 315230af27 implement SamplerCache for drastically increased structure perf 2021-01-03 13:24:17 -07:00
dfsek fed24920f8 Add error message to BiomeGridFactory 2021-01-02 20:19:18 -07:00
dfsek a785d7b892 add 2d biomes support 2021-01-02 20:19:08 -07:00
dfsek de9eb26ebc fix check fail for search 2021-01-02 18:33:28 -07:00
dfsek a5105f9f9d implement precedence matrix and NegationOperation 2021-01-02 03:40:51 -07:00
dfsek 0fef1619d2 implement ModuloOperation 2021-01-02 01:08:45 -07:00
dfsek b209c49877 BukkitRail 2021-01-02 00:50:07 -07:00
dfsek ddc218c4d4 Add more math functions 2021-01-02 00:44:26 -07:00
dfsek 77f348912f completely redo internal TerraScript args 2021-01-02 00:44:16 -07:00
Haurum d21d448947 Create da.yml (#42) 2020-12-30 13:33:31 -07:00
520 changed files with 11921 additions and 7851 deletions
+5 -1
View File
@@ -138,4 +138,8 @@ build
!lib/*.jar
.idea/Terra.iml
/run/
.idea/**.iml
.idea/**.iml
/lang/
/packs/
/config.yml
/region/
+1 -1
View File
@@ -1,6 +1,6 @@
import com.dfsek.terra.getGitHash
val versionObj = Version("3", "0", "0", true)
val versionObj = Version("4", "3", "0", true)
allprojects {
version = versionObj
@@ -7,7 +7,6 @@ import org.gradle.kotlin.dsl.repositories
fun Project.configureDependencies() {
repositories {
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
@@ -19,6 +18,8 @@ fun Project.configureDependencies() {
dependencies {
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
"testImplementation"("org.yaml:snakeyaml:1.27")
"testImplementation"("com.googlecode.json-simple:json-simple:1.1.1")
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"compileOnly"("org.jetbrains:annotations:20.1.0")
}
@@ -45,12 +45,13 @@ fun Project.configureDistribution() {
}
tasks["processResources"].dependsOn(downloadDefaultPacks)
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE")
}
tasks.withType<Jar> {
from("../LICENSE", "../../LICENSE")
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
tasks.register<Jar>("javadocJar") {
+29 -2
View File
@@ -2,6 +2,7 @@ import com.dfsek.terra.configureCommon
plugins {
`java-library`
`maven-publish`
}
configureCommon()
@@ -12,12 +13,38 @@ dependencies {
"shadedApi"("org.apache.commons:commons-rng-core:1.3")
"shadedApi"("commons-io:commons-io:2.4")
"shadedApi"("com.scireum:parsii:1.2.1")
"shadedApi"("com.dfsek:Tectonic:1.0.3")
"shadedApi"("com.dfsek:Paralithic:0.3.2")
"shadedApi"("com.dfsek:Tectonic:1.2.3")
"shadedApi"("net.jafama:jafama:2.3.2")
"shadedApi"("org.yaml:snakeyaml:1.27")
"shadedApi"("org.ow2.asm:asm:9.0")
"compileOnly"("com.googlecode.json-simple:json-simple:1.1")
"shadedApi"("com.google.guava:guava:30.0-jre")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks["sourcesJar"])
artifact(tasks["jar"])
}
}
repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) {
val mavenUsername: String? by project
val mavenPassword: String? by project
if (mavenUsername != null && mavenPassword != null) {
credentials {
username = mavenUsername
password = mavenPassword
}
}
}
}
}
@@ -1,4 +0,0 @@
package com.dfsek.terra;
public interface CommandHandler {
}
@@ -1,19 +0,0 @@
package com.dfsek.terra;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.profiler.DataType;
import com.dfsek.terra.api.profiler.Measurement;
import com.dfsek.terra.api.profiler.WorldProfiler;
public class TerraProfiler extends WorldProfiler {
public TerraProfiler(World w) {
super(w);
this
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime")
.addMeasurement(new Measurement(10000000, DataType.PERIOD_MILLISECONDS), "TreeTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "OreTime")
.addMeasurement(new Measurement(5000000, DataType.PERIOD_MILLISECONDS), "CaveTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "ElevationTime");
}
}
@@ -1,55 +0,0 @@
package com.dfsek.terra;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.generator.GeneratorWrapper;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.biome.BiomeZone;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.config.base.ConfigPack;
public class TerraWorld {
private final TerraBiomeGrid grid;
private final BiomeZone zone;
private final ConfigPack config;
private final boolean safe;
private final TerraProfiler profiler;
private final World world;
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
config = c;
profiler = new TerraProfiler(w);
this.grid = new TerraBiomeGrid.TerraBiomeGridBuilder(w.getSeed(), c, main).build();
this.zone = grid.getZone();
this.world = w;
safe = true;
}
public World getWorld() {
return world;
}
public static boolean isTerraWorld(World w) {
return w.getGenerator().getHandle() instanceof GeneratorWrapper;
}
public TerraBiomeGrid getGrid() {
return grid;
}
public ConfigPack getConfig() {
return config;
}
public BiomeZone getZone() {
return zone;
}
public boolean isSafe() {
return safe;
}
public TerraProfiler getProfiler() {
return profiler;
}
}
@@ -1,8 +0,0 @@
package com.dfsek.terra.api;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.Handle;
public interface Entity extends Handle {
Location getLocation();
}
@@ -1,63 +0,0 @@
package com.dfsek.terra.api;
import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.biome.palette.PaletteHolder;
import com.dfsek.terra.biome.palette.PaletteLayer;
import com.dfsek.terra.carving.CarverPalette;
import com.dfsek.terra.config.loaders.ImageLoaderLoader;
import com.dfsek.terra.config.loaders.MaterialSetLoader;
import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader;
import com.dfsek.terra.config.loaders.RangeLoader;
import com.dfsek.terra.config.loaders.config.FloraLayerLoader;
import com.dfsek.terra.config.loaders.config.GridSpawnLoader;
import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader;
import com.dfsek.terra.config.loaders.config.OreConfigLoader;
import com.dfsek.terra.config.loaders.config.OreHolderLoader;
import com.dfsek.terra.config.loaders.config.TreeLayerLoader;
import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader;
import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader;
import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader;
import com.dfsek.terra.generation.config.NoiseBuilder;
import com.dfsek.terra.generation.items.flora.FloraLayer;
import com.dfsek.terra.generation.items.flora.TerraFlora;
import com.dfsek.terra.generation.items.ores.Ore;
import com.dfsek.terra.generation.items.ores.OreConfig;
import com.dfsek.terra.generation.items.ores.OreHolder;
import com.dfsek.terra.generation.items.tree.TreeLayer;
import com.dfsek.terra.image.ImageLoader;
import com.dfsek.terra.procgen.GridSpawn;
import com.dfsek.terra.util.MaterialSet;
public class GenericLoaders implements LoaderRegistrar {
private final TerraPlugin main;
public GenericLoaders(TerraPlugin main) {
this.main = main;
}
@Override
public void register(TypeRegistry registry) {
registry.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader())
.registerLoader(Range.class, new RangeLoader())
.registerLoader(CarverPalette.class, new CarverPaletteLoader())
.registerLoader(GridSpawn.class, new GridSpawnLoader())
.registerLoader(PaletteHolder.class, new PaletteHolderLoader())
.registerLoader(PaletteLayer.class, new PaletteLayerLoader())
.registerLoader(FloraLayer.class, new FloraLayerLoader())
.registerLoader(Ore.Type.class, (t, o, l) -> Ore.Type.valueOf((String) o))
.registerLoader(OreConfig.class, new OreConfigLoader())
.registerLoader(NoiseBuilder.class, new NoiseBuilderLoader())
.registerLoader(TreeLayer.class, new TreeLayerLoader(main))
.registerLoader(MaterialSet.class, new MaterialSetLoader())
.registerLoader(OreHolder.class, new OreHolderLoader())
.registerLoader(ImageLoader.class, new ImageLoaderLoader())
.registerLoader(TerraBiomeGrid.Type.class, (t, o, l) -> TerraBiomeGrid.Type.valueOf((String) o))
.registerLoader(ImageLoader.Channel.class, (t, o, l) -> ImageLoader.Channel.valueOf((String) o))
.registerLoader(ImageLoader.Align.class, (t, o, l) -> ImageLoader.Align.valueOf((String) o))
.registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf((String) o));
}
}
@@ -1,4 +0,0 @@
package com.dfsek.terra.api;
public interface Player extends Entity {
}
@@ -1,13 +1,15 @@
package com.dfsek.terra.api.platform;
package com.dfsek.terra.api.core;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.LoaderRegistrar;
import com.dfsek.terra.api.lang.Language;
import com.dfsek.terra.api.core.event.EventManager;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.config.base.PluginConfig;
import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.debug.DebugLogger;
import com.dfsek.terra.registry.ConfigRegistry;
import com.dfsek.terra.world.TerraWorld;
import java.io.File;
import java.util.logging.Logger;
@@ -38,4 +40,9 @@ public interface TerraPlugin extends LoaderRegistrar {
void saveDefaultConfig();
String platformName();
DebugLogger getDebugLogger();
EventManager getEventManager();
}
@@ -0,0 +1,4 @@
package com.dfsek.terra.api.core.event;
public interface EventListener {
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.api.core.event;
import com.dfsek.terra.api.core.event.events.Event;
public interface EventManager {
/**
* Call an event, and return the execution status.
* @param event Event to pass to all registered EventListeners.
* @return False if the event is cancellable and has been cancelled, otherwise true.
*/
boolean callEvent(Event event);
void registerListener(EventListener listener);
}
@@ -0,0 +1,92 @@
package com.dfsek.terra.api.core.event;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.core.event.annotations.Priority;
import com.dfsek.terra.api.core.event.events.Cancellable;
import com.dfsek.terra.api.core.event.events.Event;
import com.dfsek.terra.api.util.ReflectionUtil;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TerraEventManager implements EventManager {
private final Map<Class<? extends Event>, List<ListenerHolder>> listeners = new HashMap<>();
private final TerraPlugin main;
public TerraEventManager(TerraPlugin main) {
this.main = main;
}
@Override
public boolean callEvent(Event event) {
listeners.getOrDefault(event.getClass(), Collections.emptyList()).forEach(listenerHolder -> {
try {
listenerHolder.method.invoke(listenerHolder.listener, event);
} catch(InvocationTargetException e) {
StringWriter writer = new StringWriter();
e.getTargetException().printStackTrace(new PrintWriter(writer));
main.getLogger().warning("Exception occurred during event handling:");
main.getLogger().warning(writer.toString());
main.getLogger().warning("Report this to the maintainers of " + listenerHolder.method.getName());
} catch(Exception e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
main.getLogger().warning("Exception occurred during event handling:");
main.getLogger().warning(writer.toString());
main.getLogger().warning("Report this to the maintainers of " + listenerHolder.method.getName());
}
}
);
if(event instanceof Cancellable) return !((Cancellable) event).isCancelled();
return true;
}
@SuppressWarnings("unchecked")
@Override
public void registerListener(EventListener listener) {
Class<? extends EventListener> listenerClass = listener.getClass();
Method[] methods = ReflectionUtil.getMethods(listenerClass);
for(Method method : methods) {
if(method.getParameterCount() != 1) continue; // Check that parameter count is only 1.
Class<?> eventParam = method.getParameterTypes()[0];
if(!Event.class.isAssignableFrom(eventParam)) continue; // Check that parameter is an Event.
Priority p = method.getAnnotation(Priority.class);
int priority = p == null ? 0 : p.value();
method.setAccessible(true);
List<ListenerHolder> holders = listeners.computeIfAbsent((Class<? extends Event>) eventParam, e -> new ArrayList<>());
holders.add(new ListenerHolder(method, listener, priority));
holders.sort(Comparator.comparingInt(ListenerHolder::getPriority)); // Sort priorities.
}
}
private static final class ListenerHolder {
private final Method method;
private final EventListener listener;
private final int priority;
private ListenerHolder(Method method, EventListener listener, int priority) {
this.method = method;
this.listener = listener;
this.priority = priority;
}
public int getPriority() {
return priority;
}
}
}
@@ -0,0 +1,38 @@
package com.dfsek.terra.api.core.event.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotated listener methods will have a specific priority set.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Priority {
/**
* Highest possible priority. Listeners with this priority will always be invoked first.
*/
int HIGHEST = Integer.MAX_VALUE;
/**
* Lowest possible priority. Listeners with this priority will always be invoked last.
*/
int LOWEST = Integer.MIN_VALUE;
/**
* Default priority.
*/
int NORMAL = 0;
/**
* High priority.
*/
int HIGH = 1;
/**
* Low Priority.
*/
int LOW = -1;
/**
* @return Priority of this event. Events are executed from lowest to highest priorities.
*/
int value();
}
@@ -0,0 +1,11 @@
package com.dfsek.terra.api.core.event.events;
/**
* Events that implement this interface may be cancelled.
*
* Cancelling an event is assumed to stop the execution of whatever action triggered the event.
*/
public interface Cancellable extends Event {
boolean isCancelled();
void setCancelled();
}
@@ -0,0 +1,4 @@
package com.dfsek.terra.api.core.event.events;
public interface Event {
}
@@ -0,0 +1,16 @@
package com.dfsek.terra.api.core.event.events.config;
import com.dfsek.terra.api.core.event.events.Event;
import com.dfsek.terra.config.pack.ConfigPack;
public abstract class ConfigPackLoadEvent implements Event {
private final ConfigPack pack;
public ConfigPackLoadEvent(ConfigPack pack) {
this.pack = pack;
}
public ConfigPack getPack() {
return pack;
}
}
@@ -0,0 +1,12 @@
package com.dfsek.terra.api.core.event.events.config;
import com.dfsek.terra.config.pack.ConfigPack;
/**
* Called when a config pack has finished loading.
*/
public class ConfigPackPostLoadEvent extends ConfigPackLoadEvent {
public ConfigPackPostLoadEvent(ConfigPack pack) {
super(pack);
}
}
@@ -0,0 +1,12 @@
package com.dfsek.terra.api.core.event.events.config;
import com.dfsek.terra.config.pack.ConfigPack;
/**
* Called before a config pack's registries are filled. At this point, the pack manifest has been loaded, and all registries are empty.
*/
public class ConfigPackPreLoadEvent extends ConfigPackLoadEvent {
public ConfigPackPreLoadEvent(ConfigPack pack) {
super(pack);
}
}
@@ -0,0 +1,19 @@
package com.dfsek.terra.api.core.event.events.world;
import com.dfsek.terra.api.core.event.events.Event;
import com.dfsek.terra.world.TerraWorld;
/**
* Called upon initialization of a TerraWorld.
*/
public class TerraWorldLoadEvent implements Event {
private final TerraWorld world;
public TerraWorldLoadEvent(TerraWorld world) {
this.world = world;
}
public TerraWorld getWorld() {
return world;
}
}
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,5 @@
package com.dfsek.terra.procgen;
package com.dfsek.terra.api.math;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.util.GlueList;
@@ -14,12 +13,12 @@ import java.util.Random;
public class GridSpawn {
private final int separation;
private final int width;
private final int seedOffset;
private final int salt;
public GridSpawn(int width, int separation, int seedOffset) {
public GridSpawn(int width, int separation, int salt) {
this.separation = separation;
this.width = width;
this.seedOffset = seedOffset;
this.salt = salt;
}
/**
@@ -36,7 +35,7 @@ public class GridSpawn {
List<Vector3> zones = new GlueList<>();
for(int xi = structureChunkX - 1; xi <= structureChunkX + 1; xi++) {
for(int zi = structureChunkZ - 1; zi <= structureChunkZ + 1; zi++) {
zones.add(getChunkSpawn(xi, zi, seed + seedOffset));
zones.add(getChunkSpawn(xi, zi, seed));
}
}
Vector3 shortest = zones.get(0);
@@ -56,7 +55,7 @@ public class GridSpawn {
* @return Vector representing spawnpoint
*/
public Vector3 getChunkSpawn(int structureChunkX, int structureChunkZ, long seed) {
Random r = new FastRandom(MathUtil.getCarverChunkSeed(structureChunkX, structureChunkZ, seed + seedOffset));
Random r = new FastRandom(MathUtil.getCarverChunkSeed(structureChunkX, structureChunkZ, seed + salt));
int offsetX = r.nextInt(width);
int offsetZ = r.nextInt(width);
int sx = structureChunkX * (width + 2 * separation) + offsetX;
@@ -1,15 +1,24 @@
package com.dfsek.terra.api.math;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.world.generation.math.Sampler;
import net.jafama.FastMath;
import java.util.List;
import java.util.Random;
/**
* Utility class for mathematical functions.
*/
public final class MathUtil {
private static final double EPSILON = 0.1E-5;
/**
* Epsilon for fuzzy floating point comparisons.
*/
public static final double EPSILON = 1.0E-5;
/**
* Derivative constant.
*/
private static final double DERIVATIVE_DIST = 0.55;
/**
* Gets the standard deviation of an array of doubles.
@@ -17,18 +26,18 @@ public final class MathUtil {
* @param numArray The array of numbers to calculate the standard deviation of.
* @return double - The standard deviation.
*/
public static double standardDeviation(double[] numArray) {
public static double standardDeviation(List<Number> numArray) {
double sum = 0.0, standardDeviation = 0.0;
int length = numArray.length;
int length = numArray.size();
for(double num : numArray) {
sum += num;
for(Number num : numArray) {
sum += num.doubleValue();
}
double mean = sum / length;
for(double num : numArray) {
standardDeviation += FastMath.pow(num - mean, 2);
for(Number num : numArray) {
standardDeviation += FastMath.pow2(num.doubleValue() - mean);
}
return FastMath.sqrt(standardDeviation / length);
@@ -68,4 +77,117 @@ public final class MathUtil {
public static boolean equals(double a, double b) {
return a == b || FastMath.abs(a - b) < EPSILON;
}
public static double derivative(Sampler sampler, double x, double y, double z) {
double baseSample = sampler.sample(x, y, z);
double xVal1 = (sampler.sample(x + DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
double xVal2 = (sampler.sample(x - DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
double zVal1 = (sampler.sample(x, y, z + DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
double zVal2 = (sampler.sample(x, y, z - DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
double yVal1 = (sampler.sample(x, y + DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
double yVal2 = (sampler.sample(x, y - DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
return Math.sqrt(((xVal2 - xVal1) * (xVal2 - xVal1)) + ((zVal2 - zVal1) * (zVal2 - zVal1)) + ((yVal2 - yVal1) * (yVal2 - yVal1)));
}
public static int normalizeIndex(double val, int size) {
return FastMath.max(FastMath.min(FastMath.floorToInt(((val + 1D) / 2D) * size), size - 1), 0);
}
public static long squash(int first, int last) {
return (((long) first) << 32) | (last & 0xffffffffL);
}
/**
* Clamp value to range of [-1, 1]
*
* @param in Value to clamp
* @return Clamped value
*/
public static double clamp(double in) {
return FastMath.min(FastMath.max(in, -1), 1);
}
/**
* Compute the value in a normally distributed data set that has probability p.
*
* @param p Probability of value
* @param mu Mean of data
* @param sigma Standard deviation of data
* @return Value corresponding to input probability
*/
public static double normalInverse(double p, double mu, double sigma) {
if(p < 0 || p > 1)
throw new IllegalArgumentException("Probability must be in range [0, 1]");
if(sigma < 0)
throw new IllegalArgumentException("Standard deviation must be positive.");
if(p == 0)
return Double.NEGATIVE_INFINITY;
if(p == 1)
return Double.POSITIVE_INFINITY;
if(sigma == 0)
return mu;
double q, r, val;
q = p - 0.5;
if(FastMath.abs(q) <= .425) {
r = .180625 - q * q;
val =
q * (((((((r * 2509.0809287301226727 +
33430.575583588128105) * r + 67265.770927008700853) * r +
45921.953931549871457) * r + 13731.693765509461125) * r +
1971.5909503065514427) * r + 133.14166789178437745) * r +
3.387132872796366608)
/ (((((((r * 5226.495278852854561 +
28729.085735721942674) * r + 39307.89580009271061) * r +
21213.794301586595867) * r + 5394.1960214247511077) * r +
687.1870074920579083) * r + 42.313330701600911252) * r + 1);
} else {
if(q > 0) {
r = 1 - p;
} else {
r = p;
}
r = FastMath.sqrt(-FastMath.log(r));
if(r <= 5) {
r += -1.6;
val = (((((((r * 7.7454501427834140764e-4 +
.0227238449892691845833) * r + .24178072517745061177) *
r + 1.27045825245236838258) * r +
3.64784832476320460504) * r + 5.7694972214606914055) *
r + 4.6303378461565452959) * r +
1.42343711074968357734)
/ (((((((r *
1.05075007164441684324e-9 + 5.475938084995344946e-4) *
r + .0151986665636164571966) * r +
.14810397642748007459) * r + .68976733498510000455) *
r + 1.6763848301838038494) * r +
2.05319162663775882187) * r + 1);
} else {
r += -5;
val = (((((((r * 2.01033439929228813265e-7 +
2.71155556874348757815e-5) * r +
.0012426609473880784386) * r + .026532189526576123093) *
r + .29656057182850489123) * r +
1.7848265399172913358) * r + 5.4637849111641143699) *
r + 6.6579046435011037772)
/ (((((((r *
2.04426310338993978564e-15 + 1.4215117583164458887e-7) *
r + 1.8463183175100546818e-5) * r +
7.868691311456132591e-4) * r + .0148753612908506148525)
* r + .13692988092273580531) * r +
.59983220655588793769) * r + 1);
}
if(q < 0.0) {
val = -val;
}
}
return mu + sigma * val;
}
}
@@ -1,15 +1,15 @@
package com.dfsek.terra.api.math;
import com.dfsek.terra.api.world.biome.NormalizationUtil;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
@SuppressWarnings("unchecked")
public class ProbabilityCollection<E> {
private final Set<Object> cont = new HashSet<>();
private final Set<E> cont = new HashSet<>();
private Object[] array = new Object[0];
private int size;
@@ -24,19 +24,19 @@ public class ProbabilityCollection<E> {
return this;
}
public E get() {
if(array.length == 0) return null;
return (E) array[ThreadLocalRandom.current().nextInt(array.length)];
}
public E get(Random r) {
if(array.length == 0) return null;
return (E) array[r.nextInt(array.length)];
}
public E get(FastNoiseLite n, double x, double z) {
public E get(NoiseSampler n, double x, double y, double z) {
if(array.length == 0) return null;
return (E) array[NormalizationUtil.normalize(n.getNoise(x, z), array.length, 1)];
return (E) array[MathUtil.normalizeIndex(n.getNoise(x, y, z), array.length)];
}
public E get(NoiseSampler n, double x, double z) {
if(array.length == 0) return null;
return (E) array[MathUtil.normalizeIndex(n.getNoise(x, z), array.length)];
}
public int getTotalProbability() {
@@ -46,4 +46,51 @@ public class ProbabilityCollection<E> {
public int size() {
return size;
}
public Set<E> getContents() {
return new HashSet<>(cont);
}
public static final class Singleton<T> extends ProbabilityCollection<T> {
private final T single;
public Singleton(T single) {
this.single = single;
}
@Override
public ProbabilityCollection<T> add(T item, int probability) {
throw new UnsupportedOperationException();
}
@Override
public T get(Random r) {
return single;
}
@Override
public T get(NoiseSampler n, double x, double y, double z) {
return single;
}
@Override
public T get(NoiseSampler n, double x, double z) {
return single;
}
@Override
public int getTotalProbability() {
return 1;
}
@Override
public int size() {
return 1;
}
@Override
public Set<T> getContents() {
return Collections.singleton(single);
}
}
}
@@ -0,0 +1,32 @@
package com.dfsek.terra.api.math.noise;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.math.vector.Vector3;
public interface NoiseSampler {
/**
* 2D noise at given position using current settings
* <p>
* Noise output bounded between -1...1
*/
double getNoise(double x, double y);
/**
* 3D noise at given position using current settings
* <p>
* Noise output bounded between -1...1
*/
double getNoise(double x, double y, double z);
default double getNoise(Vector3 vector3) {
return getNoise(vector3.getX(), vector3.getY(), vector3.getZ());
}
default double getNoise(Vector2 vector2) {
return getNoise(vector2.getX(), vector2.getZ());
}
double getNoiseSeeded(int seed, double x, double y);
double getNoiseSeeded(int seed, double x, double y, double z);
}
@@ -0,0 +1,20 @@
package com.dfsek.terra.api.math.noise.normalizer;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import net.jafama.FastMath;
public class ClampNormalizer extends Normalizer {
private final double min;
private final double max;
public ClampNormalizer(NoiseSampler sampler, double min, double max) {
super(sampler);
this.min = min;
this.max = max;
}
@Override
public double normalize(double in) {
return FastMath.max(FastMath.min(in, max), min);
}
}
@@ -0,0 +1,22 @@
package com.dfsek.terra.api.math.noise.normalizer;
import com.dfsek.terra.api.math.noise.NoiseSampler;
/**
* Normalizer to linearly scale data's range.
*/
public class LinearNormalizer extends Normalizer {
private final double min;
private final double max;
public LinearNormalizer(NoiseSampler sampler, double min, double max) {
super(sampler);
this.min = min;
this.max = max;
}
@Override
public double normalize(double in) {
return (in - min) * (2 / (max - min)) - 1;
}
}
@@ -0,0 +1,45 @@
package com.dfsek.terra.api.math.noise.normalizer;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import net.jafama.FastMath;
/**
* Normalizer to redistribute normally distributed data to a continuous distribution via an automatically generated lookup table.
*/
public class NormalNormalizer extends Normalizer {
private final double[] lookup;
public NormalNormalizer(NoiseSampler sampler, int buckets, double mean, double standardDeviation) {
super(sampler);
this.lookup = new double[buckets];
for(int i = 0; i < buckets; i++) {
lookup[i] = MathUtil.normalInverse((double) i / buckets, mean, standardDeviation);
}
}
@Override
public double normalize(double in) {
int start = 0;
int end = lookup.length - 1;
while(start + 1 < end) {
int mid = start + (end - start) / 2;
if(lookup[mid] <= in) {
start = mid;
} else {
end = mid;
}
}
double left = FastMath.abs(lookup[start] - in);
double right = FastMath.abs(lookup[end] - in);
double fin;
if(left <= right) {
fin = (double) start / (lookup.length);
} else fin = (double) end / (lookup.length);
return (fin - 0.5) * 2;
}
}
@@ -0,0 +1,33 @@
package com.dfsek.terra.api.math.noise.normalizer;
import com.dfsek.terra.api.math.noise.NoiseSampler;
public abstract class Normalizer implements NoiseSampler {
private final NoiseSampler sampler;
public Normalizer(NoiseSampler sampler) {
this.sampler = sampler;
}
public abstract double normalize(double in);
@Override
public double getNoise(double x, double y) {
return normalize(sampler.getNoise(x, y));
}
@Override
public double getNoise(double x, double y, double z) {
return normalize(sampler.getNoise(x, y, z));
}
@Override
public double getNoiseSeeded(int seed, double x, double y) {
return normalize(sampler.getNoiseSeeded(seed, x, y));
}
@Override
public double getNoiseSeeded(int seed, double x, double y, double z) {
return normalize(sampler.getNoiseSeeded(seed, x, y, z));
}
}
@@ -0,0 +1,44 @@
package com.dfsek.terra.api.math.noise.samplers;
import com.dfsek.terra.api.math.noise.NoiseSampler;
public class DomainWarpedSampler implements NoiseSampler {
private final NoiseSampler function;
private final NoiseSampler warp;
private final int seed;
private final double amplitude;
public DomainWarpedSampler(NoiseSampler function, NoiseSampler warp, int seed, double amplitude) {
this.function = function;
this.warp = warp;
this.seed = seed;
this.amplitude = amplitude;
}
@Override
public double getNoise(double x, double y) {
return getNoiseSeeded(seed, x, y);
}
@Override
public double getNoise(double x, double y, double z) {
return getNoiseSeeded(seed, x, y, z);
}
@Override
public double getNoiseSeeded(int seed, double x, double y) {
return function.getNoise(
x + warp.getNoiseSeeded(seed, x, y) * amplitude,
y + warp.getNoiseSeeded(seed + 1, x, y) * amplitude
);
}
@Override
public double getNoiseSeeded(int seed, double x, double y, double z) {
return function.getNoise(
x + warp.getNoiseSeeded(seed, x, y, z) * amplitude,
y + warp.getNoiseSeeded(seed + 1, x, y, z) * amplitude,
z + warp.getNoiseSeeded(seed + 2, x, y, z) * amplitude
);
}
}
@@ -0,0 +1,67 @@
package com.dfsek.terra.api.math.noise.samplers;
import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.paralithic.defined.UserDefinedFunction;
import com.dfsek.terra.api.math.paralithic.noise.NoiseFunction2;
import com.dfsek.terra.api.math.paralithic.noise.NoiseFunction3;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import java.util.Map;
/**
* Sampler implementation using Paralithic expression
*/
public class ExpressionSampler implements NoiseSampler {
private final Expression expression;
public ExpressionSampler(String equation, Scope parent, long seed, Map<String, NoiseSeeded> functions, Map<String, FunctionTemplate> definedFunctions) throws ParseException {
Parser parser = new Parser();
Scope scope = new Scope().withParent(parent);
scope.addInvocationVariable("x");
scope.addInvocationVariable("y");
scope.addInvocationVariable("z");
functions.forEach((id, noise) -> {
switch(noise.getDimensions()) {
case 2:
parser.registerFunction(id, new NoiseFunction2(noise.apply(seed)));
break;
case 3:
parser.registerFunction(id, new NoiseFunction3(noise.apply(seed)));
break;
}
});
for(Map.Entry<String, FunctionTemplate> entry : definedFunctions.entrySet()) {
parser.registerFunction(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue(), parser, parent));
}
this.expression = parser.parse(equation, scope);
}
@Override
public double getNoise(double x, double y) {
return getNoise(x, 0, y);
}
@Override
public double getNoise(double x, double y, double z) {
return expression.evaluate(x, y, z);
}
@Override
public double getNoiseSeeded(int seed, double x, double y) {
return getNoise(x, y);
}
@Override
public double getNoiseSeeded(int seed, double x, double y, double z) {
return getNoise(x, y, z);
}
}
@@ -0,0 +1,70 @@
package com.dfsek.terra.api.math.noise.samplers;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import net.jafama.FastMath;
import java.awt.image.BufferedImage;
public class ImageSampler implements NoiseSampler {
private final BufferedImage image;
private final Channel channel;
private final double frequency;
public ImageSampler(BufferedImage image, Channel channel, double frequency) {
this.image = image;
this.channel = channel;
this.frequency = frequency;
}
@Override
public double getNoise(double x, double y) {
return ((channel.getChannel(image.getRGB(FastMath.floorMod(FastMath.floorToInt(x * frequency), image.getWidth()), FastMath.floorMod(FastMath.floorToInt(y * frequency), image.getHeight()))) / 255D) - 0.5) * 2;
}
@Override
public double getNoise(double x, double y, double z) {
return getNoise(x, y);
}
@Override
public double getNoiseSeeded(int seed, double x, double y) {
return getNoise(x, y);
}
@Override
public double getNoiseSeeded(int seed, double x, double y, double z) {
return getNoise(x, y, z);
}
public enum Channel {
RED {
@Override
public int getChannel(int mashed) {
return (mashed >> 16) & 0xff;
}
}, GREEN {
@Override
public int getChannel(int mashed) {
return (mashed >> 8) & 0xff;
}
}, BLUE {
@Override
public int getChannel(int mashed) {
return mashed & 0xff;
}
}, GRAYSCALE {
@Override
public int getChannel(int mashed) {
return (RED.getChannel(mashed) + GREEN.getChannel(mashed) + BLUE.getChannel(mashed)) / 3;
}
}, ALPHA {
@Override
public int getChannel(int mashed) {
return (mashed >> 24) & 0xff;
}
};
public abstract int getChannel(int mashed);
}
}
@@ -0,0 +1,59 @@
package com.dfsek.terra.api.math.noise.samplers;
import com.dfsek.terra.api.math.noise.NoiseSampler;
public class KernelSampler implements NoiseSampler {
private final double[][] kernel;
private final NoiseSampler in;
private double frequency = 1;
public KernelSampler(double[][] kernel, NoiseSampler in) {
this.kernel = kernel;
this.in = in;
}
@Override
public double getNoise(double x, double y) {
return getNoiseSeeded(0, x, y);
}
@Override
public double getNoise(double x, double y, double z) {
return getNoiseSeeded(0, x, y, z);
}
@Override
public double getNoiseSeeded(int seed, double x, double y) {
x *= frequency;
y *= frequency;
double accumulator = 0;
for(int kx = 0; kx < kernel.length; kx++) {
for(int ky = 0; ky < kernel[kx].length; ky++) {
accumulator += in.getNoise(x + kx, y + ky) * kernel[kx][ky];
}
}
return accumulator;
}
@Override
public double getNoiseSeeded(int seed, double x, double y, double z) {
x *= frequency;
y *= frequency;
z *= frequency;
double accumulator = 0;
for(int kx = 0; kx < kernel.length; kx++) {
for(int ky = 0; ky < kernel[kx].length; ky++) {
accumulator += in.getNoise(x + kx, y, z + ky) * kernel[kx][ky];
}
}
return accumulator;
}
public void setFrequency(double frequency) {
this.frequency = frequency;
}
}
@@ -0,0 +1,565 @@
package com.dfsek.terra.api.math.noise.samplers.noise;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.simplex.OpenSimplex2Sampler;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.math.vector.Vector3;
/**
* NoiseSampler implementation for Cellular (Voronoi/Worley) Noise.
*/
public class CellularSampler extends NoiseFunction {
private static final double[] RAND_VECS_3D = {
-0.7292736885d, -0.6618439697d, 0.1735581948d, 0, 0.790292081d, -0.5480887466d, -0.2739291014d, 0, 0.7217578935d, 0.6226212466d,
-0.3023380997d, 0, 0.565683137d, -0.8208298145d, -0.0790000257d, 0, 0.760049034d, -0.5555979497d, -0.3370999617d, 0,
0.3713945616d, 0.5011264475d, 0.7816254623d, 0, -0.1277062463d, -0.4254438999d, -0.8959289049d, 0, -0.2881560924d,
-0.5815838982d, 0.7607405838d, 0, 0.5849561111d, -0.662820239d, -0.4674352136d, 0, 0.3307171178d, 0.0391653737d, 0.94291689d, 0,
0.8712121778d, -0.4113374369d, -0.2679381538d, 0, 0.580981015d, 0.7021915846d, 0.4115677815d, 0, 0.503756873d, 0.6330056931d,
-0.5878203852d, 0, 0.4493712205d, 0.601390195d, 0.6606022552d, 0, -0.6878403724d, 0.09018890807d, -0.7202371714d, 0,
-0.5958956522d, -0.6469350577d, 0.475797649d, 0, -0.5127052122d, 0.1946921978d, -0.8361987284d, 0, -0.9911507142d,
-0.05410276466d, -0.1212153153d, 0, -0.2149721042d, 0.9720882117d, -0.09397607749d, 0, -0.7518650936d, -0.5428057603d,
0.3742469607d, 0, 0.5237068895d, 0.8516377189d, -0.02107817834d, 0, 0.6333504779d, 0.1926167129d, -0.7495104896d, 0,
-0.06788241606d, 0.3998305789d, 0.9140719259d, 0, -0.5538628599d, -0.4729896695d, -0.6852128902d, 0, -0.7261455366d,
-0.5911990757d, 0.3509933228d, 0, -0.9229274737d, -0.1782808786d, 0.3412049336d, 0, -0.6968815002d, 0.6511274338d,
0.3006480328d, 0, 0.9608044783d, -0.2098363234d, -0.1811724921d, 0, 0.06817146062d, -0.9743405129d, 0.2145069156d, 0,
-0.3577285196d, -0.6697087264d, -0.6507845481d, 0, -0.1868621131d, 0.7648617052d, -0.6164974636d, 0, -0.6541697588d,
0.3967914832d, 0.6439087246d, 0, 0.6993340405d, -0.6164538506d, 0.3618239211d, 0, -0.1546665739d, 0.6291283928d, 0.7617583057d,
0, -0.6841612949d, -0.2580482182d, -0.6821542638d, 0, 0.5383980957d, 0.4258654885d, 0.7271630328d, 0, -0.5026987823d,
-0.7939832935d, -0.3418836993d, 0, 0.3202971715d, 0.2834415347d, 0.9039195862d, 0, 0.8683227101d, -0.0003762656404d,
-0.4959995258d, 0, 0.791120031d, -0.08511045745d, 0.6057105799d, 0, -0.04011016052d, -0.4397248749d, 0.8972364289d, 0,
0.9145119872d, 0.3579346169d, -0.1885487608d, 0, -0.9612039066d, -0.2756484276d, 0.01024666929d, 0, 0.6510361721d,
-0.2877799159d, -0.7023778346d, 0, -0.2041786351d, 0.7365237271d, 0.644859585d, 0, -0.7718263711d, 0.3790626912d, 0.5104855816d,
0, -0.3060082741d, -0.7692987727d, 0.5608371729d, 0, 0.454007341d, -0.5024843065d, 0.7357899537d, 0, 0.4816795475d,
0.6021208291d, -0.6367380315d, 0, 0.6961980369d, -0.3222197429d, 0.641469197d, 0, -0.6532160499d, -0.6781148932d, 0.3368515753d,
0, 0.5089301236d, -0.6154662304d, -0.6018234363d, 0, -0.1635919754d, -0.9133604627d, -0.372840892d, 0, 0.52408019d,
-0.8437664109d, 0.1157505864d, 0, 0.5902587356d, 0.4983817807d, -0.6349883666d, 0, 0.5863227872d, 0.494764745d, 0.6414307729d,
0, 0.6779335087d, 0.2341345225d, 0.6968408593d, 0, 0.7177054546d, -0.6858979348d, 0.120178631d, 0, -0.5328819713d,
-0.5205125012d, 0.6671608058d, 0, -0.8654874251d, -0.0700727088d, -0.4960053754d, 0, -0.2861810166d, 0.7952089234d,
0.5345495242d, 0, -0.04849529634d, 0.9810836427d, -0.1874115585d, 0, -0.6358521667d, 0.6058348682d, 0.4781800233d, 0,
0.6254794696d, -0.2861619734d, 0.7258696564d, 0, -0.2585259868d, 0.5061949264d, -0.8227581726d, 0, 0.02136306781d,
0.5064016808d, -0.8620330371d, 0, 0.200111773d, 0.8599263484d, 0.4695550591d, 0, 0.4743561372d, 0.6014985084d, -0.6427953014d,
0, 0.6622993731d, -0.5202474575d, -0.5391679918d, 0, 0.08084972818d, -0.6532720452d, 0.7527940996d, 0, -0.6893687501d,
0.0592860349d, 0.7219805347d, 0, -0.1121887082d, -0.9673185067d, 0.2273952515d, 0, 0.7344116094d, 0.5979668656d, -0.3210532909d,
0, 0.5789393465d, -0.2488849713d, 0.7764570201d, 0, 0.6988182827d, 0.3557169806d, -0.6205791146d, 0, -0.8636845529d,
-0.2748771249d, -0.4224826141d, 0, -0.4247027957d, -0.4640880967d, 0.777335046d, 0, 0.5257722489d, -0.8427017621d,
0.1158329937d, 0, 0.9343830603d, 0.316302472d, -0.1639543925d, 0, -0.1016836419d, -0.8057303073d, -0.5834887393d, 0,
-0.6529238969d, 0.50602126d, -0.5635892736d, 0, -0.2465286165d, -0.9668205684d, -0.06694497494d, 0, -0.9776897119d,
-0.2099250524d, -0.007368825344d, 0, 0.7736893337d, 0.5734244712d, 0.2694238123d, 0, -0.6095087895d, 0.4995678998d,
0.6155736747d, 0, 0.5794535482d, 0.7434546771d, 0.3339292269d, 0, -0.8226211154d, 0.08142581855d, 0.5627293636d, 0,
-0.510385483d, 0.4703667658d, 0.7199039967d, 0, -0.5764971849d, -0.07231656274d, -0.8138926898d, 0, 0.7250628871d,
0.3949971505d, -0.5641463116d, 0, -0.1525424005d, 0.4860840828d, -0.8604958341d, 0, -0.5550976208d, -0.4957820792d,
0.667882296d, 0, -0.1883614327d, 0.9145869398d, 0.357841725d, 0, 0.7625556724d, -0.5414408243d, -0.3540489801d, 0,
-0.5870231946d, -0.3226498013d, -0.7424963803d, 0, 0.3051124198d, 0.2262544068d, -0.9250488391d, 0, 0.6379576059d, 0.577242424d,
-0.5097070502d, 0, -0.5966775796d, 0.1454852398d, -0.7891830656d, 0, -0.658330573d, 0.6555487542d, -0.3699414651d, 0,
0.7434892426d, 0.2351084581d, 0.6260573129d, 0, 0.5562114096d, 0.8264360377d, -0.0873632843d, 0, -0.3028940016d, -0.8251527185d,
0.4768419182d, 0, 0.1129343818d, -0.985888439d, -0.1235710781d, 0, 0.5937652891d, -0.5896813806d, 0.5474656618d, 0,
0.6757964092d, -0.5835758614d, -0.4502648413d, 0, 0.7242302609d, -0.1152719764d, 0.6798550586d, 0, -0.9511914166d,
0.0753623979d, -0.2992580792d, 0, 0.2539470961d, -0.1886339355d, 0.9486454084d, 0, 0.571433621d, -0.1679450851d, -0.8032795685d,
0, -0.06778234979d, 0.3978269256d, 0.9149531629d, 0, 0.6074972649d, 0.733060024d, -0.3058922593d, 0, -0.5435478392d,
0.1675822484d, 0.8224791405d, 0, -0.5876678086d, -0.3380045064d, -0.7351186982d, 0, -0.7967562402d, 0.04097822706d,
-0.6029098428d, 0, -0.1996350917d, 0.8706294745d, 0.4496111079d, 0, -0.02787660336d, -0.9106232682d, -0.4122962022d, 0,
-0.7797625996d, -0.6257634692d, 0.01975775581d, 0, -0.5211232846d, 0.7401644346d, -0.4249554471d, 0, 0.8575424857d,
0.4053272873d, -0.3167501783d, 0, 0.1045223322d, 0.8390195772d, -0.5339674439d, 0, 0.3501822831d, 0.9242524096d, -0.1520850155d,
0, 0.1987849858d, 0.07647613266d, 0.9770547224d, 0, 0.7845996363d, 0.6066256811d, -0.1280964233d, 0, 0.09006737436d,
-0.9750989929d, -0.2026569073d, 0, -0.8274343547d, -0.542299559d, 0.1458203587d, 0, -0.3485797732d, -0.415802277d, 0.840000362d,
0, -0.2471778936d, -0.7304819962d, -0.6366310879d, 0, -0.3700154943d, 0.8577948156d, 0.3567584454d, 0, 0.5913394901d,
-0.548311967d, -0.5913303597d, 0, 0.1204873514d, -0.7626472379d, -0.6354935001d, 0, 0.616959265d, 0.03079647928d, 0.7863922953d,
0, 0.1258156836d, -0.6640829889d, -0.7369967419d, 0, -0.6477565124d, -0.1740147258d, -0.7417077429d, 0, 0.6217889313d,
-0.7804430448d, -0.06547655076d, 0, 0.6589943422d, -0.6096987708d, 0.4404473475d, 0, -0.2689837504d, -0.6732403169d,
-0.6887635427d, 0, -0.3849775103d, 0.5676542638d, 0.7277093879d, 0, 0.5754444408d, 0.8110471154d, -0.1051963504d, 0,
0.9141593684d, 0.3832947817d, 0.131900567d, 0, -0.107925319d, 0.9245493968d, 0.3654593525d, 0, 0.377977089d, 0.3043148782d,
0.8743716458d, 0, -0.2142885215d, -0.8259286236d, 0.5214617324d, 0, 0.5802544474d, 0.4148098596d, -0.7008834116d, 0,
-0.1982660881d, 0.8567161266d, -0.4761596756d, 0, -0.03381553704d, 0.3773180787d, -0.9254661404d, 0, -0.6867922841d,
-0.6656597827d, 0.2919133642d, 0, 0.7731742607d, -0.2875793547d, -0.5652430251d, 0, -0.09655941928d, 0.9193708367d,
-0.3813575004d, 0, 0.2715702457d, -0.9577909544d, -0.09426605581d, 0, 0.2451015704d, -0.6917998565d, -0.6792188003d, 0,
0.977700782d, -0.1753855374d, 0.1155036542d, 0, -0.5224739938d, 0.8521606816d, 0.02903615945d, 0, -0.7734880599d,
-0.5261292347d, 0.3534179531d, 0, -0.7134492443d, -0.269547243d, 0.6467878011d, 0, 0.1644037271d, 0.5105846203d, -0.8439637196d,
0, 0.6494635788d, 0.05585611296d, 0.7583384168d, 0, -0.4711970882d, 0.5017280509d, -0.7254255765d, 0, -0.6335764307d,
-0.2381686273d, -0.7361091029d, 0, -0.9021533097d, -0.270947803d, -0.3357181763d, 0, -0.3793711033d, 0.872258117d,
0.3086152025d, 0, -0.6855598966d, -0.3250143309d, 0.6514394162d, 0, 0.2900942212d, -0.7799057743d, -0.5546100667d, 0,
-0.2098319339d, 0.85037073d, 0.4825351604d, 0, -0.4592603758d, 0.6598504336d, -0.5947077538d, 0, 0.8715945488d, 0.09616365406d,
-0.4807031248d, 0, -0.6776666319d, 0.7118504878d, -0.1844907016d, 0, 0.7044377633d, 0.312427597d, 0.637304036d, 0,
-0.7052318886d, -0.2401093292d, -0.6670798253d, 0, 0.081921007d, -0.7207336136d, -0.6883545647d, 0, -0.6993680906d,
-0.5875763221d, -0.4069869034d, 0, -0.1281454481d, 0.6419895885d, 0.7559286424d, 0, -0.6337388239d, -0.6785471501d,
-0.3714146849d, 0, 0.5565051903d, -0.2168887573d, -0.8020356851d, 0, -0.5791554484d, 0.7244372011d, -0.3738578718d, 0,
0.1175779076d, -0.7096451073d, 0.6946792478d, 0, -0.6134619607d, 0.1323631078d, 0.7785527795d, 0, 0.6984635305d,
-0.02980516237d, -0.715024719d, 0, 0.8318082963d, -0.3930171956d, 0.3919597455d, 0, 0.1469576422d, 0.05541651717d,
-0.9875892167d, 0, 0.708868575d, -0.2690503865d, 0.6520101478d, 0, 0.2726053183d, 0.67369766d, -0.68688995d, 0, -0.6591295371d,
0.3035458599d, -0.6880466294d, 0, 0.4815131379d, -0.7528270071d, 0.4487723203d, 0, 0.9430009463d, 0.1675647412d, -0.2875261255d,
0, 0.434802957d, 0.7695304522d, -0.4677277752d, 0, 0.3931996188d, 0.594473625d, 0.7014236729d, 0, 0.7254336655d, -0.603925654d,
0.3301814672d, 0, 0.7590235227d, -0.6506083235d, 0.02433313207d, 0, -0.8552768592d, -0.3430042733d, 0.3883935666d, 0,
-0.6139746835d, 0.6981725247d, 0.3682257648d, 0, -0.7465905486d, -0.5752009504d, 0.3342849376d, 0, 0.5730065677d, 0.810555537d,
-0.1210916791d, 0, -0.9225877367d, -0.3475211012d, -0.167514036d, 0, -0.7105816789d, -0.4719692027d, -0.5218416899d, 0,
-0.08564609717d, 0.3583001386d, 0.929669703d, 0, -0.8279697606d, -0.2043157126d, 0.5222271202d, 0, 0.427944023d, 0.278165994d,
0.8599346446d, 0, 0.5399079671d, -0.7857120652d, -0.3019204161d, 0, 0.5678404253d, -0.5495413974d, -0.6128307303d, 0,
-0.9896071041d, 0.1365639107d, -0.04503418428d, 0, -0.6154342638d, -0.6440875597d, 0.4543037336d, 0, 0.1074204368d,
-0.7946340692d, 0.5975094525d, 0, -0.3595449969d, -0.8885529948d, 0.28495784d, 0, -0.2180405296d, 0.1529888965d, 0.9638738118d,
0, -0.7277432317d, -0.6164050508d, -0.3007234646d, 0, 0.7249729114d, -0.00669719484d, 0.6887448187d, 0, -0.5553659455d,
-0.5336586252d, 0.6377908264d, 0, 0.5137558015d, 0.7976208196d, -0.3160000073d, 0, -0.3794024848d, 0.9245608561d,
-0.03522751494d, 0, 0.8229248658d, 0.2745365933d, -0.4974176556d, 0, -0.5404114394d, 0.6091141441d, 0.5804613989d, 0,
0.8036581901d, -0.2703029469d, 0.5301601931d, 0, 0.6044318879d, 0.6832968393d, 0.4095943388d, 0, 0.06389988817d, 0.9658208605d,
-0.2512108074d, 0, 0.1087113286d, 0.7402471173d, -0.6634877936d, 0, -0.713427712d, -0.6926784018d, 0.1059128479d, 0,
0.6458897819d, -0.5724548511d, -0.5050958653d, 0, -0.6553931414d, 0.7381471625d, 0.159995615d, 0, 0.3910961323d, 0.9188871375d,
-0.05186755998d, 0, -0.4879022471d, -0.5904376907d, 0.6429111375d, 0, 0.6014790094d, 0.7707441366d, -0.2101820095d, 0,
-0.5677173047d, 0.7511360995d, 0.3368851762d, 0, 0.7858573506d, 0.226674665d, 0.5753666838d, 0, -0.4520345543d, -0.604222686d,
-0.6561857263d, 0, 0.002272116345d, 0.4132844051d, -0.9105991643d, 0, -0.5815751419d, -0.5162925989d, 0.6286591339d, 0,
-0.03703704785d, 0.8273785755d, 0.5604221175d, 0, -0.5119692504d, 0.7953543429d, -0.3244980058d, 0, -0.2682417366d,
-0.9572290247d, -0.1084387619d, 0, -0.2322482736d, -0.9679131102d, -0.09594243324d, 0, 0.3554328906d, -0.8881505545d,
0.2913006227d, 0, 0.7346520519d, -0.4371373164d, 0.5188422971d, 0, 0.9985120116d, 0.04659011161d, -0.02833944577d, 0,
-0.3727687496d, -0.9082481361d, 0.1900757285d, 0, 0.91737377d, -0.3483642108d, 0.1925298489d, 0, 0.2714911074d, 0.4147529736d,
-0.8684886582d, 0, 0.5131763485d, -0.7116334161d, 0.4798207128d, 0, -0.8737353606d, 0.18886992d, -0.4482350644d, 0,
0.8460043821d, -0.3725217914d, 0.3814499973d, 0, 0.8978727456d, -0.1780209141d, -0.4026575304d, 0, 0.2178065647d,
-0.9698322841d, -0.1094789531d, 0, -0.1518031304d, -0.7788918132d, -0.6085091231d, 0, -0.2600384876d, -0.4755398075d,
-0.8403819825d, 0, 0.572313509d, -0.7474340931d, -0.3373418503d, 0, -0.7174141009d, 0.1699017182d, -0.6756111411d, 0,
-0.684180784d, 0.02145707593d, -0.7289967412d, 0, -0.2007447902d, 0.06555605789d, -0.9774476623d, 0, -0.1148803697d,
-0.8044887315d, 0.5827524187d, 0, -0.7870349638d, 0.03447489231d, 0.6159443543d, 0, -0.2015596421d, 0.6859872284d,
0.6991389226d, 0, -0.08581082512d, -0.10920836d, -0.9903080513d, 0, 0.5532693395d, 0.7325250401d, -0.396610771d, 0,
-0.1842489331d, -0.9777375055d, -0.1004076743d, 0, 0.0775473789d, -0.9111505856d, 0.4047110257d, 0, 0.1399838409d,
0.7601631212d, -0.6344734459d, 0, 0.4484419361d, -0.845289248d, 0.2904925424d, 0
};
private static final double[] RAND_VECS_2D = {
-0.2700222198d, -0.9628540911d, 0.3863092627d, -0.9223693152d, 0.04444859006d, -0.999011673d, -0.5992523158d, -0.8005602176d,
-0.7819280288d, 0.6233687174d, 0.9464672271d, 0.3227999196d, -0.6514146797d, -0.7587218957d, 0.9378472289d, 0.347048376d,
-0.8497875957d, -0.5271252623d, -0.879042592d, 0.4767432447d, -0.892300288d, -0.4514423508d, -0.379844434d, -0.9250503802d,
-0.9951650832d, 0.0982163789d, 0.7724397808d, -0.6350880136d, 0.7573283322d, -0.6530343002d, -0.9928004525d, -0.119780055d,
-0.0532665713d, 0.9985803285d, 0.9754253726d, -0.2203300762d, -0.7665018163d, 0.6422421394d, 0.991636706d, 0.1290606184d,
-0.994696838d, 0.1028503788d, -0.5379205513d, -0.84299554d, 0.5022815471d, -0.8647041387d, 0.4559821461d, -0.8899889226d,
-0.8659131224d, -0.5001944266d, 0.0879458407d, -0.9961252577d, -0.5051684983d, 0.8630207346d, 0.7753185226d, -0.6315704146d,
-0.6921944612d, 0.7217110418d, -0.5191659449d, -0.8546734591d, 0.8978622882d, -0.4402764035d, -0.1706774107d, 0.9853269617d,
-0.9353430106d, -0.3537420705d, -0.9992404798d, 0.03896746794d, -0.2882064021d, -0.9575683108d, -0.9663811329d, 0.2571137995d,
-0.8759714238d, -0.4823630009d, -0.8303123018d, -0.5572983775d, 0.05110133755d, -0.9986934731d, -0.8558373281d, -0.5172450752d,
0.09887025282d, 0.9951003332d, 0.9189016087d, 0.3944867976d, -0.2439375892d, -0.9697909324d, -0.8121409387d, -0.5834613061d,
-0.9910431363d, 0.1335421355d, 0.8492423985d, -0.5280031709d, -0.9717838994d, -0.2358729591d, 0.9949457207d, 0.1004142068d,
0.6241065508d, -0.7813392434d, 0.662910307d, 0.7486988212d, -0.7197418176d, 0.6942418282d, -0.8143370775d, -0.5803922158d,
0.104521054d, -0.9945226741d, -0.1065926113d, -0.9943027784d, 0.445799684d, -0.8951327509d, 0.105547406d, 0.9944142724d,
-0.992790267d, 0.1198644477d, -0.8334366408d, 0.552615025d, 0.9115561563d, -0.4111755999d, 0.8285544909d, -0.5599084351d,
0.7217097654d, -0.6921957921d, 0.4940492677d, -0.8694339084d, -0.3652321272d, -0.9309164803d, -0.9696606758d, 0.2444548501d,
0.08925509731d, -0.996008799d, 0.5354071276d, -0.8445941083d, -0.1053576186d, 0.9944343981d, -0.9890284586d, 0.1477251101d,
0.004856104961d, 0.9999882091d, 0.9885598478d, 0.1508291331d, 0.9286129562d, -0.3710498316d, -0.5832393863d, -0.8123003252d,
0.3015207509d, 0.9534596146d, -0.9575110528d, 0.2883965738d, 0.9715802154d, -0.2367105511d, 0.229981792d, 0.9731949318d,
0.955763816d, -0.2941352207d, 0.740956116d, 0.6715534485d, -0.9971513787d, -0.07542630764d, 0.6905710663d, -0.7232645452d,
-0.290713703d, -0.9568100872d, 0.5912777791d, -0.8064679708d, -0.9454592212d, -0.325740481d, 0.6664455681d, 0.74555369d,
0.6236134912d, 0.7817328275d, 0.9126993851d, -0.4086316587d, -0.8191762011d, 0.5735419353d, -0.8812745759d, -0.4726046147d,
0.9953313627d, 0.09651672651d, 0.9855650846d, -0.1692969699d, -0.8495980887d, 0.5274306472d, 0.6174853946d, -0.7865823463d,
0.8508156371d, 0.52546432d, 0.9985032451d, -0.05469249926d, 0.1971371563d, -0.9803759185d, 0.6607855748d, -0.7505747292d,
-0.03097494063d, 0.9995201614d, -0.6731660801d, 0.739491331d, -0.7195018362d, -0.6944905383d, 0.9727511689d, 0.2318515979d,
0.9997059088d, -0.0242506907d, 0.4421787429d, -0.8969269532d, 0.9981350961d, -0.061043673d, -0.9173660799d, -0.3980445648d,
-0.8150056635d, -0.5794529907d, -0.8789331304d, 0.4769450202d, 0.0158605829d, 0.999874213d, -0.8095464474d, 0.5870558317d,
-0.9165898907d, -0.3998286786d, -0.8023542565d, 0.5968480938d, -0.5176737917d, 0.8555780767d, -0.8154407307d, -0.5788405779d,
0.4022010347d, -0.9155513791d, -0.9052556868d, -0.4248672045d, 0.7317445619d, 0.6815789728d, -0.5647632201d, -0.8252529947d,
-0.8403276335d, -0.5420788397d, -0.9314281527d, 0.363925262d, 0.5238198472d, 0.8518290719d, 0.7432803869d, -0.6689800195d,
-0.985371561d, -0.1704197369d, 0.4601468731d, 0.88784281d, 0.825855404d, 0.5638819483d, 0.6182366099d, 0.7859920446d,
0.8331502863d, -0.553046653d, 0.1500307506d, 0.9886813308d, -0.662330369d, -0.7492119075d, -0.668598664d, 0.743623444d,
0.7025606278d, 0.7116238924d, -0.5419389763d, -0.8404178401d, -0.3388616456d, 0.9408362159d, 0.8331530315d, 0.5530425174d,
-0.2989720662d, -0.9542618632d, 0.2638522993d, 0.9645630949d, 0.124108739d, -0.9922686234d, -0.7282649308d, -0.6852956957d,
0.6962500149d, 0.7177993569d, -0.9183535368d, 0.3957610156d, -0.6326102274d, -0.7744703352d, -0.9331891859d, -0.359385508d,
-0.1153779357d, -0.9933216659d, 0.9514974788d, -0.3076565421d, -0.08987977445d, -0.9959526224d, 0.6678496916d, 0.7442961705d,
0.7952400393d, -0.6062947138d, -0.6462007402d, -0.7631674805d, -0.2733598753d, 0.9619118351d, 0.9669590226d, -0.254931851d,
-0.9792894595d, 0.2024651934d, -0.5369502995d, -0.8436138784d, -0.270036471d, -0.9628500944d, -0.6400277131d, 0.7683518247d,
-0.7854537493d, -0.6189203566d, 0.06005905383d, -0.9981948257d, -0.02455770378d, 0.9996984141d, -0.65983623d, 0.751409442d,
-0.6253894466d, -0.7803127835d, -0.6210408851d, -0.7837781695d, 0.8348888491d, 0.5504185768d, -0.1592275245d, 0.9872419133d,
0.8367622488d, 0.5475663786d, -0.8675753916d, -0.4973056806d, -0.2022662628d, -0.9793305667d, 0.9399189937d, 0.3413975472d,
0.9877404807d, -0.1561049093d, -0.9034455656d, 0.4287028224d, 0.1269804218d, -0.9919052235d, -0.3819600854d, 0.924178821d,
0.9754625894d, 0.2201652486d, -0.3204015856d, -0.9472818081d, -0.9874760884d, 0.1577687387d, 0.02535348474d, -0.9996785487d,
0.4835130794d, -0.8753371362d, -0.2850799925d, -0.9585037287d, -0.06805516006d, -0.99768156d, -0.7885244045d, -0.6150034663d,
0.3185392127d, -0.9479096845d, 0.8880043089d, 0.4598351306d, 0.6476921488d, -0.7619021462d, 0.9820241299d, 0.1887554194d,
0.9357275128d, -0.3527237187d, -0.8894895414d, 0.4569555293d, 0.7922791302d, 0.6101588153d, 0.7483818261d, 0.6632681526d,
-0.7288929755d, -0.6846276581d, 0.8729032783d, -0.4878932944d, 0.8288345784d, 0.5594937369d, 0.08074567077d, 0.9967347374d,
0.9799148216d, -0.1994165048d, -0.580730673d, -0.8140957471d, -0.4700049791d, -0.8826637636d, 0.2409492979d, 0.9705377045d,
0.9437816757d, -0.3305694308d, -0.8927998638d, -0.4504535528d, -0.8069622304d, 0.5906030467d, 0.06258973166d, 0.9980393407d,
-0.9312597469d, 0.3643559849d, 0.5777449785d, 0.8162173362d, -0.3360095855d, -0.941858566d, 0.697932075d, -0.7161639607d,
-0.002008157227d, -0.9999979837d, -0.1827294312d, -0.9831632392d, -0.6523911722d, 0.7578824173d, -0.4302626911d, -0.9027037258d,
-0.9985126289d, -0.05452091251d, -0.01028102172d, -0.9999471489d, -0.4946071129d, 0.8691166802d, -0.2999350194d, 0.9539596344d,
0.8165471961d, 0.5772786819d, 0.2697460475d, 0.962931498d, -0.7306287391d, -0.6827749597d, -0.7590952064d, -0.6509796216d,
-0.907053853d, 0.4210146171d, -0.5104861064d, -0.8598860013d, 0.8613350597d, 0.5080373165d, 0.5007881595d, -0.8655698812d,
-0.654158152d, 0.7563577938d, -0.8382755311d, -0.545246856d, 0.6940070834d, 0.7199681717d, 0.06950936031d, 0.9975812994d,
0.1702942185d, -0.9853932612d, 0.2695973274d, 0.9629731466d, 0.5519612192d, -0.8338697815d, 0.225657487d, -0.9742067022d,
0.4215262855d, -0.9068161835d, 0.4881873305d, -0.8727388672d, -0.3683854996d, -0.9296731273d, -0.9825390578d, 0.1860564427d,
0.81256471d, 0.5828709909d, 0.3196460933d, -0.9475370046d, 0.9570913859d, 0.2897862643d, -0.6876655497d, -0.7260276109d,
-0.9988770922d, -0.047376731d, -0.1250179027d, 0.992154486d, -0.8280133617d, 0.560708367d, 0.9324863769d, -0.3612051451d,
0.6394653183d, 0.7688199442d, -0.01623847064d, -0.9998681473d, -0.9955014666d, -0.09474613458d, -0.81453315d, 0.580117012d,
0.4037327978d, -0.9148769469d, 0.9944263371d, 0.1054336766d, -0.1624711654d, 0.9867132919d, -0.9949487814d, -0.100383875d,
-0.6995302564d, 0.7146029809d, 0.5263414922d, -0.85027327d, -0.5395221479d, 0.841971408d, 0.6579370318d, 0.7530729462d,
0.01426758847d, -0.9998982128d, -0.6734383991d, 0.7392433447d, 0.639412098d, -0.7688642071d, 0.9211571421d, 0.3891908523d,
-0.146637214d, -0.9891903394d, -0.782318098d, 0.6228791163d, -0.5039610839d, -0.8637263605d, -0.7743120191d, -0.6328039957d,
};
private DistanceFunction distanceFunction = DistanceFunction.EuclideanSq;
private ReturnType returnType = ReturnType.Distance;
private double jitterModifier = 1.0;
private NoiseSampler noiseLookup;
public CellularSampler(int seed) {
super(seed);
noiseLookup = new OpenSimplex2Sampler(seed);
}
public void setDistanceFunction(DistanceFunction distanceFunction) {
this.distanceFunction = distanceFunction;
}
public void setJitterModifier(double jitterModifier) {
this.jitterModifier = jitterModifier;
}
public void setNoiseLookup(NoiseSampler noiseLookup) {
this.noiseLookup = noiseLookup;
}
public void setReturnType(ReturnType returnType) {
this.returnType = returnType;
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
int xr = fastRound(x);
int yr = fastRound(y);
double distance0 = Double.MAX_VALUE;
double distance1 = Double.MAX_VALUE;
double distance2 = Double.MAX_VALUE;
int closestHash = 0;
double cellularJitter = 0.43701595 * jitterModifier;
int xPrimed = (xr - 1) * PRIME_X;
int yPrimedBase = (yr - 1) * PRIME_Y;
Vector2 center = new Vector2(x, y);
switch(distanceFunction) {
default:
case Euclidean:
case EuclideanSq:
for(int xi = xr - 1; xi <= xr + 1; xi++) {
int yPrimed = yPrimedBase;
for(int yi = yr - 1; yi <= yr + 1; yi++) {
int hash = hash(seed, xPrimed, yPrimed);
int idx = hash & (255 << 1);
double vecX = (xi - x) + RAND_VECS_2D[idx] * cellularJitter;
double vecY = (yi - y) + RAND_VECS_2D[idx | 1] * cellularJitter;
double newDistance = vecX * vecX + vecY * vecY;
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
if(newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
center.setX((xi + RAND_VECS_2D[idx] * cellularJitter) / frequency);
center.setZ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / frequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
}
yPrimed += PRIME_Y;
}
xPrimed += PRIME_X;
}
break;
case Manhattan:
for(int xi = xr - 1; xi <= xr + 1; xi++) {
int yPrimed = yPrimedBase;
for(int yi = yr - 1; yi <= yr + 1; yi++) {
int hash = hash(seed, xPrimed, yPrimed);
int idx = hash & (255 << 1);
double vecX = (xi - x) + RAND_VECS_2D[idx] * cellularJitter;
double vecY = (yi - y) + RAND_VECS_2D[idx | 1] * cellularJitter;
double newDistance = fastAbs(vecX) + fastAbs(vecY);
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
if(newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
center.setX((xi + RAND_VECS_2D[idx] * cellularJitter) / frequency);
center.setZ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / frequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
}
yPrimed += PRIME_Y;
}
xPrimed += PRIME_X;
}
break;
case Hybrid:
for(int xi = xr - 1; xi <= xr + 1; xi++) {
int yPrimed = yPrimedBase;
for(int yi = yr - 1; yi <= yr + 1; yi++) {
int hash = hash(seed, xPrimed, yPrimed);
int idx = hash & (255 << 1);
double vecX = (xi - x) + RAND_VECS_2D[idx] * cellularJitter;
double vecY = (yi - y) + RAND_VECS_2D[idx | 1] * cellularJitter;
double newDistance = (fastAbs(vecX) + fastAbs(vecY)) + (vecX * vecX + vecY * vecY);
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
if(newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
center.setX((xi + RAND_VECS_2D[idx] * cellularJitter) / frequency);
center.setZ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / frequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
}
yPrimed += PRIME_Y;
}
xPrimed += PRIME_X;
}
break;
}
if(distanceFunction == DistanceFunction.Euclidean && returnType != ReturnType.CellValue) {
distance0 = fastSqrt(distance0);
if(returnType != ReturnType.CellValue) {
distance1 = fastSqrt(distance1);
}
}
switch(returnType) {
case CellValue:
return closestHash * (1 / 2147483648.0);
case Distance:
return distance0 - 1;
case Distance2:
return distance1 - 1;
case Distance2Add:
return (distance1 + distance0) * 0.5 - 1;
case Distance2Sub:
return distance1 - distance0 - 1;
case Distance2Mul:
return distance1 * distance0 * 0.5 - 1;
case Distance2Div:
return distance0 / distance1 - 1;
case NoiseLookup:
return noiseLookup.getNoise(center.getX(), center.getZ());
case Distance3:
return distance2 - 1;
case Distance3Add:
return (distance2 + distance0) * 0.5 - 1;
case Distance3Sub:
return distance2 - distance0 - 1;
case Distance3Mul:
return distance2 * distance0 - 1;
case Distance3Div:
return distance0 / distance2 - 1;
default:
return 0;
}
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
int xr = fastRound(x);
int yr = fastRound(y);
int zr = fastRound(z);
double distance0 = Double.MAX_VALUE;
double distance1 = Double.MAX_VALUE;
double distance2 = Double.MAX_VALUE;
int closestHash = 0;
double cellularJitter = 0.39614353 * jitterModifier;
int xPrimed = (xr - 1) * PRIME_X;
int yPrimedBase = (yr - 1) * PRIME_Y;
int zPrimedBase = (zr - 1) * PRIME_Z;
Vector3 center = new Vector3(x, y, z);
switch(distanceFunction) {
case Euclidean:
case EuclideanSq:
for(int xi = xr - 1; xi <= xr + 1; xi++) {
int yPrimed = yPrimedBase;
for(int yi = yr - 1; yi <= yr + 1; yi++) {
int zPrimed = zPrimedBase;
for(int zi = zr - 1; zi <= zr + 1; zi++) {
int hash = hash(seed, xPrimed, yPrimed, zPrimed);
int idx = hash & (255 << 2);
double vecX = (xi - x) + RAND_VECS_3D[idx] * cellularJitter;
double vecY = (yi - y) + RAND_VECS_3D[idx | 1] * cellularJitter;
double vecZ = (zi - z) + RAND_VECS_3D[idx | 2] * cellularJitter;
double newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ;
if(newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
center.setX((xi + RAND_VECS_3D[idx] * cellularJitter) / frequency);
center.setY((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / frequency);
center.setZ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / frequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
}
zPrimed += PRIME_Z;
}
yPrimed += PRIME_Y;
}
xPrimed += PRIME_X;
}
break;
case Manhattan:
for(int xi = xr - 1; xi <= xr + 1; xi++) {
int yPrimed = yPrimedBase;
for(int yi = yr - 1; yi <= yr + 1; yi++) {
int zPrimed = zPrimedBase;
for(int zi = zr - 1; zi <= zr + 1; zi++) {
int hash = hash(seed, xPrimed, yPrimed, zPrimed);
int idx = hash & (255 << 2);
double vecX = (xi - x) + RAND_VECS_3D[idx] * cellularJitter;
double vecY = (yi - y) + RAND_VECS_3D[idx | 1] * cellularJitter;
double vecZ = (zi - z) + RAND_VECS_3D[idx | 2] * cellularJitter;
double newDistance = fastAbs(vecX) + fastAbs(vecY) + fastAbs(vecZ);
if(newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
center.setX((xi + RAND_VECS_3D[idx] * cellularJitter) / frequency);
center.setY((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / frequency);
center.setZ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / frequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
}
zPrimed += PRIME_Z;
}
yPrimed += PRIME_Y;
}
xPrimed += PRIME_X;
}
break;
case Hybrid:
for(int xi = xr - 1; xi <= xr + 1; xi++) {
int yPrimed = yPrimedBase;
for(int yi = yr - 1; yi <= yr + 1; yi++) {
int zPrimed = zPrimedBase;
for(int zi = zr - 1; zi <= zr + 1; zi++) {
int hash = hash(seed, xPrimed, yPrimed, zPrimed);
int idx = hash & (255 << 2);
double vecX = (xi - x) + RAND_VECS_3D[idx] * cellularJitter;
double vecY = (yi - y) + RAND_VECS_3D[idx | 1] * cellularJitter;
double vecZ = (zi - z) + RAND_VECS_3D[idx | 2] * cellularJitter;
double newDistance = (fastAbs(vecX) + fastAbs(vecY) + fastAbs(vecZ)) +
(vecX * vecX + vecY * vecY + vecZ * vecZ);
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
if(newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
center.setX((xi + RAND_VECS_3D[idx] * cellularJitter) / frequency);
center.setY((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / frequency);
center.setZ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / frequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
}
zPrimed += PRIME_Z;
}
yPrimed += PRIME_Y;
}
xPrimed += PRIME_X;
}
break;
default:
break;
}
if(distanceFunction == DistanceFunction.Euclidean && returnType != ReturnType.CellValue) {
distance0 = fastSqrt(distance0);
if(returnType != ReturnType.CellValue) {
distance1 = fastSqrt(distance1);
}
}
switch(returnType) {
case CellValue:
return closestHash * (1 / 2147483648.0);
case Distance:
return distance0 - 1;
case Distance2:
return distance1 - 1;
case Distance2Add:
return (distance1 + distance0) * 0.5 - 1;
case Distance2Sub:
return distance1 - distance0 - 1;
case Distance2Mul:
return distance1 * distance0 * 0.5 - 1;
case Distance2Div:
return distance0 / distance1 - 1;
case NoiseLookup:
return noiseLookup.getNoise(center.getX(), center.getY(), center.getZ());
case Distance3:
return distance2 - 1;
case Distance3Add:
return (distance2 + distance0) * 0.5 - 1;
case Distance3Sub:
return distance2 - distance0 - 1;
case Distance3Mul:
return distance2 * distance0 - 1;
case Distance3Div:
return distance0 / distance2 - 1;
default:
return 0;
}
}
public enum DistanceFunction {
Euclidean,
EuclideanSq,
Manhattan,
Hybrid
}
public enum ReturnType {
CellValue,
Distance,
Distance2,
Distance2Add,
Distance2Sub,
Distance2Mul,
Distance2Div,
NoiseLookup,
Distance3,
Distance3Add,
Distance3Sub,
Distance3Mul,
Distance3Div
}
}
@@ -0,0 +1,23 @@
package com.dfsek.terra.api.math.noise.samplers.noise;
/**
* Sampler implementation that returns a constant.
*/
public class ConstantSampler extends NoiseFunction {
private final double constant;
public ConstantSampler(double constant) {
super(0);
this.constant = constant;
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
return constant;
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
return constant;
}
}
@@ -0,0 +1,43 @@
package com.dfsek.terra.api.math.noise.samplers.noise;
import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.paralithic.functions.Function;
import java.util.Map;
/**
* NoiseSampler implementation using a Paralithic expression.
*/
public class ExpressionFunction extends NoiseFunction {
private final Expression expression;
public ExpressionFunction(Map<String, Function> functions, String eq, Map<String, Double> vars) throws ParseException {
super(0);
Parser p = new Parser();
Scope scope = new Scope();
scope.addInvocationVariable("x");
scope.addInvocationVariable("y");
scope.addInvocationVariable("z");
vars.forEach(scope::create);
functions.forEach(p::registerFunction);
expression = p.parse(eq, scope);
frequency = 1;
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
return expression.evaluate(x, 0, y);
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
return expression.evaluate(x, y, z);
}
}
@@ -0,0 +1,111 @@
package com.dfsek.terra.api.math.noise.samplers.noise;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import net.jafama.FastMath;
@SuppressWarnings("ManualMinMaxCalculation")
public abstract class NoiseFunction implements NoiseSampler {
// Hashing
protected static final int PRIME_X = 501125321;
protected static final int PRIME_Y = 1136930381;
protected static final int PRIME_Z = 1720413743;
protected double frequency = 0.02d;
protected int seed;
public NoiseFunction(int seed) {
this.seed = seed;
}
protected static int fastFloor(double f) {
return f >= 0 ? (int) f : (int) f - 1;
}
protected static int hash(int seed, int xPrimed, int yPrimed, int zPrimed) {
int hash = seed ^ xPrimed ^ yPrimed ^ zPrimed;
hash *= 0x27d4eb2d;
return hash;
}
protected static int hash(int seed, int xPrimed, int yPrimed) {
int hash = seed ^ xPrimed ^ yPrimed;
hash *= 0x27d4eb2d;
return hash;
}
protected static int fastRound(double f) {
return f >= 0 ? (int) (f + 0.5f) : (int) (f - 0.5);
}
protected static double lerp(double a, double b, double t) {
return a + t * (b - a);
}
protected static double interpHermite(double t) {
return t * t * (3 - 2 * t);
}
protected static double interpQuintic(double t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
protected static double cubicLerp(double a, double b, double c, double d, double t) {
double p = (d - c) - (a - b);
return t * t * t * p + t * t * ((a - b) - p) + t * (c - a) + b;
}
protected static double fastMin(double a, double b) {
return a < b ? a : b;
}
protected static double fastMax(double a, double b) {
return a > b ? a : b;
}
protected static double fastAbs(double f) {
return f < 0 ? -f : f;
}
protected static double fastSqrt(double f) {
return FastMath.sqrt(f);
}
public void setSeed(int seed) {
this.seed = seed;
}
public double getFrequency() {
return frequency;
}
public void setFrequency(double frequency) {
this.frequency = frequency;
}
@Override
public double getNoise(double x, double y) {
return getNoiseSeeded(seed, x, y);
}
@Override
public double getNoise(double x, double y, double z) {
return getNoiseSeeded(seed, x, y, z);
}
@Override
public double getNoiseSeeded(int seed, double x, double y) {
return getNoiseRaw(seed, x * frequency, y * frequency);
}
@Override
public double getNoiseSeeded(int seed, double x, double y, double z) {
return getNoiseRaw(seed, x * frequency, y * frequency, z * frequency);
}
public abstract double getNoiseRaw(int seed, double x, double y);
public abstract double getNoiseRaw(int seed, double x, double y, double z);
}
@@ -0,0 +1,46 @@
package com.dfsek.terra.api.math.noise.samplers.noise.fractal;
import com.dfsek.terra.api.math.noise.NoiseSampler;
public class BrownianMotionSampler extends FractalNoiseFunction {
public BrownianMotionSampler(int seed, NoiseSampler input) {
super(seed, input);
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
double sum = 0;
double amp = fractalBounding;
for(int i = 0; i < octaves; i++) {
double noise = input.getNoiseSeeded(seed++, x, y);
sum += noise * amp;
amp *= lerp(1.0, fastMin(noise + 1, 2) * 0.5, weightedStrength);
x *= lacunarity;
y *= lacunarity;
amp *= gain;
}
return sum;
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
double sum = 0;
double amp = fractalBounding;
for(int i = 0; i < octaves; i++) {
double noise = input.getNoiseSeeded(seed++, x, y, z);
sum += noise * amp;
amp *= lerp(1.0, (noise + 1) * 0.5, weightedStrength);
x *= lacunarity;
y *= lacunarity;
z *= lacunarity;
amp *= gain;
}
return sum;
}
}
@@ -0,0 +1,48 @@
package com.dfsek.terra.api.math.noise.samplers.noise.fractal;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.NoiseFunction;
public abstract class FractalNoiseFunction extends NoiseFunction {
protected final NoiseSampler input;
protected double fractalBounding = 1 / 1.75;
protected int octaves = 3;
protected double gain = 0.5;
protected double lacunarity = 2.0d;
protected double weightedStrength = 0.0d;
public FractalNoiseFunction(int seed, NoiseSampler input) {
super(seed);
this.input = input;
frequency = 1;
}
public void setWeightedStrength(double weightedStrength) {
this.weightedStrength = weightedStrength;
}
protected void calculateFractalBounding() {
double gain = fastAbs(this.gain);
double amp = gain;
double ampFractal = 1.0;
for(int i = 1; i < octaves; i++) {
ampFractal += amp;
amp *= gain;
}
fractalBounding = 1 / ampFractal;
}
public void setOctaves(int octaves) {
this.octaves = octaves;
calculateFractalBounding();
}
public void setGain(double gain) {
this.gain = gain;
calculateFractalBounding();
}
public void setLacunarity(double lacunarity) {
this.lacunarity = lacunarity;
}
}
@@ -0,0 +1,58 @@
package com.dfsek.terra.api.math.noise.samplers.noise.fractal;
import com.dfsek.terra.api.math.noise.NoiseSampler;
public class PingPongSampler extends FractalNoiseFunction {
private double pingPongStrength = 2.0;
public PingPongSampler(int seed, NoiseSampler input) {
super(seed, input);
}
private static double pingPong(double t) {
t -= (int) (t * 0.5f) << 1;
return t < 1 ? t : 2 - t;
}
public void setPingPongStrength(double strength) {
this.pingPongStrength = strength;
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
double sum = 0;
double amp = fractalBounding;
for(int i = 0; i < octaves; i++) {
double noise = pingPong((input.getNoiseSeeded(seed++, x, y) + 1) * pingPongStrength);
sum += (noise - 0.5) * 2 * amp;
amp *= lerp(1.0, noise, weightedStrength);
x *= lacunarity;
y *= lacunarity;
amp *= gain;
}
return sum;
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
double sum = 0;
double amp = fractalBounding;
for(int i = 0; i < octaves; i++) {
double noise = pingPong((input.getNoiseSeeded(seed++, x, y, z) + 1) * pingPongStrength);
sum += (noise - 0.5) * 2 * amp;
amp *= lerp(1.0, noise, weightedStrength);
x *= lacunarity;
y *= lacunarity;
z *= lacunarity;
amp *= gain;
}
return sum;
}
}
@@ -0,0 +1,47 @@
package com.dfsek.terra.api.math.noise.samplers.noise.fractal;
import com.dfsek.terra.api.math.noise.NoiseSampler;
public class RidgedFractalSampler extends FractalNoiseFunction {
public RidgedFractalSampler(int seed, NoiseSampler input) {
super(seed, input);
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
double sum = 0;
double amp = fractalBounding;
for(int i = 0; i < octaves; i++) {
double noise = fastAbs(input.getNoiseSeeded(seed++, x, y));
sum += (noise * -2 + 1) * amp;
amp *= lerp(1.0, 1 - noise, weightedStrength);
x *= lacunarity;
y *= lacunarity;
amp *= gain;
}
return sum;
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
double sum = 0;
double amp = fractalBounding;
for(int i = 0; i < octaves; i++) {
double noise = fastAbs(input.getNoiseSeeded(seed++, x, y, z));
sum += (noise * -2 + 1) * amp;
amp *= lerp(1.0, 1 - noise, weightedStrength);
x *= lacunarity;
y *= lacunarity;
z *= lacunarity;
amp *= gain;
}
return sum;
}
}
@@ -0,0 +1,39 @@
package com.dfsek.terra.api.math.noise.samplers.noise.random;
import com.dfsek.terra.api.math.noise.samplers.noise.NoiseFunction;
/**
* NoiseSampler implementation to provide random, normally distributed (Gaussian) noise.
*/
public class GaussianNoiseSampler extends NoiseFunction {
private final WhiteNoiseSampler whiteNoiseSampler; // Back with a white noise sampler.
public GaussianNoiseSampler(int seed) {
super(seed);
whiteNoiseSampler = new WhiteNoiseSampler(seed);
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
double v1, v2, s;
do {
v1 = whiteNoiseSampler.getNoiseSeeded(seed++, x, y);
v2 = whiteNoiseSampler.getNoiseSeeded(seed++, x, y);
s = v1 * v1 + v2 * v2;
} while(s >= 1 || s == 0);
double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s) / s);
return v1 * multiplier;
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
double v1, v2, s;
do {
v1 = whiteNoiseSampler.getNoiseSeeded(seed++, x, y, z);
v2 = whiteNoiseSampler.getNoiseSeeded(seed++, x, y, z);
s = v1 * v1 + v2 * v2;
} while(s >= 1 || s == 0);
double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s) / s);
return v1 * multiplier;
}
}
@@ -0,0 +1,49 @@
package com.dfsek.terra.api.math.noise.samplers.noise.random;
import com.dfsek.terra.api.math.noise.samplers.noise.NoiseFunction;
/**
* NoiseSampler implementation to produce random, uniformly distributed (white) noise.
*/
public class WhiteNoiseSampler extends NoiseFunction {
private static final long POSITIVE_POW1 = 0b01111111111L << 52; // Bits that when applied to the exponent/sign section of a double, produce a positive number with a power of 1.
public WhiteNoiseSampler(int seed) {
super(seed);
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
long hashX = Double.doubleToRawLongBits(x) ^ seed;
long hashZ = Double.doubleToRawLongBits(y) ^ seed;
long hash = ((hashX ^ (hashX >>> 32)) + ((hashZ ^ (hashZ >>> 32)) << 32)) ^ seed;
long base = (murmur64(hash) & 0x000fffffffffffffL)
| POSITIVE_POW1; // Sign and exponent
return (Double.longBitsToDouble(base) - 1.5) * 2;
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
long hashX = Double.doubleToRawLongBits(x) ^ seed;
long hashZ = Double.doubleToRawLongBits(y) ^ seed;
long hash = (((hashX ^ (hashX >>> 32)) + ((hashZ ^ (hashZ >>> 32)) << 32)) ^ seed) + Double.doubleToRawLongBits(z);
long base = ((murmur64(hash)) & 0x000fffffffffffffL)
| POSITIVE_POW1; // Sign and exponent
return (Double.longBitsToDouble(base) - 1.5) * 2;
}
/**
* Murmur64 hashing function
*
* @param h Input value
* @return Hashed value
*/
private static long murmur64(long h) {
h ^= h >>> 33;
h *= 0xff51afd7ed558ccdL;
h ^= h >>> 33;
h *= 0xc4ceb9fe1a85ec53L;
h ^= h >>> 33;
return h;
}
}
@@ -0,0 +1,266 @@
package com.dfsek.terra.api.math.noise.samplers.noise.simplex;
/**
* NoiseSampler implementation to provide OpenSimplex2 (Smooth Variant) noise.
*/
public class OpenSimplex2SSampler extends SimplexStyleSampler {
public OpenSimplex2SSampler(int seed) {
super(seed);
}
@Override
@SuppressWarnings("NumericOverflow")
public double getNoiseRaw(int seed, double x, double y) {
// 2D OpenSimplex2S case is a modified 2D simplex noise.
final double SQRT3 = 1.7320508075688772935274463415059;
final double G2 = (3 - SQRT3) / 6;
final double F2 = 0.5f * (SQRT3 - 1);
double s = (x + y) * F2;
x += s;
y += s;
int i = fastFloor(x);
int j = fastFloor(y);
double xi = x - i;
double yi = y - j;
i *= PRIME_X;
j *= PRIME_Y;
int i1 = i + PRIME_X;
int j1 = j + PRIME_Y;
double t = (xi + yi) * G2;
double x0 = xi - t;
double y0 = yi - t;
double a0 = (2.0 / 3.0) - x0 * x0 - y0 * y0;
double value = (a0 * a0) * (a0 * a0) * gradCoord(seed, i, j, x0, y0);
double a1 = 2 * (1 - 2 * G2) * (1 / G2 - 2) * t + ((-2 * (1 - 2 * G2) * (1 - 2 * G2)) + a0);
double x1 = x0 - (1 - 2 * G2);
double y1 = y0 - (1 - 2 * G2);
value += (a1 * a1) * (a1 * a1) * gradCoord(seed, i1, j1, x1, y1);
// Nested conditionals were faster than compact bit logic/arithmetic.
double xmyi = xi - yi;
if(t > G2) {
if(xi + xmyi > 1) {
double x2 = x0 + (3 * G2 - 2);
double y2 = y0 + (3 * G2 - 1);
double a2 = (2.0 / 3.0) - x2 * x2 - y2 * y2;
if(a2 > 0) {
value += (a2 * a2) * (a2 * a2) * gradCoord(seed, i + (PRIME_X << 1), j + PRIME_Y, x2, y2);
}
} else {
double x2 = x0 + G2;
double y2 = y0 + (G2 - 1);
double a2 = (2.0 / 3.0) - x2 * x2 - y2 * y2;
if(a2 > 0) {
value += (a2 * a2) * (a2 * a2) * gradCoord(seed, i, j + PRIME_Y, x2, y2);
}
}
if(yi - xmyi > 1) {
double x3 = x0 + (3 * G2 - 1);
double y3 = y0 + (3 * G2 - 2);
double a3 = (2.0 / 3.0) - x3 * x3 - y3 * y3;
if(a3 > 0) {
value += (a3 * a3) * (a3 * a3) * gradCoord(seed, i + PRIME_X, j + (PRIME_Y << 1), x3, y3);
}
} else {
double x3 = x0 + (G2 - 1);
double y3 = y0 + G2;
double a3 = (2.0 / 3.0) - x3 * x3 - y3 * y3;
if(a3 > 0) {
value += (a3 * a3) * (a3 * a3) * gradCoord(seed, i + PRIME_X, j, x3, y3);
}
}
} else {
if(xi + xmyi < 0) {
double x2 = x0 + (1 - G2);
double y2 = y0 - G2;
double a2 = (2.0 / 3.0) - x2 * x2 - y2 * y2;
if(a2 > 0) {
value += (a2 * a2) * (a2 * a2) * gradCoord(seed, i - PRIME_X, j, x2, y2);
}
} else {
double x2 = x0 + (G2 - 1);
double y2 = y0 + G2;
double a2 = (2.0 / 3.0) - x2 * x2 - y2 * y2;
if(a2 > 0) {
value += (a2 * a2) * (a2 * a2) * gradCoord(seed, i + PRIME_X, j, x2, y2);
}
}
if(yi < xmyi) {
double x2 = x0 - G2;
double y2 = y0 - (G2 - 1);
double a2 = (2.0 / 3.0) - x2 * x2 - y2 * y2;
if(a2 > 0) {
value += (a2 * a2) * (a2 * a2) * gradCoord(seed, i, j - PRIME_Y, x2, y2);
}
} else {
double x2 = x0 + G2;
double y2 = y0 + (G2 - 1);
double a2 = (2.0 / 3.0) - x2 * x2 - y2 * y2;
if(a2 > 0) {
value += (a2 * a2) * (a2 * a2) * gradCoord(seed, i, j + PRIME_Y, x2, y2);
}
}
}
return value * 18.24196194486065;
}
@Override
@SuppressWarnings("NumericOverflow")
public double getNoiseRaw(int seed, double x, double y, double z) {
// 3D OpenSimplex2S case uses two offset rotated cube grids.
final double R3 = (2.0 / 3.0);
double r = (x + y + z) * R3; // Rotation, not skew
x = r - x;
y = r - y;
z = r - z;
int i = fastFloor(x);
int j = fastFloor(y);
int k = fastFloor(z);
double xi = x - i;
double yi = y - j;
double zi = z - k;
i *= PRIME_X;
j *= PRIME_Y;
k *= PRIME_Z;
int seed2 = seed + 1293373;
int xNMask = (int) (-0.5 - xi);
int yNMask = (int) (-0.5 - yi);
int zNMask = (int) (-0.5 - zi);
double x0 = xi + xNMask;
double y0 = yi + yNMask;
double z0 = zi + zNMask;
double a0 = 0.75 - x0 * x0 - y0 * y0 - z0 * z0;
double value = (a0 * a0) * (a0 * a0) * gradCoord(seed, i + (xNMask & PRIME_X), j + (yNMask & PRIME_Y), k + (zNMask & PRIME_Z), x0, y0,
z0);
double x1 = xi - 0.5;
double y1 = yi - 0.5;
double z1 = zi - 0.5;
double a1 = 0.75 - x1 * x1 - y1 * y1 - z1 * z1;
value += (a1 * a1) * (a1 * a1) * gradCoord(seed2, i + PRIME_X, j + PRIME_Y, k + PRIME_Z, x1, y1, z1);
double xAFlipMask0 = ((xNMask | 1) << 1) * x1;
double yAFlipMask0 = ((yNMask | 1) << 1) * y1;
double zAFlipMask0 = ((zNMask | 1) << 1) * z1;
double xAFlipMask1 = (-2 - (xNMask << 2)) * x1 - 1.0;
double yAFlipMask1 = (-2 - (yNMask << 2)) * y1 - 1.0;
double zAFlipMask1 = (-2 - (zNMask << 2)) * z1 - 1.0;
boolean skip5 = false;
double a2 = xAFlipMask0 + a0;
if(a2 > 0) {
double x2 = x0 - (xNMask | 1);
value += (a2 * a2) * (a2 * a2) * gradCoord(seed, i + (~xNMask & PRIME_X), j + (yNMask & PRIME_Y), k + (zNMask & PRIME_Z), x2, y0,
z0);
} else {
double a3 = yAFlipMask0 + zAFlipMask0 + a0;
if(a3 > 0) {
double y3 = y0 - (yNMask | 1);
double z3 = z0 - (zNMask | 1);
value += (a3 * a3) * (a3 * a3) * gradCoord(seed, i + (xNMask & PRIME_X), j + (~yNMask & PRIME_Y), k + (~zNMask & PRIME_Z), x0,
y3, z3);
}
double a4 = xAFlipMask1 + a1;
if(a4 > 0) {
double x4 = (xNMask | 1) + x1;
value += (a4 * a4) * (a4 * a4) * gradCoord(seed2, i + (xNMask & (PRIME_X << 1)), j + PRIME_Y, k + PRIME_Z, x4, y1, z1);
skip5 = true;
}
}
boolean skip9 = false;
double a6 = yAFlipMask0 + a0;
if(a6 > 0) {
double y6 = y0 - (yNMask | 1);
value += (a6 * a6) * (a6 * a6) * gradCoord(seed, i + (xNMask & PRIME_X), j + (~yNMask & PRIME_Y), k + (zNMask & PRIME_Z), x0, y6,
z0);
} else {
double a7 = xAFlipMask0 + zAFlipMask0 + a0;
if(a7 > 0) {
double x7 = x0 - (xNMask | 1);
double z7 = z0 - (zNMask | 1);
value += (a7 * a7) * (a7 * a7) * gradCoord(seed, i + (~xNMask & PRIME_X), j + (yNMask & PRIME_Y), k + (~zNMask & PRIME_Z), x7,
y0, z7);
}
double a8 = yAFlipMask1 + a1;
if(a8 > 0) {
double y8 = (yNMask | 1) + y1;
value += (a8 * a8) * (a8 * a8) * gradCoord(seed2, i + PRIME_X, j + (yNMask & (PRIME_Y << 1)), k + PRIME_Z, x1, y8, z1);
skip9 = true;
}
}
boolean skipD = false;
double aA = zAFlipMask0 + a0;
if(aA > 0) {
double zA = z0 - (zNMask | 1);
value += (aA * aA) * (aA * aA) * gradCoord(seed, i + (xNMask & PRIME_X), j + (yNMask & PRIME_Y), k + (~zNMask & PRIME_Z), x0, y0,
zA);
} else {
double aB = xAFlipMask0 + yAFlipMask0 + a0;
if(aB > 0) {
double xB = x0 - (xNMask | 1);
double yB = y0 - (yNMask | 1);
value += (aB * aB) * (aB * aB) * gradCoord(seed, i + (~xNMask & PRIME_X), j + (~yNMask & PRIME_Y), k + (zNMask & PRIME_Z), xB,
yB, z0);
}
double aC = zAFlipMask1 + a1;
if(aC > 0) {
double zC = (zNMask | 1) + z1;
value += (aC * aC) * (aC * aC) * gradCoord(seed2, i + PRIME_X, j + PRIME_Y, k + (zNMask & (PRIME_Z << 1)), x1, y1, zC);
skipD = true;
}
}
if(!skip5) {
double a5 = yAFlipMask1 + zAFlipMask1 + a1;
if(a5 > 0) {
double y5 = (yNMask | 1) + y1;
double z5 = (zNMask | 1) + z1;
value += (a5 * a5) * (a5 * a5) * gradCoord(seed2, i + PRIME_X, j + (yNMask & (PRIME_Y << 1)), k + (zNMask & (PRIME_Z << 1)),
x1, y5, z5);
}
}
if(!skip9) {
double a9 = xAFlipMask1 + zAFlipMask1 + a1;
if(a9 > 0) {
double x9 = (xNMask | 1) + x1;
double z9 = (zNMask | 1) + z1;
value += (a9 * a9) * (a9 * a9) * gradCoord(seed2, i + (xNMask & (PRIME_X << 1)), j + PRIME_Y, k + (zNMask & (PRIME_Z << 1)), x9,
y1, z9);
}
}
if(!skipD) {
double aD = xAFlipMask1 + yAFlipMask1 + a1;
if(aD > 0) {
double xD = (xNMask | 1) + x1;
double yD = (yNMask | 1) + y1;
value += (aD * aD) * (aD * aD) * gradCoord(seed2, i + (xNMask & (PRIME_X << 1)), j + (yNMask & (PRIME_Y << 1)), k + PRIME_Z,
xD, yD, z1);
}
}
return value * 9.046026385208288;
}
}
@@ -0,0 +1,155 @@
package com.dfsek.terra.api.math.noise.samplers.noise.simplex;
/**
* NoiseSampler implementation to provide OpenSimplex2 noise.
*/
public class OpenSimplex2Sampler extends SimplexStyleSampler {
private static final double SQRT3 = 1.7320508075688772935274463415059;
public OpenSimplex2Sampler(int seed) {
super(seed);
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
// 2D OpenSimplex2 case uses the same algorithm as ordinary Simplex.
final double G2 = (3 - SQRT3) / 6;
final double F2 = 0.5f * (SQRT3 - 1);
double s = (x + y) * F2;
x += s;
y += s;
int i = fastFloor(x);
int j = fastFloor(y);
double xi = x - i;
double yi = y - j;
double t = (xi + yi) * G2;
double x0 = xi - t;
double y0 = yi - t;
i *= PRIME_X;
j *= PRIME_Y;
double n0, n1, n2;
double a = 0.5 - x0 * x0 - y0 * y0;
if(a <= 0) n0 = 0;
else {
n0 = (a * a) * (a * a) * gradCoord(seed, i, j, x0, y0);
}
double c = 2 * (1 - 2 * G2) * (1 / G2 - 2) * t + ((-2 * (1 - 2 * G2) * (1 - 2 * G2)) + a);
if(c <= 0) n2 = 0;
else {
double x2 = x0 + (2 * G2 - 1);
double y2 = y0 + (2 * G2 - 1);
n2 = (c * c) * (c * c) * gradCoord(seed, i + PRIME_X, j + PRIME_Y, x2, y2);
}
if(y0 > x0) {
double x1 = x0 + G2;
double y1 = y0 + (G2 - 1);
double b = 0.5 - x1 * x1 - y1 * y1;
if(b <= 0) n1 = 0;
else {
n1 = (b * b) * (b * b) * gradCoord(seed, i, j + PRIME_Y, x1, y1);
}
} else {
double x1 = x0 + (G2 - 1);
double y1 = y0 + G2;
double b = 0.5 - x1 * x1 - y1 * y1;
if(b <= 0) n1 = 0;
else {
n1 = (b * b) * (b * b) * gradCoord(seed, i + PRIME_X, j, x1, y1);
}
}
return (n0 + n1 + n2) * 99.83685446303647f;
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
// 3D OpenSimplex2Sampler case uses two offset rotated cube grids.
final double R3 = (2.0 / 3.0);
double r = (x + y + z) * R3; // Rotation, not skew
x = r - x;
y = r - y;
z = r - z;
int i = fastRound(x);
int j = fastRound(y);
int k = fastRound(z);
double x0 = x - i;
double y0 = y - j;
double z0 = z - k;
int xNSign = (int) (-1.0 - x0) | 1;
int yNSign = (int) (-1.0 - y0) | 1;
int zNSign = (int) (-1.0 - z0) | 1;
double ax0 = xNSign * -x0;
double ay0 = yNSign * -y0;
double az0 = zNSign * -z0;
i *= PRIME_X;
j *= PRIME_Y;
k *= PRIME_Z;
double value = 0;
double a = (0.6f - x0 * x0) - (y0 * y0 + z0 * z0);
for(int l = 0; ; l++) {
if(a > 0) {
value += (a * a) * (a * a) * gradCoord(seed, i, j, k, x0, y0, z0);
}
if(ax0 >= ay0 && ax0 >= az0) {
double b = a + ax0 + ax0;
if(b > 1) {
b -= 1;
value += (b * b) * (b * b) * gradCoord(seed, i - xNSign * PRIME_X, j, k, x0 + xNSign, y0, z0);
}
} else if(ay0 > ax0 && ay0 >= az0) {
double b = a + ay0 + ay0;
if(b > 1) {
b -= 1;
value += (b * b) * (b * b) * gradCoord(seed, i, j - yNSign * PRIME_Y, k, x0, y0 + yNSign, z0);
}
} else {
double b = a + az0 + az0;
if(b > 1) {
b -= 1;
value += (b * b) * (b * b) * gradCoord(seed, i, j, k - zNSign * PRIME_Z, x0, y0, z0 + zNSign);
}
}
if(l == 1) break;
ax0 = 0.5 - ax0;
ay0 = 0.5 - ay0;
az0 = 0.5 - az0;
x0 = xNSign * ax0;
y0 = yNSign * ay0;
z0 = zNSign * az0;
a += (0.75 - ax0) - (ay0 + az0);
i += (xNSign >> 1) & PRIME_X;
j += (yNSign >> 1) & PRIME_Y;
k += (zNSign >> 1) & PRIME_Z;
xNSign = -xNSign;
yNSign = -yNSign;
zNSign = -zNSign;
seed = ~seed;
}
return value * 32.69428253173828125;
}
}
@@ -0,0 +1,69 @@
package com.dfsek.terra.api.math.noise.samplers.noise.simplex;
/**
* NoiseSampler implementation to provide Perlin Noise.
*/
public class PerlinSampler extends SimplexStyleSampler {
public PerlinSampler(int seed) {
super(seed);
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
int x0 = fastFloor(x);
int y0 = fastFloor(y);
double xd0 = x - x0;
double yd0 = y - y0;
double xd1 = xd0 - 1;
double yd1 = yd0 - 1;
double xs = interpQuintic(xd0);
double ys = interpQuintic(yd0);
x0 *= PRIME_X;
y0 *= PRIME_Y;
int x1 = x0 + PRIME_X;
int y1 = y0 + PRIME_Y;
double xf0 = lerp(gradCoord(seed, x0, y0, xd0, yd0), gradCoord(seed, x1, y0, xd1, yd0), xs);
double xf1 = lerp(gradCoord(seed, x0, y1, xd0, yd1), gradCoord(seed, x1, y1, xd1, yd1), xs);
return lerp(xf0, xf1, ys) * 1.4247691104677813;
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
int x0 = fastFloor(x);
int y0 = fastFloor(y);
int z0 = fastFloor(z);
double xd0 = x - x0;
double yd0 = y - y0;
double zd0 = z - z0;
double xd1 = xd0 - 1;
double yd1 = yd0 - 1;
double zd1 = zd0 - 1;
double xs = interpQuintic(xd0);
double ys = interpQuintic(yd0);
double zs = interpQuintic(zd0);
x0 *= PRIME_X;
y0 *= PRIME_Y;
z0 *= PRIME_Z;
int x1 = x0 + PRIME_X;
int y1 = y0 + PRIME_Y;
int z1 = z0 + PRIME_Z;
double xf00 = lerp(gradCoord(seed, x0, y0, z0, xd0, yd0, zd0), gradCoord(seed, x1, y0, z0, xd1, yd0, zd0), xs);
double xf10 = lerp(gradCoord(seed, x0, y1, z0, xd0, yd1, zd0), gradCoord(seed, x1, y1, z0, xd1, yd1, zd0), xs);
double xf01 = lerp(gradCoord(seed, x0, y0, z1, xd0, yd0, zd1), gradCoord(seed, x1, y0, z1, xd1, yd0, zd1), xs);
double xf11 = lerp(gradCoord(seed, x0, y1, z1, xd0, yd1, zd1), gradCoord(seed, x1, y1, z1, xd1, yd1, zd1), xs);
double yf0 = lerp(xf00, xf10, ys);
double yf1 = lerp(xf01, xf11, ys);
return lerp(yf0, yf1, zs) * 0.964921414852142333984375;
}
}
@@ -0,0 +1,100 @@
package com.dfsek.terra.api.math.noise.samplers.noise.simplex;
import com.dfsek.terra.api.math.noise.samplers.noise.NoiseFunction;
/**
* Abstract NoiseSampler implementation for simplex-style noise functions.
*/
public abstract class SimplexStyleSampler extends NoiseFunction {
protected static final double[] GRADIENTS_2_D = {
0.130526192220052d, 0.99144486137381d, 0.38268343236509d, 0.923879532511287d, 0.608761429008721d, 0.793353340291235d,
0.793353340291235d, 0.608761429008721d, 0.923879532511287d, 0.38268343236509d, 0.99144486137381d, 0.130526192220051d,
0.99144486137381d, -0.130526192220051d, 0.923879532511287d, -0.38268343236509d, 0.793353340291235d, -0.60876142900872d,
0.608761429008721d, -0.793353340291235d, 0.38268343236509d, -0.923879532511287d, 0.130526192220052d, -0.99144486137381d,
-0.130526192220052d, -0.99144486137381d, -0.38268343236509d, -0.923879532511287d, -0.608761429008721d, -0.793353340291235d,
-0.793353340291235d, -0.608761429008721d, -0.923879532511287d, -0.38268343236509d, -0.99144486137381d, -0.130526192220052d,
-0.99144486137381d, 0.130526192220051d, -0.923879532511287d, 0.38268343236509d, -0.793353340291235d, 0.608761429008721d,
-0.608761429008721d, 0.793353340291235d, -0.38268343236509d, 0.923879532511287d, -0.130526192220052d, 0.99144486137381d,
0.130526192220052d, 0.99144486137381d, 0.38268343236509d, 0.923879532511287d, 0.608761429008721d, 0.793353340291235d,
0.793353340291235d, 0.608761429008721d, 0.923879532511287d, 0.38268343236509d, 0.99144486137381d, 0.130526192220051d,
0.99144486137381d, -0.130526192220051d, 0.923879532511287d, -0.38268343236509d, 0.793353340291235d, -0.60876142900872d,
0.608761429008721d, -0.793353340291235d, 0.38268343236509d, -0.923879532511287d, 0.130526192220052d, -0.99144486137381d,
-0.130526192220052d, -0.99144486137381d, -0.38268343236509d, -0.923879532511287d, -0.608761429008721d, -0.793353340291235d,
-0.793353340291235d, -0.608761429008721d, -0.923879532511287d, -0.38268343236509d, -0.99144486137381d, -0.130526192220052d,
-0.99144486137381d, 0.130526192220051d, -0.923879532511287d, 0.38268343236509d, -0.793353340291235d, 0.608761429008721d,
-0.608761429008721d, 0.793353340291235d, -0.38268343236509d, 0.923879532511287d, -0.130526192220052d, 0.99144486137381d,
0.130526192220052d, 0.99144486137381d, 0.38268343236509d, 0.923879532511287d, 0.608761429008721d, 0.793353340291235d,
0.793353340291235d, 0.608761429008721d, 0.923879532511287d, 0.38268343236509d, 0.99144486137381d, 0.130526192220051d,
0.99144486137381d, -0.130526192220051d, 0.923879532511287d, -0.38268343236509d, 0.793353340291235d, -0.60876142900872d,
0.608761429008721d, -0.793353340291235d, 0.38268343236509d, -0.923879532511287d, 0.130526192220052d, -0.99144486137381d,
-0.130526192220052d, -0.99144486137381d, -0.38268343236509d, -0.923879532511287d, -0.608761429008721d, -0.793353340291235d,
-0.793353340291235d, -0.608761429008721d, -0.923879532511287d, -0.38268343236509d, -0.99144486137381d, -0.130526192220052d,
-0.99144486137381d, 0.130526192220051d, -0.923879532511287d, 0.38268343236509d, -0.793353340291235d, 0.608761429008721d,
-0.608761429008721d, 0.793353340291235d, -0.38268343236509d, 0.923879532511287d, -0.130526192220052d, 0.99144486137381d,
0.130526192220052d, 0.99144486137381d, 0.38268343236509d, 0.923879532511287d, 0.608761429008721d, 0.793353340291235d,
0.793353340291235d, 0.608761429008721d, 0.923879532511287d, 0.38268343236509d, 0.99144486137381d, 0.130526192220051d,
0.99144486137381d, -0.130526192220051d, 0.923879532511287d, -0.38268343236509d, 0.793353340291235d, -0.60876142900872d,
0.608761429008721d, -0.793353340291235d, 0.38268343236509d, -0.923879532511287d, 0.130526192220052d, -0.99144486137381d,
-0.130526192220052d, -0.99144486137381d, -0.38268343236509d, -0.923879532511287d, -0.608761429008721d, -0.793353340291235d,
-0.793353340291235d, -0.608761429008721d, -0.923879532511287d, -0.38268343236509d, -0.99144486137381d, -0.130526192220052d,
-0.99144486137381d, 0.130526192220051d, -0.923879532511287d, 0.38268343236509d, -0.793353340291235d, 0.608761429008721d,
-0.608761429008721d, 0.793353340291235d, -0.38268343236509d, 0.923879532511287d, -0.130526192220052d, 0.99144486137381d,
0.130526192220052d, 0.99144486137381d, 0.38268343236509d, 0.923879532511287d, 0.608761429008721d, 0.793353340291235d,
0.793353340291235d, 0.608761429008721d, 0.923879532511287d, 0.38268343236509d, 0.99144486137381d, 0.130526192220051d,
0.99144486137381d, -0.130526192220051d, 0.923879532511287d, -0.38268343236509d, 0.793353340291235d, -0.60876142900872d,
0.608761429008721d, -0.793353340291235d, 0.38268343236509d, -0.923879532511287d, 0.130526192220052d, -0.99144486137381d,
-0.130526192220052d, -0.99144486137381d, -0.38268343236509d, -0.923879532511287d, -0.608761429008721d, -0.793353340291235d,
-0.793353340291235d, -0.608761429008721d, -0.923879532511287d, -0.38268343236509d, -0.99144486137381d, -0.130526192220052d,
-0.99144486137381d, 0.130526192220051d, -0.923879532511287d, 0.38268343236509d, -0.793353340291235d, 0.608761429008721d,
-0.608761429008721d, 0.793353340291235d, -0.38268343236509d, 0.923879532511287d, -0.130526192220052d, 0.99144486137381d,
0.38268343236509d, 0.923879532511287d, 0.923879532511287d, 0.38268343236509d, 0.923879532511287d, -0.38268343236509d,
0.38268343236509d, -0.923879532511287d, -0.38268343236509d, -0.923879532511287d, -0.923879532511287d, -0.38268343236509d,
-0.923879532511287d, 0.38268343236509d, -0.38268343236509d, 0.923879532511287d,
};
protected static final double[] GRADIENTS_3D = {
0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0,
1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0,
1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0,
0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0,
1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0,
1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0,
0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0,
1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0,
1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0,
0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0,
1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0,
1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0,
0, 1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0,
1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, -1, 0,
1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, -1, 0, 0,
1, 1, 0, 0, 0, -1, 1, 0, -1, 1, 0, 0, 0, -1, -1, 0
};
public SimplexStyleSampler(int seed) {
super(seed);
}
protected static double gradCoord(int seed, int xPrimed, int yPrimed, double xd, double yd) {
int hash = hash(seed, xPrimed, yPrimed);
hash ^= hash >> 15;
hash &= 127 << 1;
double xg = GRADIENTS_2_D[hash];
double yg = GRADIENTS_2_D[hash | 1];
return xd * xg + yd * yg;
}
protected static double gradCoord(int seed, int xPrimed, int yPrimed, int zPrimed, double xd, double yd, double zd) {
int hash = hash(seed, xPrimed, yPrimed, zPrimed);
hash ^= hash >> 15;
hash &= 63 << 2;
double xg = GRADIENTS_3D[hash];
double yg = GRADIENTS_3D[hash | 1];
double zg = GRADIENTS_3D[hash | 2];
return xd * xg + yd * yg + zd * zg;
}
}
@@ -0,0 +1,104 @@
package com.dfsek.terra.api.math.noise.samplers.noise.value;
public class ValueCubicSampler extends ValueStyleNoise {
public ValueCubicSampler(int seed) {
super(seed);
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
int x1 = fastFloor(x);
int y1 = fastFloor(y);
double xs = x - x1;
double ys = y - y1;
x1 *= PRIME_X;
y1 *= PRIME_Y;
int x0 = x1 - PRIME_X;
int y0 = y1 - PRIME_Y;
int x2 = x1 + PRIME_X;
int y2 = y1 + PRIME_Y;
int x3 = x1 + (PRIME_X << 1);
int y3 = y1 + (PRIME_Y << 1);
return cubicLerp(
cubicLerp(valCoord(seed, x0, y0), valCoord(seed, x1, y0), valCoord(seed, x2, y0), valCoord(seed, x3, y0),
xs),
cubicLerp(valCoord(seed, x0, y1), valCoord(seed, x1, y1), valCoord(seed, x2, y1), valCoord(seed, x3, y1),
xs),
cubicLerp(valCoord(seed, x0, y2), valCoord(seed, x1, y2), valCoord(seed, x2, y2), valCoord(seed, x3, y2),
xs),
cubicLerp(valCoord(seed, x0, y3), valCoord(seed, x1, y3), valCoord(seed, x2, y3), valCoord(seed, x3, y3),
xs),
ys) * (1 / (1.5 * 1.5));
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
int x1 = fastFloor(x);
int y1 = fastFloor(y);
int z1 = fastFloor(z);
double xs = x - x1;
double ys = y - y1;
double zs = z - z1;
x1 *= PRIME_X;
y1 *= PRIME_Y;
z1 *= PRIME_Z;
int x0 = x1 - PRIME_X;
int y0 = y1 - PRIME_Y;
int z0 = z1 - PRIME_Z;
int x2 = x1 + PRIME_X;
int y2 = y1 + PRIME_Y;
int z2 = z1 + PRIME_Z;
int x3 = x1 + (PRIME_X << 1);
int y3 = y1 + (PRIME_Y << 1);
int z3 = z1 + (PRIME_Z << 1);
return cubicLerp(
cubicLerp(
cubicLerp(valCoord(seed, x0, y0, z0), valCoord(seed, x1, y0, z0), valCoord(seed, x2, y0, z0),
valCoord(seed, x3, y0, z0), xs),
cubicLerp(valCoord(seed, x0, y1, z0), valCoord(seed, x1, y1, z0), valCoord(seed, x2, y1, z0),
valCoord(seed, x3, y1, z0), xs),
cubicLerp(valCoord(seed, x0, y2, z0), valCoord(seed, x1, y2, z0), valCoord(seed, x2, y2, z0),
valCoord(seed, x3, y2, z0), xs),
cubicLerp(valCoord(seed, x0, y3, z0), valCoord(seed, x1, y3, z0), valCoord(seed, x2, y3, z0),
valCoord(seed, x3, y3, z0), xs),
ys),
cubicLerp(
cubicLerp(valCoord(seed, x0, y0, z1), valCoord(seed, x1, y0, z1), valCoord(seed, x2, y0, z1),
valCoord(seed, x3, y0, z1), xs),
cubicLerp(valCoord(seed, x0, y1, z1), valCoord(seed, x1, y1, z1), valCoord(seed, x2, y1, z1),
valCoord(seed, x3, y1, z1), xs),
cubicLerp(valCoord(seed, x0, y2, z1), valCoord(seed, x1, y2, z1), valCoord(seed, x2, y2, z1),
valCoord(seed, x3, y2, z1), xs),
cubicLerp(valCoord(seed, x0, y3, z1), valCoord(seed, x1, y3, z1), valCoord(seed, x2, y3, z1),
valCoord(seed, x3, y3, z1), xs),
ys),
cubicLerp(
cubicLerp(valCoord(seed, x0, y0, z2), valCoord(seed, x1, y0, z2), valCoord(seed, x2, y0, z2),
valCoord(seed, x3, y0, z2), xs),
cubicLerp(valCoord(seed, x0, y1, z2), valCoord(seed, x1, y1, z2), valCoord(seed, x2, y1, z2),
valCoord(seed, x3, y1, z2), xs),
cubicLerp(valCoord(seed, x0, y2, z2), valCoord(seed, x1, y2, z2), valCoord(seed, x2, y2, z2),
valCoord(seed, x3, y2, z2), xs),
cubicLerp(valCoord(seed, x0, y3, z2), valCoord(seed, x1, y3, z2), valCoord(seed, x2, y3, z2),
valCoord(seed, x3, y3, z2), xs),
ys),
cubicLerp(
cubicLerp(valCoord(seed, x0, y0, z3), valCoord(seed, x1, y0, z3), valCoord(seed, x2, y0, z3),
valCoord(seed, x3, y0, z3), xs),
cubicLerp(valCoord(seed, x0, y1, z3), valCoord(seed, x1, y1, z3), valCoord(seed, x2, y1, z3),
valCoord(seed, x3, y1, z3), xs),
cubicLerp(valCoord(seed, x0, y2, z3), valCoord(seed, x1, y2, z3), valCoord(seed, x2, y2, z3),
valCoord(seed, x3, y2, z3), xs),
cubicLerp(valCoord(seed, x0, y3, z3), valCoord(seed, x1, y3, z3), valCoord(seed, x2, y3, z3),
valCoord(seed, x3, y3, z3), xs),
ys),
zs) * (1 / (1.5 * 1.5 * 1.5));
}
}
@@ -0,0 +1,54 @@
package com.dfsek.terra.api.math.noise.samplers.noise.value;
public class ValueSampler extends ValueStyleNoise {
public ValueSampler(int seed) {
super(seed);
}
@Override
public double getNoiseRaw(int seed, double x, double y) {
int x0 = fastFloor(x);
int y0 = fastFloor(y);
double xs = interpHermite(x - x0);
double ys = interpHermite(y - y0);
x0 *= PRIME_X;
y0 *= PRIME_Y;
int x1 = x0 + PRIME_X;
int y1 = y0 + PRIME_Y;
double xf0 = lerp(valCoord(seed, x0, y0), valCoord(seed, x1, y0), xs);
double xf1 = lerp(valCoord(seed, x0, y1), valCoord(seed, x1, y1), xs);
return lerp(xf0, xf1, ys);
}
@Override
public double getNoiseRaw(int seed, double x, double y, double z) {
int x0 = fastFloor(x);
int y0 = fastFloor(y);
int z0 = fastFloor(z);
double xs = interpHermite(x - x0);
double ys = interpHermite(y - y0);
double zs = interpHermite(z - z0);
x0 *= PRIME_X;
y0 *= PRIME_Y;
z0 *= PRIME_Z;
int x1 = x0 + PRIME_X;
int y1 = y0 + PRIME_Y;
int z1 = z0 + PRIME_Z;
double xf00 = lerp(valCoord(seed, x0, y0, z0), valCoord(seed, x1, y0, z0), xs);
double xf10 = lerp(valCoord(seed, x0, y1, z0), valCoord(seed, x1, y1, z0), xs);
double xf01 = lerp(valCoord(seed, x0, y0, z1), valCoord(seed, x1, y0, z1), xs);
double xf11 = lerp(valCoord(seed, x0, y1, z1), valCoord(seed, x1, y1, z1), xs);
double yf0 = lerp(xf00, xf10, ys);
double yf1 = lerp(xf01, xf11, ys);
return lerp(yf0, yf1, zs);
}
}
@@ -0,0 +1,25 @@
package com.dfsek.terra.api.math.noise.samplers.noise.value;
import com.dfsek.terra.api.math.noise.samplers.noise.NoiseFunction;
public abstract class ValueStyleNoise extends NoiseFunction {
public ValueStyleNoise(int seed) {
super(seed);
}
protected static double valCoord(int seed, int xPrimed, int yPrimed) {
int hash = hash(seed, xPrimed, yPrimed);
hash *= hash;
hash ^= hash << 19;
return hash * (1 / 2147483648.0);
}
protected static double valCoord(int seed, int xPrimed, int yPrimed, int zPrimed) {
int hash = hash(seed, xPrimed, yPrimed, zPrimed);
hash *= hash;
hash ^= hash << 19;
return hash * (1 / 2147483648.0);
}
}
@@ -0,0 +1,27 @@
package com.dfsek.terra.api.math.paralithic;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
public class BlankFunction implements DynamicFunction {
private final int args;
public BlankFunction(int args) {
this.args = args;
}
@Override
public int getArgNumber() {
return args;
}
@Override
public double eval(double... d) {
return 0;
}
@Override
public boolean isStateless() {
return true;
}
}
@@ -0,0 +1,44 @@
package com.dfsek.terra.api.math.paralithic.defined;
import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
public class UserDefinedFunction implements DynamicFunction {
private final Expression expression;
private final int args;
protected UserDefinedFunction(Expression expression, int args) {
this.expression = expression;
this.args = args;
}
@Override
public double eval(double... args) {
return expression.evaluate(args);
}
@Override
public boolean isStateless() {
return true;
}
@Override
public int getArgNumber() {
return args;
}
public static UserDefinedFunction newInstance(FunctionTemplate template, Parser parser, Scope parent) throws ParseException {
Scope functionScope = new Scope().withParent(parent);
template.getArgs().forEach(functionScope::addInvocationVariable);
return new UserDefinedFunction(parser.parse(template.getFunction(), functionScope), template.getArgs().size());
}
}
@@ -0,0 +1,7 @@
package com.dfsek.terra.api.math.paralithic.noise;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
public interface NoiseFunction extends DynamicFunction {
}
@@ -1,42 +1,30 @@
package com.dfsek.terra.math;
package com.dfsek.terra.api.math.paralithic.noise;
import com.dfsek.terra.api.math.FastNoiseLite;
import com.dfsek.terra.generation.config.NoiseBuilder;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.util.hash.HashMapDoubleDouble;
import parsii.eval.Expression;
import java.util.List;
public class NoiseFunction2 implements NoiseFunction {
private final FastNoiseLite gen;
private final NoiseSampler gen;
private final Cache cache = new Cache();
public NoiseFunction2(long seed, NoiseBuilder builder) {
this.gen = builder.build((int) seed);
public NoiseFunction2(NoiseSampler gen) {
this.gen = gen;
}
@Override
public int getNumberOfArguments() {
public int getArgNumber() {
return 2;
}
@Override
public double eval(List<Expression> list) {
return cache.get(gen, list.get(0).evaluate(), list.get(1).evaluate());
}
/**
* Evaluate without cache. For testing.
*
* @param list Parameters.
* @return Result.
*/
public double evalNoCache(List<Expression> list) {
return gen.getNoise(list.get(0).evaluate(), list.get(1).evaluate());
public double eval(double... args) {
return cache.get(gen, args[0], args[1]);
}
@Override
public boolean isNaturalFunction() {
public boolean isStateless() {
return true;
}
@@ -44,7 +32,11 @@ public class NoiseFunction2 implements NoiseFunction {
private static final long serialVersionUID = 8915092734723467010L;
private static final int cacheSize = 384;
public double get(FastNoiseLite noise, double x, double z) {
public Cache() {
super(cacheSize);
}
public double get(NoiseSampler noise, double x, double z) {
double xx = x >= 0 ? x * 2 : x * -2 - 1;
double zz = z >= 0 ? z * 2 : z * -2 - 1;
double key = (xx >= zz) ? (xx * xx + xx + zz) : (zz * zz + xx);
@@ -55,7 +47,7 @@ public class NoiseFunction2 implements NoiseFunction {
return (value == 4.9E-324D ? addAndReturn(noise.getNoise(x, z), key) : value);
}
private double addAndReturn(double value, double key) {
private synchronized double addAndReturn(double value, double key) {
this.put(key, value);
return value;
}
@@ -0,0 +1,26 @@
package com.dfsek.terra.api.math.paralithic.noise;
import com.dfsek.terra.api.math.noise.NoiseSampler;
public class NoiseFunction3 implements NoiseFunction {
private final NoiseSampler gen;
public NoiseFunction3(NoiseSampler gen) {
this.gen = gen;
}
@Override
public int getArgNumber() {
return 3;
}
@Override
public double eval(double... args) {
return gen.getNoise(args[0], args[1], args[2]);
}
@Override
public boolean isStateless() {
return true;
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.procgen.pixel;
package com.dfsek.terra.api.math.pixel;
public class Distribution {
public Distribution(Rectangle bound, int numPoints, double minRad) {
@@ -1,4 +1,4 @@
package com.dfsek.terra.procgen.pixel;
package com.dfsek.terra.api.math.pixel;
import com.dfsek.terra.api.math.vector.Vector2;
@@ -1,4 +1,4 @@
package com.dfsek.terra.procgen.pixel;
package com.dfsek.terra.api.math.pixel;
import com.dfsek.terra.api.math.vector.Vector2;
import net.jafama.FastMath;
@@ -106,6 +106,11 @@ public class Location implements Cloneable {
return this;
}
public Location add(Location add) {
vector.add(add.toVector());
return this;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Location)) {
@@ -160,4 +165,9 @@ public class Location implements Cloneable {
public Vector3 toVector() {
return vector.clone();
}
@Override
public String toString() {
return "[" + world + ": (" + getX() + ", " + getY() + ", " + getZ() + ")]";
}
}
@@ -1,11 +1,11 @@
package com.dfsek.terra.api.math.vector;
import com.dfsek.terra.api.math.MathUtil;
import net.jafama.FastMath;
/**
* oh yeah
*/
@SuppressWarnings("unused")
public class Vector2 implements Cloneable {
private double x;
private double z;
@@ -157,11 +157,9 @@ public class Vector2 implements Cloneable {
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Vector2)) {
return false;
}
if(!(obj instanceof Vector2)) return false;
Vector2 other = (Vector2) obj;
return other.x == this.x && other.z == this.z;
return MathUtil.equals(this.x, other.x) && MathUtil.equals(this.z, other.z);
}
@Override
@@ -173,6 +171,20 @@ public class Vector2 implements Cloneable {
}
}
public Vector2 add(double x, double z) {
this.x += x;
this.z += z;
return this;
}
public int getBlockX() {
return FastMath.floorToInt(x);
}
public int getBlockZ() {
return FastMath.floorToInt(z);
}
@Override
public String toString() {
return "(" + x + ", " + z + ")";
@@ -1,15 +1,15 @@
package com.dfsek.terra.api.math.vector;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.api.platform.world.World;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
/**
* 3D Mutable Vector
*/
public class Vector3 implements Cloneable {
/**
* Threshold for fuzzy equals().
*/
private static final double epsilon = 0.000001;
private double x;
private double y;
@@ -21,15 +21,6 @@ public class Vector3 implements Cloneable {
this.z = z;
}
/**
* Get the threshold used for equals().
*
* @return The epsilon.
*/
public static double getEpsilon() {
return epsilon;
}
public double getZ() {
return z;
}
@@ -113,13 +104,17 @@ public class Vector3 implements Cloneable {
return FastMath.sqrt(lengthSquared());
}
public double inverseLength() {
return FastMath.invSqrtQuick(lengthSquared());
}
/**
* Returns if a vector is normalized
*
* @return whether the vector is normalised
*/
public boolean isNormalized() {
return Math.abs(this.lengthSquared() - 1) < getEpsilon();
return MathUtil.equals(this.lengthSquared(), 1);
}
/**
@@ -292,7 +287,7 @@ public class Vector3 implements Cloneable {
}
public Vector3 normalize() {
return this.multiply(1D / this.length());
return this.multiply(this.inverseLength());
}
public Vector3 subtract(int x, int y, int z) {
@@ -333,12 +328,14 @@ public class Vector3 implements Cloneable {
*/
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Vector3)) {
return false;
}
if(!(obj instanceof Vector3)) return false;
Vector3 other = (Vector3) obj;
return Math.abs(x - other.x) < epsilon && Math.abs(y - other.y) < epsilon && Math.abs(z - other.z) < epsilon && (this.getClass().equals(obj.getClass()));
return MathUtil.equals(x, other.x) && MathUtil.equals(y, other.y) && MathUtil.equals(x, other.z);
}
@Override
public String toString() {
return "(" + getX() + ", " + getY() + ", " + getZ() + ")";
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.procgen.voxel;
package com.dfsek.terra.api.math.voxel;
import com.dfsek.terra.api.math.vector.Vector3;
@@ -1,10 +1,10 @@
package com.dfsek.terra.procgen.voxel;
package com.dfsek.terra.api.math.voxel;
import com.dfsek.terra.api.math.FastNoiseLite;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.vector.Vector3;
public class DeformedSphere extends VoxelGeometry {
public DeformedSphere(Vector3 start, int rad, double deform, FastNoiseLite noise) {
public DeformedSphere(Vector3 start, int rad, double deform, NoiseSampler noise) {
for(int x = -rad; x <= rad; x++) {
for(int y = -rad; y <= rad; y++) {
for(int z = -rad; z <= rad; z++) {
@@ -1,4 +1,4 @@
package com.dfsek.terra.procgen.voxel;
package com.dfsek.terra.api.math.voxel;
import com.dfsek.terra.api.math.vector.Vector3;
@@ -1,4 +1,4 @@
package com.dfsek.terra.procgen.voxel;
package com.dfsek.terra.api.math.voxel;
import com.dfsek.terra.api.math.vector.Vector3;
@@ -1,4 +1,4 @@
package com.dfsek.terra.procgen.voxel;
package com.dfsek.terra.api.math.voxel;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.util.GlueList;
@@ -4,5 +4,10 @@ package com.dfsek.terra.api.platform;
* An interface that contains a platform delegate.
*/
public interface Handle {
/**
* Gets the delegate object.
*
* @return Delegate
*/
Object getHandle();
}
@@ -0,0 +1,6 @@
package com.dfsek.terra.api.platform;
import com.dfsek.terra.api.platform.entity.Entity;
public interface Player extends Entity {
}
@@ -8,4 +8,6 @@ public interface BlockData extends Cloneable, Handle {
boolean matches(MaterialData materialData);
BlockData clone();
String getAsString();
}
@@ -16,4 +16,8 @@ public interface BlockState extends Handle {
BlockData getBlockData();
boolean update(boolean applyPhysics);
default void applyState(String state) {
// Do nothing by default.
}
}
@@ -0,0 +1,38 @@
package com.dfsek.terra.api.platform.block.state;
import com.dfsek.terra.api.platform.entity.EntityType;
import org.jetbrains.annotations.NotNull;
public interface MobSpawner extends BlockState {
EntityType getSpawnedType();
void setSpawnedType(@NotNull EntityType creatureType);
int getDelay();
void setDelay(int delay);
int getMinSpawnDelay();
void setMinSpawnDelay(int delay);
int getMaxSpawnDelay();
void setMaxSpawnDelay(int delay);
int getSpawnCount();
void setSpawnCount(int spawnCount);
int getMaxNearbyEntities();
void setMaxNearbyEntities(int maxNearbyEntities);
int getRequiredPlayerRange();
void setRequiredPlayerRange(int requiredPlayerRange);
int getSpawnRange();
void setSpawnRange(int spawnRange);
}
@@ -0,0 +1,94 @@
package com.dfsek.terra.api.platform.block.state;
import java.util.HashMap;
import java.util.Map;
public class SerialState {
protected final Map<String, Property<?>> properties = new HashMap<>();
public SerialState() {
}
public static Map<String, String> parse(String props) {
String[] sep = props.split(",");
Map<String, String> map = new HashMap<>();
for(String item : sep) {
map.put(item.substring(0, item.indexOf('=')), item.substring(item.indexOf('=') + 1));
}
return map;
}
private void checkExists(String prop) {
if(!properties.containsKey(prop)) throw new IllegalArgumentException("No such property \"" + prop + "\"");
}
private void checkType(Class<?> clazz, Object o, String id) {
if(!clazz.isInstance(o))
throw new IllegalArgumentException("Invalid data for property " + id + ": " + o);
}
public void setProperty(String id, Object value) {
checkExists(id);
Property<?> prop = properties.get(id);
checkType(prop.getValueClass(), value, id);
prop.setValue(value);
}
public int getInteger(String id) {
checkExists(id);
Property<?> prop = properties.get(id);
checkType(Integer.class, prop.getValue(), id);
return (Integer) prop.getValue();
}
public String getString(String id) {
checkExists(id);
Property<?> prop = properties.get(id);
checkType(String.class, prop.getValue(), id);
return (String) prop.getValue();
}
public long getLong(String id) {
checkExists(id);
Property<?> prop = properties.get(id);
checkType(Long.class, prop.getValue(), id);
return (Long) prop.getValue();
}
public boolean getBoolean(String id) {
checkExists(id);
Property<?> prop = properties.get(id);
checkType(Boolean.class, prop.getValue(), id);
return (Boolean) prop.getValue();
}
@SuppressWarnings("unchecked")
public <T> T get(String id, Class<T> clazz) {
checkExists(id);
Property<?> prop = properties.get(id);
checkType(clazz, prop.getValue(), id);
return (T) prop.getValue();
}
protected static class Property<T> {
private final Class<T> clazz;
private Object value;
public Property(Class<T> clazz) {
this.clazz = clazz;
}
public Class<T> getValueClass() {
return clazz;
}
@SuppressWarnings("unchecked")
public T getValue() {
return (T) value;
}
public void setValue(Object value) {
this.value = value;
}
}
}
@@ -0,0 +1,11 @@
package com.dfsek.terra.api.platform.block.state;
import org.jetbrains.annotations.NotNull;
public interface Sign extends BlockState {
@NotNull String[] getLines();
@NotNull String getLine(int index) throws IndexOutOfBoundsException;
void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException;
}
@@ -0,0 +1,9 @@
package com.dfsek.terra.api.platform.entity;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.Handle;
public interface Entity extends Handle, CommandSender {
Location getLocation();
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.api.platform.world.entity;
package com.dfsek.terra.api.platform.entity;
import com.dfsek.terra.api.platform.Handle;
@@ -1,71 +0,0 @@
package com.dfsek.terra.api.platform.generator;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.BiomeGrid;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Random;
public interface ChunkGenerator extends Handle {
boolean isParallelCapable();
boolean shouldGenerateCaves();
boolean shouldGenerateDecorations();
boolean shouldGenerateMobs();
boolean shouldGenerateStructures();
ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome);
List<BlockPopulator> getDefaultPopulators(World world);
@Nullable
TerraChunkGenerator getTerraGenerator();
interface ChunkData {
Object getHandle();
/**
* Get the maximum height for the chunk.
* <p>
* Setting blocks at or above this height will do nothing.
*
* @return the maximum height
*/
int getMaxHeight();
/**
* Set the block at x,y,z in the chunk data to material.
* <p>
* Setting blocks outside the chunk's bounds does nothing.
*
* @param x the x location in the chunk from 0-15 inclusive
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
* @param z the z location in the chunk from 0-15 inclusive
* @param blockData the type to set the block to
*/
void setBlock(int x, int y, int z, @NotNull BlockData blockData);
/**
* Get the type and data of the block at x, y, z.
* <p>
* Getting blocks outside the chunk's bounds returns air.
*
* @param x the x location in the chunk from 0-15 inclusive
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
* @param z the z location in the chunk from 0-15 inclusive
* @return the data of the block or the BlockData for air if x, y or z are outside the chunk's bounds
*/
@NotNull BlockData getBlockData(int x, int y, int z);
}
}
@@ -2,7 +2,14 @@ package com.dfsek.terra.api.platform.handle;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
import java.util.Set;
public interface ItemHandle {
ItemStack newItemStack(MaterialData material, int amount);
Enchantment getEnchantment(String id);
Set<Enchantment> getEnchantments();
}
@@ -3,8 +3,7 @@ package com.dfsek.terra.api.platform.handle;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.platform.world.entity.EntityType;
import com.dfsek.terra.api.platform.entity.EntityType;
/**
* Interface to be implemented for world manipulation.
@@ -20,7 +19,5 @@ public interface WorldHandle {
MaterialData createMaterialData(String data);
Tree getTree(String id);
EntityType getEntity(String id);
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.api.platform.inventory.item;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.inventory.ItemStack;
public interface Enchantment extends Handle {
boolean canEnchantItem(ItemStack itemStack);
String getID();
boolean conflictsWith(Enchantment other);
int getMaxLevel();
}
@@ -2,5 +2,10 @@ package com.dfsek.terra.api.platform.inventory.item;
import com.dfsek.terra.api.platform.Handle;
import java.util.Map;
public interface ItemMeta extends Handle {
Map<Enchantment, Integer> getEnchantments();
void addEnchantment(Enchantment enchantment, int level);
}
@@ -1,9 +1,8 @@
package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.Block;
public interface Chunk extends Handle {
public interface Chunk extends ChunkAccess {
int getX();
int getZ();
@@ -0,0 +1,31 @@
package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.BlockData;
import org.jetbrains.annotations.NotNull;
public interface ChunkAccess extends Handle {
/**
* Set the block at x,y,z in the chunk data to material.
* <p>
* Setting blocks outside the chunk's bounds does nothing.
*
* @param x the x location in the chunk from 0-15 inclusive
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
* @param z the z location in the chunk from 0-15 inclusive
* @param blockData the type to set the block to
*/
void setBlock(int x, int y, int z, @NotNull BlockData blockData);
/**
* Get the type and data of the block at x, y, z.
* <p>
* Getting blocks outside the chunk's bounds returns air.
*
* @param x the x location in the chunk from 0-15 inclusive
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
* @param z the z location in the chunk from 0-15 inclusive
* @return the data of the block or the BlockData for air if x, y or z are outside the chunk's bounds
*/
@NotNull BlockData getBlockData(int x, int y, int z);
}
@@ -1,6 +0,0 @@
package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.platform.Handle;
public interface Tree extends Handle, com.dfsek.terra.api.world.tree.Tree {
}
@@ -3,9 +3,9 @@ package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.entity.Entity;
import com.dfsek.terra.api.platform.world.entity.EntityType;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import java.io.File;
import java.util.UUID;
@@ -31,7 +31,5 @@ public interface World extends Handle {
Block getBlockAt(Location l);
boolean generateTree(Location l, Tree vanillaTreeType);
Entity spawnEntity(Location location, EntityType entityType);
}
@@ -1,6 +0,0 @@
package com.dfsek.terra.api.platform.world.entity;
import com.dfsek.terra.api.platform.Handle;
public interface Entity extends Handle {
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.api.platform.generator;
package com.dfsek.terra.api.platform.world.generator;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.world.Chunk;
@@ -0,0 +1,43 @@
package com.dfsek.terra.api.platform.world.generator;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.world.BiomeGrid;
import com.dfsek.terra.api.platform.world.ChunkAccess;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Random;
public interface ChunkGenerator extends Handle {
boolean isParallelCapable();
boolean shouldGenerateCaves();
boolean shouldGenerateDecorations();
boolean shouldGenerateMobs();
boolean shouldGenerateStructures();
ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome);
List<BlockPopulator> getDefaultPopulators(World world);
@Nullable
TerraChunkGenerator getTerraGenerator();
interface ChunkData extends ChunkAccess {
/**
* Get the maximum height for the chunk.
* <p>
* Setting blocks at or above this height will do nothing.
*
* @return the maximum height
*/
int getMaxHeight();
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.api.platform.generator;
package com.dfsek.terra.api.platform.world.generator;
import com.dfsek.terra.api.platform.Handle;
@@ -1,11 +1,12 @@
package com.dfsek.terra.api.structures.loot;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.structures.loot.functions.AmountFunction;
import com.dfsek.terra.api.structures.loot.functions.DamageFunction;
import com.dfsek.terra.api.structures.loot.functions.Function;
import com.dfsek.terra.api.structures.loot.functions.EnchantFunction;
import com.dfsek.terra.api.structures.loot.functions.LootFunction;
import com.dfsek.terra.api.util.GlueList;
import net.jafama.FastMath;
import org.json.simple.JSONArray;
@@ -20,7 +21,7 @@ import java.util.Random;
public class Entry {
private final MaterialData item;
private final long weight;
private final List<Function> functions = new GlueList<>();
private final List<LootFunction> functions = new GlueList<>();
private final TerraPlugin main;
/**
@@ -63,6 +64,15 @@ public class Entry {
long minDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("min");
functions.add(new DamageFunction(FastMath.toIntExact(minDamage), FastMath.toIntExact(maxDamage)));
break;
case "minecraft:enchant_with_levels":
case "enchant_with_levels":
long maxEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("max");
long minEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("min");
JSONArray disabled = null;
if(((JSONObject) function).containsKey("disabled_enchants"))
disabled = (JSONArray) ((JSONObject) function).get("disabled_enchants");
functions.add(new EnchantFunction(FastMath.toIntExact(minEnchant), FastMath.toIntExact(maxEnchant), disabled, main));
break;
}
}
}
@@ -76,7 +86,7 @@ public class Entry {
*/
public ItemStack getItem(Random r) {
ItemStack item = main.getItemHandle().newItemStack(this.item, 1);
for(Function f : functions) {
for(LootFunction f : functions) {
item = f.apply(item, r);
}
return item;
@@ -1,6 +1,6 @@
package com.dfsek.terra.api.structures.loot;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.platform.inventory.Inventory;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.util.GlueList;
@@ -1,7 +1,7 @@
package com.dfsek.terra.api.structures.loot;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.util.GlueList;
import net.jafama.FastMath;
@@ -6,9 +6,9 @@ import com.dfsek.terra.api.platform.inventory.ItemStack;
import java.util.Random;
/**
* Loot Function fot setting the amount of an item.
* Loot LootFunction fot setting the amount of an item.
*/
public class AmountFunction implements Function {
public class AmountFunction implements LootFunction {
private final int max;
private final int min;
@@ -7,9 +7,9 @@ import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
import java.util.Random;
/**
* Loot Function for setting the damage on items in Loot Tables
* Loot LootFunction for setting the damage on items in Loot Tables
*/
public class DamageFunction implements Function {
public class DamageFunction implements LootFunction {
private final int max;
private final int min;
@@ -0,0 +1,64 @@
package com.dfsek.terra.api.structures.loot.functions;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
import com.dfsek.terra.api.util.GlueList;
import net.jafama.FastMath;
import org.json.simple.JSONArray;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class EnchantFunction implements LootFunction {
private final int min;
private final int max;
private final JSONArray disabled;
private final TerraPlugin main;
public EnchantFunction(int min, int max, JSONArray disabled, TerraPlugin main) {
this.max = max;
this.min = min;
this.disabled = disabled;
this.main = main;
}
/**
* Applies the function to an ItemStack.
*
* @param original The ItemStack on which to apply the function.
* @param r The Random instance to use.
* @return - ItemStack - The mutated ItemStack.
*/
@Override
public ItemStack apply(ItemStack original, Random r) {
double enchant = (r.nextDouble() * (max - min)) + min;
List<Enchantment> possible = new GlueList<>();
for(Enchantment ench : main.getItemHandle().getEnchantments()) {
if(ench.canEnchantItem(original) && (disabled == null || !this.disabled.contains(ench.getID()))) {
possible.add(ench);
}
}
int numEnchant = (r.nextInt((int) FastMath.abs(enchant)) / 10 + 1);
Collections.shuffle(possible);
ItemMeta meta = original.getItemMeta();
iter:
for(int i = 0; i < numEnchant && i < possible.size(); i++) {
Enchantment chosen = possible.get(i);
for(Enchantment ench : meta.getEnchantments().keySet()) {
if(chosen.conflictsWith(ench)) continue iter;
}
int lvl = r.nextInt(1 + (int) (((enchant / 40 > 1) ? 1 : enchant / 40) * (chosen.getMaxLevel())));
try {
meta.addEnchantment(chosen, FastMath.max(lvl, 1));
} catch(IllegalArgumentException e) {
main.getLogger().warning("Attempted to enchant " + original.getType() + " with " + chosen + " at level " + FastMath.max(lvl, 1) + ", but an unexpected exception occurred! Usually this is caused by a misbehaving enchantment plugin.");
}
}
original.setItemMeta(meta);
return original;
}
}
@@ -8,7 +8,7 @@ import java.util.Random;
/**
* Interface for mutating items in Loot Tables.
*/
public interface Function {
public interface LootFunction {
/**
* Applies the function to an ItemStack.
*
@@ -11,9 +11,6 @@ import com.dfsek.terra.api.structures.parser.lang.constants.NumericConstant;
import com.dfsek.terra.api.structures.parser.lang.constants.StringConstant;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.AbsFunction;
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.PowFunction;
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.SqrtFunction;
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.BreakKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.ContinueKeyword;
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.FailKeyword;
@@ -27,7 +24,9 @@ import com.dfsek.terra.api.structures.parser.lang.operations.BooleanNotOperation
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanOrOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.ConcatenationOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.DivisionOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.ModuloOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.MultiplicationOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.NegationOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.NumberAdditionOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.SubtractionOperation;
import com.dfsek.terra.api.structures.parser.lang.operations.statements.EqualsStatement;
@@ -37,29 +36,22 @@ import com.dfsek.terra.api.structures.parser.lang.operations.statements.LessThan
import com.dfsek.terra.api.structures.parser.lang.operations.statements.LessThanStatement;
import com.dfsek.terra.api.structures.parser.lang.operations.statements.NotEqualsStatement;
import com.dfsek.terra.api.structures.parser.lang.variables.Assignment;
import com.dfsek.terra.api.structures.parser.lang.variables.BooleanVariable;
import com.dfsek.terra.api.structures.parser.lang.variables.Declaration;
import com.dfsek.terra.api.structures.parser.lang.variables.Getter;
import com.dfsek.terra.api.structures.parser.lang.variables.NumberVariable;
import com.dfsek.terra.api.structures.parser.lang.variables.StringVariable;
import com.dfsek.terra.api.structures.parser.lang.variables.Variable;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.api.structures.tokenizer.Token;
import com.dfsek.terra.api.structures.tokenizer.Tokenizer;
import com.dfsek.terra.api.structures.tokenizer.exceptions.TokenizerException;
import com.dfsek.terra.api.util.GlueList;
import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SuppressWarnings("unchecked")
public class Parser {
private final String data;
private final Map<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
private final Set<String> builtinFunctions = Sets.newHashSet("abs", "sqrt", "pow");
private String id;
@@ -67,7 +59,7 @@ public class Parser {
this.data = data;
}
public Parser addFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
public Parser registerFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
functions.put(name, functionBuilder);
return this;
}
@@ -83,18 +75,7 @@ public class Parser {
* @throws ParseException If parsing fails.
*/
public Block parse() throws ParseException {
Tokenizer tokenizer = new Tokenizer(data);
TokenHolder tokens = new TokenHolder();
try {
Token t = tokenizer.fetch();
while(t != null) {
tokens.add(t);
t = tokenizer.fetch();
}
} catch(TokenizerException e) {
throw new ParseException("Failed to tokenize input", new Position(0, 0), e);
}
Tokenizer tokens = new Tokenizer(data);
// Parse ID
ParserUtil.checkType(tokens.consume(), Token.Type.ID); // First token must be ID
@@ -103,21 +84,12 @@ public class Parser {
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
this.id = idToken.getContent();
// Check for dangling brackets
int blockLevel = 0;
for(Token t : tokens.getTokens()) {
if(t.getType().equals(Token.Type.BLOCK_BEGIN)) blockLevel++;
else if(t.getType().equals(Token.Type.BLOCK_END)) blockLevel--;
if(blockLevel < 0) throw new ParseException("Dangling closing brace", t.getPosition());
}
if(blockLevel != 0)
throw new ParseException("Dangling opening brace", tokens.getTokens().get(tokens.getTokens().size() - 1).getPosition());
return parseBlock(tokens, new HashMap<>(), false);
}
private Keyword<?> parseLoopLike(TokenHolder tokens, Map<String, Variable<?>> variableMap, boolean loop) throws ParseException {
private Keyword<?> parseLoopLike(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, boolean loop) throws ParseException {
Token identifier = tokens.consume();
ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP);
@@ -136,7 +108,7 @@ public class Parser {
}
}
private WhileKeyword parseWhileLoop(TokenHolder tokens, Map<String, Variable<?>> variableMap, Position start) throws ParseException {
private WhileKeyword parseWhileLoop(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, Position start) throws ParseException {
Returnable<?> first = parseExpression(tokens, true, variableMap);
ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN);
@@ -145,7 +117,7 @@ public class Parser {
return new WhileKeyword(parseStatementBlock(tokens, variableMap, true), (Returnable<Boolean>) first, start); // While loop
}
private IfKeyword parseIfStatement(TokenHolder tokens, Map<String, Variable<?>> variableMap, Position start, boolean loop) throws ParseException {
private IfKeyword parseIfStatement(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, Position start, boolean loop) throws ParseException {
Returnable<?> condition = parseExpression(tokens, true, variableMap);
ParserUtil.checkReturnType(condition, Returnable.ReturnType.BOOLEAN);
@@ -172,7 +144,7 @@ public class Parser {
return new IfKeyword(statement, (Returnable<Boolean>) condition, elseIf, elseBlock, start); // If statement
}
private Block parseStatementBlock(TokenHolder tokens, Map<String, Variable<?>> variableMap, boolean loop) throws ParseException {
private Block parseStatementBlock(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, boolean loop) throws ParseException {
if(tokens.get().getType().equals(Token.Type.BLOCK_BEGIN)) {
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
@@ -187,21 +159,17 @@ public class Parser {
}
}
private ForKeyword parseForLoop(TokenHolder tokens, Map<String, Variable<?>> old, Position start) throws ParseException {
Map<String, Variable<?>> variableMap = new HashMap<>(old); // New scope
private ForKeyword parseForLoop(Tokenizer tokens, Map<String, Returnable.ReturnType> old, Position start) throws ParseException {
Map<String, Returnable.ReturnType> variableMap = new HashMap<>(old); // New scope
Token f = tokens.get();
ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
Item<?> initializer;
if(f.isVariableDeclaration()) {
Variable<?> forVar = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(f));
ParserUtil.checkType(tokens.consume(), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
Declaration<?> forVar = parseVariableDeclaration(tokens, variableMap);
Token name = tokens.get();
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()))
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
initializer = parseAssignment(forVar, tokens, variableMap);
variableMap.put(name.getContent(), forVar);
initializer = forVar;
} else initializer = parseExpression(tokens, true, variableMap);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
Returnable<?> conditional = parseExpression(tokens, true, variableMap);
@@ -211,8 +179,7 @@ public class Parser {
Item<?> incrementer;
Token token = tokens.get();
if(variableMap.containsKey(token.getContent())) { // Assume variable assignment
Variable<?> variable = variableMap.get(token.getContent());
incrementer = parseAssignment(variable, tokens, variableMap);
incrementer = parseAssignment(tokens, variableMap);
} else incrementer = parseFunction(tokens, true, variableMap);
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
@@ -220,11 +187,15 @@ public class Parser {
return new ForKeyword(parseStatementBlock(tokens, variableMap, true), initializer, (Returnable<Boolean>) conditional, incrementer, start);
}
private Returnable<?> parseExpression(TokenHolder tokens, boolean full, Map<String, Variable<?>> variableMap) throws ParseException {
private Returnable<?> parseExpression(Tokenizer tokens, boolean full, Map<String, Returnable.ReturnType> variableMap) throws ParseException {
boolean booleanInverted = false; // Check for boolean not operator
boolean negate = false;
if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) {
booleanInverted = true;
tokens.consume();
} else if(tokens.get().getType().equals(Token.Type.SUBTRACTION_OPERATOR)) {
negate = true;
tokens.consume();
}
Token id = tokens.get();
@@ -237,17 +208,20 @@ public class Parser {
} else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression
expression = parseGroup(tokens, variableMap);
} else {
if(functions.containsKey(id.getContent()) || builtinFunctions.contains(id.getContent()))
if(functions.containsKey(id.getContent()))
expression = parseFunction(tokens, false, variableMap);
else if(variableMap.containsKey(id.getContent())) {
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER);
expression = new Getter(variableMap.get(id.getContent()));
expression = new Getter(id.getContent(), id.getPosition(), variableMap.get(id.getContent()));
} else throw new ParseException("Unexpected token \" " + id.getContent() + "\"", id.getPosition());
}
if(booleanInverted) { // Invert operation if boolean not detected
ParserUtil.checkReturnType(expression, Returnable.ReturnType.BOOLEAN);
expression = new BooleanNotOperation((Returnable<Boolean>) expression, expression.getPosition());
} else if(negate) {
ParserUtil.checkReturnType(expression, Returnable.ReturnType.NUMBER);
expression = new NegationOperation((Returnable<Number>) expression, expression.getPosition());
}
if(full && tokens.get().isBinaryOperator()) { // Parse binary operations
@@ -256,7 +230,7 @@ public class Parser {
return expression;
}
private ConstantExpression<?> parseConstantExpression(TokenHolder tokens) throws ParseException {
private ConstantExpression<?> parseConstantExpression(Tokenizer tokens) throws ParseException {
Token constantToken = tokens.consume();
Position position = constantToken.getPosition();
switch(constantToken.getType()) {
@@ -272,7 +246,7 @@ public class Parser {
}
}
private Returnable<?> parseGroup(TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
private Returnable<?> parseGroup(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap) throws ParseException {
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
Returnable<?> expression = parseExpression(tokens, true, variableMap); // Parse inside of group as a separate expression
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
@@ -280,7 +254,7 @@ public class Parser {
}
private BinaryOperation<?, ?> parseBinaryOperation(Returnable<?> left, TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
private BinaryOperation<?, ?> parseBinaryOperation(Returnable<?> left, Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap) throws ParseException {
Token binaryOperator = tokens.consume();
ParserUtil.checkBinaryOperator(binaryOperator);
@@ -327,28 +301,38 @@ public class Parser {
return new BooleanAndOperation((Returnable<Boolean>) left, (Returnable<Boolean>) right, binaryOperator.getPosition());
case BOOLEAN_OR:
return new BooleanOrOperation((Returnable<Boolean>) left, (Returnable<Boolean>) right, binaryOperator.getPosition());
case MODULO_OPERATOR:
return new ModuloOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
default:
throw new UnsupportedOperationException("Unsupported binary operator: " + binaryOperator.getType());
}
}
private Variable<?> parseVariableDeclaration(TokenHolder tokens, Returnable.ReturnType type) throws ParseException {
ParserUtil.checkVarType(tokens.get(), type); // Check for type mismatch
switch(type) {
case NUMBER:
return new NumberVariable(0d, tokens.get().getPosition());
case STRING:
return new StringVariable("", tokens.get().getPosition());
case BOOLEAN:
return new BooleanVariable(false, tokens.get().getPosition());
}
throw new UnsupportedOperationException("Unsupported variable type: " + type);
private Declaration<?> parseVariableDeclaration(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap) throws ParseException {
Token type = tokens.consume();
ParserUtil.checkType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
Returnable.ReturnType returnType = ParserUtil.getVariableReturnType(type);
ParserUtil.checkVarType(type, returnType); // Check for type mismatch
Token identifier = tokens.consume();
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER);
if(functions.containsKey(identifier.getContent()) || variableMap.containsKey(identifier.getContent()))
throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition());
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT);
Returnable<?> value = parseExpression(tokens, true, variableMap);
ParserUtil.checkReturnType(value, returnType);
variableMap.put(identifier.getContent(), returnType);
return new Declaration<>(tokens.get().getPosition(), identifier.getContent(), value, returnType);
}
private Block parseBlock(TokenHolder tokens, Map<String, Variable<?>> superVars, boolean loop) throws ParseException {
private Block parseBlock(Tokenizer tokens, Map<String, Returnable.ReturnType> superVars, boolean loop) throws ParseException {
List<Item<?>> parsedItems = new GlueList<>();
Map<String, Variable<?>> parsedVariables = new HashMap<>(superVars); // New hashmap as to not mutate parent scope's declarations.
Map<String, Returnable.ReturnType> parsedVariables = new HashMap<>(superVars); // New hashmap as to not mutate parent scope's declarations.
Token first = tokens.get();
@@ -361,7 +345,7 @@ public class Parser {
return new Block(parsedItems, first.getPosition());
}
private Item<?> parseItem(TokenHolder tokens, Map<String, Variable<?>> variableMap, boolean loop) throws ParseException {
private Item<?> parseItem(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap, boolean loop) throws ParseException {
Token token = tokens.get();
if(loop) ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
@@ -372,23 +356,12 @@ public class Parser {
return parseLoopLike(tokens, variableMap, loop);
} else if(token.isIdentifier()) { // Parse identifiers
if(variableMap.containsKey(token.getContent())) { // Assume variable assignment
Variable<?> variable = variableMap.get(token.getContent());
return parseAssignment(variable, tokens, variableMap);
return parseAssignment(tokens, variableMap);
} else return parseFunction(tokens, true, variableMap);
} else if(token.isVariableDeclaration()) {
Variable<?> temp = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(token));
ParserUtil.checkType(tokens.consume(), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
Token name = tokens.get();
ParserUtil.checkType(name, Token.Type.IDENTIFIER); // Name must be an identifier.
return parseVariableDeclaration(tokens, variableMap);
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
variableMap.put(name.getContent(), temp);
return parseAssignment(temp, tokens, variableMap);
} else if(token.getType().equals(Token.Type.RETURN)) return new ReturnKeyword(tokens.consume().getPosition());
else if(token.getType().equals(Token.Type.BREAK)) return new BreakKeyword(tokens.consume().getPosition());
else if(token.getType().equals(Token.Type.CONTINUE)) return new ContinueKeyword(tokens.consume().getPosition());
@@ -396,25 +369,25 @@ public class Parser {
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
}
private Assignment<?> parseAssignment(Variable<?> variable, TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
Token name = tokens.get();
private Assignment<?> parseAssignment(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap) throws ParseException {
Token identifier = tokens.consume();
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER);
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER);
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT);
Returnable<?> expression = parseExpression(tokens, true, variableMap);
Returnable<?> value = parseExpression(tokens, true, variableMap);
ParserUtil.checkReturnType(expression, variable.getType());
ParserUtil.checkReturnType(value, variableMap.get(identifier.getContent()));
return new Assignment<>((Variable<Object>) variable, (Returnable<Object>) expression, name.getPosition());
return new Assignment<>(value, identifier.getContent(), identifier.getPosition());
}
private Function<?> parseFunction(TokenHolder tokens, boolean fullStatement, Map<String, Variable<?>> variableMap) throws ParseException {
private Function<?> parseFunction(Tokenizer tokens, boolean fullStatement, Map<String, Returnable.ReturnType> variableMap) throws ParseException {
Token identifier = tokens.consume();
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
if(!functions.containsKey(identifier.getContent()) && !builtinFunctions.contains(identifier.getContent()))
if(!functions.containsKey(identifier.getContent()))
throw new ParseException("No such function \"" + identifier.getContent() + "\"", identifier.getPosition());
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); // Second is body begin
@@ -439,32 +412,12 @@ public class Parser {
ParserUtil.checkReturnType(argument, builder.getArgument(i));
}
return builder.build(args, identifier.getPosition());
} else {
switch(identifier.getContent()) {
case "abs":
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
if(args.size() != 1)
throw new ParseException("Expected 1 argument; found " + args.size(), identifier.getPosition());
return new AbsFunction(identifier.getPosition(), (Returnable<Number>) args.get(0));
case "sqrt":
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
if(args.size() != 1)
throw new ParseException("Expected 1 argument; found " + args.size(), identifier.getPosition());
return new SqrtFunction(identifier.getPosition(), (Returnable<Number>) args.get(0));
case "pow":
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
ParserUtil.checkReturnType(args.get(1), Returnable.ReturnType.NUMBER);
if(args.size() != 2)
throw new ParseException("Expected 1 argument; found " + args.size(), identifier.getPosition());
return new PowFunction(identifier.getPosition(), (Returnable<Number>) args.get(0), (Returnable<Number>) args.get(1));
default:
throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent());
}
}
throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent());
}
private List<Returnable<?>> getArgs(TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
private List<Returnable<?>> getArgs(Tokenizer tokens, Map<String, Returnable.ReturnType> variableMap) throws ParseException {
List<Returnable<?>> args = new GlueList<>();
while(!tokens.get().getType().equals(Token.Type.GROUP_END)) {
@@ -11,21 +11,31 @@ import java.util.Map;
public class ParserUtil {
private static final Map<Token.Type, List<Token.Type>> PRECEDENCE = new HashMap<>();
private static final List<Token.Type> ARITHMETIC = Arrays.asList(Token.Type.ADDITION_OPERATOR, Token.Type.SUBTRACTION_OPERATOR, Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR);
private static final Map<Token.Type, Map<Token.Type, Boolean>> PRECEDENCE = new HashMap<>(); // If second has precedence, true.
private static final List<Token.Type> ARITHMETIC = Arrays.asList(Token.Type.ADDITION_OPERATOR, Token.Type.SUBTRACTION_OPERATOR, Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR, Token.Type.MODULO_OPERATOR);
private static final List<Token.Type> COMPARISON = Arrays.asList(Token.Type.EQUALS_OPERATOR, Token.Type.NOT_EQUALS_OPERATOR, Token.Type.LESS_THAN_OPERATOR, Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, Token.Type.GREATER_THAN_OPERATOR, Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR);
static { // Setup precedence
PRECEDENCE.put(Token.Type.ADDITION_OPERATOR, Arrays.asList(Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR));
PRECEDENCE.put(Token.Type.SUBTRACTION_OPERATOR, Arrays.asList(Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR));
PRECEDENCE.put(Token.Type.EQUALS_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.NOT_EQUALS_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.GREATER_THAN_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.LESS_THAN_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, ARITHMETIC);
PRECEDENCE.put(Token.Type.BOOLEAN_AND, COMPARISON);
PRECEDENCE.put(Token.Type.BOOLEAN_OR, COMPARISON);
Map<Token.Type, Boolean> add = new HashMap<>(); // Addition/subtraction before Multiplication/division.
add.put(Token.Type.MULTIPLICATION_OPERATOR, true);
add.put(Token.Type.DIVISION_OPERATOR, true);
PRECEDENCE.put(Token.Type.ADDITION_OPERATOR, add);
PRECEDENCE.put(Token.Type.SUBTRACTION_OPERATOR, add);
Map<Token.Type, Boolean> numericBoolean = new HashMap<>();
ARITHMETIC.forEach(op -> numericBoolean.put(op, true)); // Numbers before comparison
COMPARISON.forEach(op -> PRECEDENCE.put(op, numericBoolean));
Map<Token.Type, Boolean> booleanOps = new HashMap<>();
ARITHMETIC.forEach(op -> booleanOps.put(op, true)); // Everything before boolean
COMPARISON.forEach(op -> booleanOps.put(op, true));
PRECEDENCE.put(Token.Type.BOOLEAN_AND, booleanOps);
PRECEDENCE.put(Token.Type.BOOLEAN_OR, booleanOps);
}
public static void checkType(Token token, Token.Type... expected) throws ParseException {
@@ -83,6 +93,8 @@ public class ParserUtil {
public static boolean hasPrecedence(Token.Type first, Token.Type second) {
if(!PRECEDENCE.containsKey(first)) return false;
return PRECEDENCE.get(first).contains(second);
Map<Token.Type, Boolean> pre = PRECEDENCE.get(first);
if(!pre.containsKey(second)) return false;
return pre.get(second);
}
}
@@ -1,59 +0,0 @@
package com.dfsek.terra.api.structures.parser;
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.api.structures.tokenizer.Token;
import com.dfsek.terra.api.util.GlueList;
import java.util.List;
/**
* Data structure to hold tokens, where items are inserted at the top and removed from the bottom.
*/
public class TokenHolder {
private final List<Token> tokens = new GlueList<>();
private Position last;
/**
* Add a token to the top of the stack.
*
* @param token Token to add
*/
public void add(Token token) {
tokens.add(token);
}
/**
* Get the token at the bottom of the stack.
*
* @return First token
* @throws ParseException If stack is empty
*/
public Token get() throws ParseException {
if(!hasNext()) throw new ParseException("Unexpected end of input", last);
Token token = tokens.get(0);
last = token.getPosition();
return token;
}
/**
* Consume (get and remove) the token at the bottom of the stack.
*
* @return First token
* @throws ParseException If stack is empty
*/
public Token consume() throws ParseException {
if(!hasNext()) throw new ParseException("Unexpected end of input", last);
Token token = tokens.remove(0);
last = token.getPosition();
return token;
}
public List<Token> getTokens() {
return tokens;
}
public boolean hasNext() {
return tokens.size() > 0;
}
}

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