Compare commits

...

91 Commits

Author SHA1 Message Date
Zoë Gidiere b10fd84e00 Merge remote-tracking branch 'origin/ver/6.5.0' into dev/metapacks 2024-01-05 09:11:42 -07:00
Astrash 271e7f3c69 Fix empty slant holders attempting to calculate slant
This occurs when the NoiseChunkGenerator3D#getSlant method is invoked at
a position where the biome has an empty slant holder, currently possible
when using the slant locator addon.

This is fixed by making slant calculation independent of SlantHolders.
Some minor refactoring has also been done as a result of this change.
2024-01-05 18:42:35 +11:00
Zoë 3e04bae828 Merge branch 'ver/6.5.0' into dev/metapacks 2023-12-24 22:39:15 -06:00
Zoë 6681bdfbf2 Merge remote-tracking branch 'origin/master' into ver/6.5.0 2023-12-24 22:39:06 -06:00
dfsek ab60f14ff1 Merge pull request #444 from PolyhedralDev/dev/fix-lerp
6.4.3 - Fix lerp (urgent)
2023-12-24 02:15:54 -07:00
dfsek d8ba9e1016 bump version 2023-12-24 02:06:11 -07:00
dfsek 3622003a39 fix other lerp issues 2023-12-24 02:02:46 -07:00
dfsek 84cd96ecf7 fix BrownianMotionSampler lerp usage 2023-12-24 01:53:05 -07:00
Zoë 82334cfe9e Merge branch 'ver/6.5.0' into dev/metapacks 2023-12-22 15:03:04 -06:00
Zoë 8afda7424c Merge branch 'master' into ver/6.5.0 2023-12-22 15:02:53 -06:00
Zoë Gidiere 50ba1c6eab push changes 2023-12-21 08:47:52 -07:00
Zoë da4ab8b71c Merge pull request #441 from PolyhedralDev/ver/6.4.2
Ver/6.4.2
2023-12-18 13:01:36 -07:00
Zoë Gidiere 3745c3e947 fix typos 2023-12-17 15:32:35 -07:00
Zoë Gidiere fd20837b55 fix error on startup 2023-12-17 15:29:18 -07:00
Zoë Gidiere 27a967f3a6 fix build 2023-12-12 20:17:15 -07:00
Zoë Gidiere 4c71355535 Reformat 2023-12-12 19:07:57 -07:00
Zoë Gidiere e83b70b5ae generation settings 2023-12-12 18:52:31 -07:00
Zoë Gidiere 56b428d501 refactor 2023-12-12 17:19:32 -07:00
Zoë Gidiere 7ca24faad3 fix loading 2023-12-12 17:15:54 -07:00
Zoë Gidiere 9d200565d7 more fixes 2023-12-12 16:54:27 -07:00
Zoë Gidiere f6c2795eaf remove debug loging 2023-12-12 16:12:36 -07:00
Zoë Gidiere 6f03746e41 another fix 2023-12-12 16:09:08 -07:00
Zoë Gidiere 47c8cb3168 Fix up random changes 2023-12-12 16:00:56 -07:00
Zoë Gidiere a9f973cae9 WIP Random Changes 2023-12-12 15:57:04 -07:00
Zoë Gidiere 033181d7c8 more wip changes 2023-12-12 15:48:31 -07:00
Zoë Gidiere e11a235386 WIP Dim opts 2023-12-12 13:55:03 -07:00
Zoë Gidiere db1e924246 more metapack work 2023-12-12 13:35:52 -07:00
Zoë Gidiere c86faa44ec Remove netherfossiloptimization because it's no longer applicable
also it's not needed mc seems to have done this themselves
2023-12-12 13:35:24 -07:00
Zoë Gidiere de91a6facb metapack linking instead of shading 2023-12-11 23:36:05 -07:00
Zoë Gidiere d4a328eb38 who let the datadrive (the dimensions) 2023-12-11 21:14:43 -07:00
Zoë Gidiere b039629b2d WIP meta pack system 2023-12-11 16:25:13 -07:00
Zoë Gidiere d48fa96ec7 opt import 2023-12-11 14:56:07 -07:00
Zoë Gidiere 8dd1f49b88 Merge remote-tracking branch 'origin/dev/remove-loader' into dev/metapacks 2023-12-11 14:54:59 -07:00
Zoë Gidiere 81528915a8 Merge branch 'ver/6.5.0' into dev/metapacks 2023-12-11 14:54:44 -07:00
Zoë Gidiere 5979254808 wip 2023-12-11 14:54:27 -07:00
Zoë Gidiere 0091e5b785 spell check 2023-12-10 18:50:40 -07:00
Zoë Gidiere 41045ae8aa literally forgor the most important part 2023-12-10 18:47:12 -07:00
Zoë Gidiere 4a83f01c1f fix incase mods are used 2023-12-10 18:44:26 -07:00
Zoë Gidiere fc764a0fb3 fix issues with spawners and entity parsing 2023-12-10 18:40:43 -07:00
Zoë Gidiere 22c46f2f80 Pin OWConfig Version 2023-12-10 17:45:52 -07:00
Zoë Gidiere f408faaa80 reformat 2023-12-10 17:07:18 -07:00
Zoë Gidiere 0ad7ee4f9f fix CME 2023-12-10 16:57:27 -07:00
Zoë Gidiere 1e55074cfa Enforce NMS bindings 2023-12-10 15:46:00 -07:00
Zoë 2a92d76276 Merge pull request #437 from PolyhedralDev/dev/1.20.3
Dev/1.20.3
2023-12-09 15:13:11 -07:00
Zoë Gidiere 687ad5db59 Final dep update
confirmed working on paper and fabric
2023-12-09 15:00:46 -07:00
Zoë Gidiere f9c9789016 remove unused maven repo 2023-12-09 01:16:38 -07:00
Zoë Gidiere 3142c2a4f0 update paper to 1.20.4 2023-12-08 22:57:01 -07:00
Zoë Gidiere b5532b7679 Merge branch 'ver/6.4.2' into dev/1.20.3 2023-12-08 22:31:12 -07:00
Zoë Gidiere 8af299d09c fix path of vale ignore 2023-12-08 22:31:04 -07:00
Zoë Gidiere 5cf8a5061d Merge branch 'ver/6.4.2' into dev/1.20.3 2023-12-08 22:11:57 -07:00
Zoë Gidiere 017876475e Add Vale config to gitignore 2023-12-08 22:11:48 -07:00
Zoë Gidiere d88e4f1f9b fix stupid error
thank you caffeine mc peeps
2023-12-08 19:57:05 -07:00
Zoë Gidiere 17eac505a0 Merge branch 'ver/6.4.2' into dev/1.20.3 2023-12-07 11:29:31 -07:00
Zoë Gidiere 8043814138 pull up version range of fabric 2023-12-07 11:29:19 -07:00
Zoë Gidiere 554887ab54 build fabric against 1.20.4 2023-12-07 11:27:06 -07:00
Zoë Gidiere 2f46a01adc Merge remote-tracking branch 'origin/master' into ver/6.4.2 2023-12-07 00:34:00 -07:00
Zoë Gidiere a1db0574e9 Merge branch 'ver/6.4.2' into dev/1.20.3 2023-12-07 00:33:45 -07:00
Zoë fd6decc706 Merge pull request #439 from PolyhedralDev/dev/github-actions
Create gradle-build.yml
2023-12-06 23:11:33 -07:00
Zoë Gidiere 0ba0d472e6 seems arch loom auto uses vineflower now 2023-12-06 22:47:35 -07:00
Zoë Gidiere 11b03eb93d actually bump bukkit version 2023-12-06 22:27:26 -07:00
Zoë Gidiere 46ca45cb1d fix bukkit build 2023-12-06 22:25:53 -07:00
Zoë Gidiere 4e5b066b91 add bukkit grass workaround 2023-12-06 22:24:55 -07:00
Zoë Gidiere db8df9741f bukkit 1.20.3 2023-12-06 22:22:18 -07:00
Zoë Gidiere 80c52870f5 add additional spigot warning 2023-12-06 12:00:03 -07:00
Zoë Gidiere 5048bc8ede Remove folialib 2023-12-06 10:52:31 -07:00
Zoë Gidiere fc0d7374e4 remove old bukkit versions 2023-12-06 10:14:43 -07:00
Zoë Gidiere e4c3affb9f pull up version range 2023-12-05 20:11:00 -07:00
Zoë Gidiere e160cae3d8 reformat 2023-12-05 20:04:08 -07:00
Zoë Gidiere cb9aa4f167 fix permissions 2023-12-05 19:53:05 -07:00
Zoë Gidiere b612d1c7aa fix name 2023-12-05 19:52:50 -07:00
Zoë Gidiere e4df8dce1d proper gradle cache 2023-12-05 19:52:12 -07:00
Zoë Gidiere 601d174720 pin versions and remove dead lines 2023-12-05 19:44:00 -07:00
Zoë 3339d08e11 Create gradle-build.yml 2023-12-05 19:35:23 -07:00
Zoë Gidiere bc65015af0 update gradle 2023-12-05 18:53:19 -07:00
Zoë Gidiere 913637b0a5 update deps 2023-12-05 18:29:43 -07:00
Zoë Gidiere 86f2356cc8 Merge branch 'ver/6.4.2' into ver/6.5.0 2023-11-27 17:55:40 -07:00
Zoë 55d09818f7 Merge pull request #436 from PolyhedralDev/dev/flatten-biome-array
Dev/flatten biome array
2023-11-27 17:54:38 -07:00
Astrash c0aaf6c6e8 Add messages to exceptions 2023-11-28 10:36:30 +11:00
Zoë Gidiere aecdcd578c initial 1.20.3
also disable forge. we're not publishing it anyway
2023-11-27 13:35:48 -07:00
Zoë Gidiere 382069b094 Bump Version to 6.4.2 2023-11-27 11:35:06 -07:00
Zoë Gidiere 734d4bfb94 reformat 2023-11-27 11:31:20 -07:00
Zoë Gidiere c82e015559 flatten array for pipeline biomes 2023-11-27 11:31:11 -07:00
Astrash 1ab3233cba Reformat code 2023-11-25 15:14:16 +11:00
Astrash 59ea5a69d8 Refactor pack loading
- Combine initial load and reload logic together between each platform implementation
- Should prevent pack load errors from blocking other packs from loading.
2023-11-25 15:10:43 +11:00
Astrash 4ba71e9c27 packDirectory -> rootPath 2023-11-25 15:07:45 +11:00
Astrash 5c7441241c Replace Loader with java.nio.files 2023-11-25 13:31:42 +11:00
Astrash ffb1198da2 Merge branch 'master' into ver/6.5.0 2023-11-25 12:33:51 +11:00
Astrash 2c211f0aa6 Merge branch 'master' into ver/6.5.0 2023-11-25 12:29:54 +11:00
Astrashh 3aef977384 Patch version 6.4.1 (#435)
* Bump version to 6.4.1

* fix fabric dev env

* Invert exposed ore logic (#433)

* Invert exposed ore logic

* Bump ore addon version

* Use logger in Gradle over println (#434)

* Log info instead of println in gradle scripts

* Missed buildSrc printlns

---------

Co-authored-by: Zoë <duplexsys@protonmail.com>
2023-11-25 01:02:45 +00:00
Zoë 6060ceae57 Merge pull request #432 from PolyhedralDev/dev/codeowners
update condeowners
2023-11-18 10:05:10 +00:00
Zoë Gidiere 866d527d35 bump version 2023-11-17 13:11:28 -07:00
195 changed files with 1826 additions and 4178 deletions
+47
View File
@@ -0,0 +1,47 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
name: Gradle Build
on: [ pull_request ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Set up JDK 17
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93
with:
java-version: '17'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- uses: burrunan/gradle-cache-action@03c71a8ba93d670980695505f48f49daf43704a6
name: Build Terra
with:
# Specifies arguments for Gradle execution
# If arguments is missing or empty, then Gradle is not executed
arguments: build
# arguments can be multi-line for better readability
# arguments: |
# --no-paralell
# build
# -x test
# Gradle version to use for execution:
# wrapper (default), current, rc, nightly, release-nightly, or
# versions like 6.6 (see https://services.gradle.org/versions/all)
gradle-version: wrapper
# Properties are passed as -Pname=value
properties: |
kotlin.js.compiler=ir
kotlin.parallel.tasks.in.project=true
+2
View File
@@ -249,3 +249,5 @@ nbdist/
platforms/**/run/** platforms/**/run/**
#Vale Config File
**/.vale.ini
+3 -3
View File
@@ -1,8 +1,8 @@
preRelease(true) preRelease(true)
versionProjects(":common:api", version("6.4.0")) versionProjects(":common:api", version("6.5.0"))
versionProjects(":common:implementation", version("6.4.0")) versionProjects(":common:implementation", version("6.5.0"))
versionProjects(":platforms", version("6.4.0")) versionProjects(":platforms", version("6.5.0"))
allprojects { allprojects {
+4 -4
View File
@@ -17,10 +17,10 @@ repositories {
dependencies { dependencies {
//TODO Allow pulling from Versions.kt //TODO Allow pulling from Versions.kt
implementation("com.github.johnrengelman", "shadow", "8.1.1") implementation("com.github.johnrengelman", "shadow", "8.1.1")
implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "1.5.6") implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "1.5.11")
implementation("org.ow2.asm", "asm", "9.5") implementation("org.ow2.asm", "asm", "9.6")
implementation("org.ow2.asm", "asm-tree", "9.5") implementation("org.ow2.asm", "asm-tree", "9.6")
implementation("com.dfsek.tectonic", "common", "4.2.0") implementation("com.dfsek.tectonic", "common", "4.2.1")
implementation("org.yaml", "snakeyaml", "2.2") implementation("org.yaml", "snakeyaml", "2.2")
} }
+2 -2
View File
@@ -18,7 +18,7 @@ fun Project.addonDir(dir: File, task: Task) {
matchingAddons(dir) { matchingAddons(dir) {
it.name.startsWith("Terra-") // Assume everything that starts with Terra- is a core addon. it.name.startsWith("Terra-") // Assume everything that starts with Terra- is a core addon.
}.forEach { }.forEach {
println("Deleting old addon: " + it.absolutePath) logger.info("Deleting old addon: " + it.absolutePath)
it.delete() it.delete()
} }
forSubProjects(":common:addons") { forSubProjects(":common:addons") {
@@ -29,7 +29,7 @@ fun Project.addonDir(dir: File, task: Task) {
val base = "${jar.archiveBaseName.get()}-${version}" val base = "${jar.archiveBaseName.get()}-${version}"
println("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base") logger.info("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base")
jar.archiveFile.orNull?.asFile?.copyTo(target) jar.archiveFile.orNull?.asFile?.copyTo(target)
} }
+5 -8
View File
@@ -48,17 +48,14 @@ fun Project.configureDependencies() {
maven("https://jitpack.io") { maven("https://jitpack.io") {
name = "JitPack" name = "JitPack"
} }
maven("https://nexuslite.gcnt.net/repos/other/") {
name = "GCNT"
}
} }
dependencies { dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0") testImplementation("org.junit.jupiter", "junit-jupiter-api", Versions.Libraries.Internal.junit)
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.0") testImplementation("org.junit.jupiter", "junit-jupiter-engine", Versions.Libraries.Internal.junit)
compileOnly("org.jetbrains:annotations:23.0.0") compileOnly("org.jetbrains", "annotations", Versions.Libraries.Internal.jetBrainsAnnotations)
compileOnly("com.google.guava:guava:30.0-jre") compileOnly("com.google.guava", "guava", Versions.Libraries.Internal.guava)
testImplementation("com.google.guava:guava:30.0-jre") testImplementation("com.google.guava", "guava", Versions.Libraries.Internal.guava)
} }
} }
@@ -27,7 +27,8 @@ fun Project.configureDistribution() {
group = "terra" group = "terra"
doFirst { doFirst {
file("${buildDir}/resources/main/packs/").deleteRecursively() file("${buildDir}/resources/main/packs/").deleteRecursively()
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraOverworldConfig/releases/download/latest/default.zip") val defaultPackUrl =
URL("https://github.com/PolyhedralDev/TerraOverworldConfig/releases/download/" + Versions.Terra.overworldConfig + "/default.zip")
downloadPack(defaultPackUrl, project) downloadPack(defaultPackUrl, project)
} }
} }
@@ -53,7 +54,7 @@ fun Project.configureDistribution() {
forSubProjects(":common:addons") { forSubProjects(":common:addons") {
val jar = getJarTask() val jar = getJarTask()
println("Packaging addon ${jar.archiveFileName.get()} to $dest. size: ${jar.archiveFile.get().asFile.length() / 1024}KB") logger.info("Packaging addon ${jar.archiveFileName.get()} to $dest. size: ${jar.archiveFile.get().asFile.length() / 1024}KB")
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else "" val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
val addonPath = fs.getPath("/addons/$boot${jar.archiveFileName.get()}") val addonPath = fs.getPath("/addons/$boot${jar.archiveFileName.get()}")
+2 -2
View File
@@ -42,10 +42,10 @@ fun preRelease(preRelease: Boolean) {
fun Project.versionProjects(project: String, version: String) { fun Project.versionProjects(project: String, version: String) {
forSubProjects(project) { forSubProjects(project) {
this.version = version this.version = version
println("Setting version of $path to $version") logger.info("Setting version of $path to $version")
} }
project(project).version = version project(project).version = version
println("Setting version of $project to $version") logger.info("Setting version of $project to $version")
} }
fun Project.version(version: String): String { fun Project.version(version: String): String {
+31 -25
View File
@@ -1,4 +1,8 @@
object Versions { object Versions {
object Terra {
const val overworldConfig = "v1.3.4"
}
object Libraries { object Libraries {
const val tectonic = "4.2.1" const val tectonic = "4.2.1"
const val paralithic = "0.7.1" const val paralithic = "0.7.1"
@@ -6,21 +10,25 @@ object Versions {
const val cloud = "1.8.4" const val cloud = "1.8.4"
const val caffeine = "3.1.8"
const val slf4j = "2.0.9" const val slf4j = "2.0.9"
const val log4j_slf4j_impl = "2.20.0" const val log4j_slf4j_impl = "2.20.0"
object Internal { object Internal {
const val shadow = "8.1.1" const val shadow = "8.1.1"
const val apacheText = "1.10.0" const val apacheText = "1.11.0"
const val apacheIO = "2.14.0" const val apacheIO = "2.15.1"
const val guava = "32.1.3-jre" const val guava = "32.1.3-jre"
const val asm = "9.5" const val asm = "9.6"
const val snakeYml = "2.2" const val snakeYml = "2.2"
const val jetBrainsAnnotations = "24.1.0"
const val junit = "5.10.1"
} }
} }
object Fabric { object Fabric {
const val fabricAPI = "0.90.0+${Mod.minecraft}" const val fabricAPI = "0.91.2+${Mod.minecraft}"
} }
// //
// object Quilt { // object Quilt {
@@ -31,30 +39,28 @@ object Versions {
object Mod { object Mod {
const val mixin = "0.12.5+mixin.0.8.5" const val mixin = "0.12.5+mixin.0.8.5"
const val minecraft = "1.20.2" const val minecraft = "1.20.4"
const val yarn = "$minecraft+build.4" const val yarn = "$minecraft+build.1"
const val fabricLoader = "0.14.23" const val fabricLoader = "0.15.1"
const val architecuryLoom = "1.3.357" const val architecuryLoom = "1.4.369"
const val architecturyPlugin = "3.4.146" const val architecturyPlugin = "3.4.151"
const val loomVineflower = "1.11.0"
}
object Forge {
const val forge = "${Mod.minecraft}-48.0.13"
const val burningwave = "12.63.0"
} }
//
// object Forge {
// const val forge = "${Mod.minecraft}-48.0.13"
// const val burningwave = "12.63.0"
// }
object Bukkit { object Bukkit {
const val paper = "1.18.2-R0.1-SNAPSHOT" const val minecraft = "1.20.4"
const val paperLib = "1.0.5" const val paperBuild = "$minecraft-R0.1-20231209.173338-2"
const val foliaLib = "0.2.5" const val paper = paperBuild
const val minecraft = "1.20.2" const val paperLib = "1.0.8"
const val reflectionRemapper = "0.1.0-SNAPSHOT" const val reflectionRemapper = "0.1.0"
const val paperDevBundle = "1.20.2-R0.1-SNAPSHOT" const val paperDevBundle = paperBuild
const val runPaper = "2.2.0" const val runPaper = "2.2.2"
const val paperWeight = "1.5.6" const val paperWeight = "1.5.11"
} }
// //
@@ -66,6 +72,6 @@ object Versions {
// //
object CLI { object CLI {
const val nbt = "6.1" const val nbt = "6.1"
const val logback = "1.4.11" const val logback = "1.4.14"
} }
} }
@@ -82,7 +82,7 @@ abstract class GenerateDocsTask : DefaultTask() {
} }
template.add(keyName.toString(), description.toString().ifBlank { template.add(keyName.toString(), description.toString().ifBlank {
println("No description provided for field " + field.name + " in class " + name) logger.info("No description provided for field " + field.name + " in class " + name)
"*No description provided.*" "*No description provided.*"
}) })
} }
@@ -1,5 +1,9 @@
package com.dfsek.terra.addons.biome.extrusion.extrusions; package com.dfsek.terra.addons.biome.extrusion.extrusions;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome; import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
import com.dfsek.terra.addons.biome.query.api.BiomeQueries; import com.dfsek.terra.addons.biome.query.api.BiomeQueries;
@@ -8,10 +12,6 @@ import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/** /**
* Sets biomes at locations based on a sampler. * Sets biomes at locations based on a sampler.
@@ -7,13 +7,13 @@
package com.dfsek.terra.addons.biome.image.v2; package com.dfsek.terra.addons.biome.image.v2;
import java.util.Optional;
import com.dfsek.terra.addons.image.colorsampler.ColorSampler; import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
import com.dfsek.terra.addons.image.converter.ColorConverter; import com.dfsek.terra.addons.image.converter.ColorConverter;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import java.util.Optional;
public class ImageBiomeProvider implements BiomeProvider { public class ImageBiomeProvider implements BiomeProvider {
private final int resolution; private final int resolution;
@@ -1,9 +1,9 @@
package com.dfsek.terra.addons.biome.pipeline.v2.api.biome; package com.dfsek.terra.addons.biome.pipeline.v2.api.biome;
import java.util.Set;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import java.util.Set;
public final class DelegatedPipelineBiome implements PipelineBiome { public final class DelegatedPipelineBiome implements PipelineBiome {
private final Biome biome; private final Biome biome;
@@ -14,7 +14,8 @@ public class BiomeChunkImpl implements BiomeChunk {
private final SeededVector worldOrigin; private final SeededVector worldOrigin;
private final int chunkOriginArrayIndex; private final int chunkOriginArrayIndex;
private final int worldCoordinateScale; private final int worldCoordinateScale;
private PipelineBiome[][] biomes; private final int size;
private PipelineBiome[] biomes;
public BiomeChunkImpl(SeededVector worldOrigin, PipelineImpl pipeline) { public BiomeChunkImpl(SeededVector worldOrigin, PipelineImpl pipeline) {
@@ -22,14 +23,14 @@ public class BiomeChunkImpl implements BiomeChunk {
this.chunkOriginArrayIndex = pipeline.getChunkOriginArrayIndex(); this.chunkOriginArrayIndex = pipeline.getChunkOriginArrayIndex();
this.worldCoordinateScale = pipeline.getResolution(); this.worldCoordinateScale = pipeline.getResolution();
int size = pipeline.getArraySize(); this.size = pipeline.getArraySize();
int expanderCount = pipeline.getExpanderCount(); int expanderCount = pipeline.getExpanderCount();
int expansionsApplied = 0; int expansionsApplied = 0;
// Allocate working arrays // Allocate working arrays
this.biomes = new PipelineBiome[size][size]; this.biomes = new PipelineBiome[size * size];
PipelineBiome[][] lookupArray = new PipelineBiome[size][size]; PipelineBiome[] lookupArray = new PipelineBiome[size * size];
// A second lookup array is required such that stage application doesn't affect lookups, otherwise application may cascade // A second lookup array is required such that stage application doesn't affect lookups, otherwise application may cascade
// Construct working grid // Construct working grid
@@ -43,7 +44,7 @@ public class BiomeChunkImpl implements BiomeChunk {
for(int gridZ = 0; gridZ < gridSize; gridZ++) { for(int gridZ = 0; gridZ < gridSize; gridZ++) {
int xIndex = gridOrigin + gridX * gridInterval; int xIndex = gridOrigin + gridX * gridInterval;
int zIndex = gridOrigin + gridZ * gridInterval; int zIndex = gridOrigin + gridZ * gridInterval;
biomes[xIndex][zIndex] = pipeline.getSource().get(worldOrigin.seed(), xIndexToWorldCoordinate(xIndex), biomes[(xIndex * size) + zIndex] = pipeline.getSource().get(worldOrigin.seed(), xIndexToWorldCoordinate(xIndex),
zIndexToWorldCoordinate(zIndex)); zIndexToWorldCoordinate(zIndex));
} }
} }
@@ -65,7 +66,7 @@ public class BiomeChunkImpl implements BiomeChunk {
// Cycle arrays, the previously populated array is swapped to be used for lookups, and the result of the stage application // Cycle arrays, the previously populated array is swapped to be used for lookups, and the result of the stage application
// overwrites the previous lookup array. This saves having to allocate a new array copy each time // overwrites the previous lookup array. This saves having to allocate a new array copy each time
PipelineBiome[][] tempArray = biomes; PipelineBiome[] tempArray = biomes;
biomes = lookupArray; biomes = lookupArray;
lookupArray = tempArray; lookupArray = tempArray;
@@ -74,7 +75,8 @@ public class BiomeChunkImpl implements BiomeChunk {
for(int gridX = 0; gridX < gridSize; gridX = gridX + 1) { for(int gridX = 0; gridX < gridSize; gridX = gridX + 1) {
int xIndex = gridOrigin + gridX * gridInterval; int xIndex = gridOrigin + gridX * gridInterval;
int zIndex = gridOrigin + gridZ * gridInterval; int zIndex = gridOrigin + gridZ * gridInterval;
biomes[xIndex][zIndex] = stage.apply(new ViewPoint(this, gridInterval, gridX, gridZ, xIndex, zIndex, lookupArray)); biomes[(xIndex * size) + zIndex] = stage.apply(
new ViewPoint(this, gridInterval, gridX, gridZ, xIndex, zIndex, lookupArray, size));
} }
} }
} }
@@ -133,7 +135,7 @@ public class BiomeChunkImpl implements BiomeChunk {
public PipelineBiome get(int xInChunk, int zInChunk) { public PipelineBiome get(int xInChunk, int zInChunk) {
int xIndex = xInChunk + chunkOriginArrayIndex; int xIndex = xInChunk + chunkOriginArrayIndex;
int zIndex = zInChunk + chunkOriginArrayIndex; int zIndex = zInChunk + chunkOriginArrayIndex;
return biomes[xIndex][zIndex]; return biomes[(xIndex * size) + zIndex];
} }
private int xIndexToWorldCoordinate(int xIndex) { private int xIndexToWorldCoordinate(int xIndex) {
@@ -159,10 +161,11 @@ public class BiomeChunkImpl implements BiomeChunk {
private final int gridZ; private final int gridZ;
private final int xIndex; private final int xIndex;
private final int zIndex; private final int zIndex;
private final PipelineBiome[][] lookupArray; private final PipelineBiome[] lookupArray;
private final int size;
private ViewPoint(BiomeChunkImpl chunk, int gridInterval, int gridX, int gridZ, int xIndex, int zIndex, private ViewPoint(BiomeChunkImpl chunk, int gridInterval, int gridX, int gridZ, int xIndex, int zIndex,
PipelineBiome[][] lookupArray) { PipelineBiome[] lookupArray, int size) {
this.chunk = chunk; this.chunk = chunk;
this.gridInterval = gridInterval; this.gridInterval = gridInterval;
this.gridX = gridX; this.gridX = gridX;
@@ -170,13 +173,14 @@ public class BiomeChunkImpl implements BiomeChunk {
this.xIndex = xIndex; this.xIndex = xIndex;
this.zIndex = zIndex; this.zIndex = zIndex;
this.lookupArray = lookupArray; this.lookupArray = lookupArray;
this.biome = lookupArray[xIndex][zIndex]; this.size = size;
this.biome = lookupArray[(this.xIndex * this.size) + this.zIndex];
} }
public PipelineBiome getRelativeBiome(int x, int z) { public PipelineBiome getRelativeBiome(int x, int z) {
int lookupXIndex = this.xIndex + x * gridInterval; int lookupXIndex = this.xIndex + x * gridInterval;
int lookupZIndex = this.zIndex + z * gridInterval; int lookupZIndex = this.zIndex + z * gridInterval;
return lookupArray[lookupXIndex][lookupZIndex]; return lookupArray[(lookupXIndex * this.size) + lookupZIndex];
} }
public PipelineBiome getBiome() { public PipelineBiome getBiome() {
@@ -7,17 +7,17 @@
package com.dfsek.terra.addons.biome.pipeline.v2.stage.mutators; package com.dfsek.terra.addons.biome.pipeline.v2.stage.mutators;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import com.dfsek.terra.addons.biome.pipeline.v2.api.Stage; import com.dfsek.terra.addons.biome.pipeline.v2.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.v2.api.biome.PipelineBiome; import com.dfsek.terra.addons.biome.pipeline.v2.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.v2.pipeline.BiomeChunkImpl; import com.dfsek.terra.addons.biome.pipeline.v2.pipeline.BiomeChunkImpl;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
public class ReplaceListStage implements Stage { public class ReplaceListStage implements Stage {
private final Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace; private final Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace;
@@ -13,6 +13,7 @@ import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties;
import com.dfsek.terra.addons.chunkgenerator.config.palette.BiomePaletteTemplate; import com.dfsek.terra.addons.chunkgenerator.config.palette.BiomePaletteTemplate;
import com.dfsek.terra.addons.chunkgenerator.config.palette.slant.SlantLayerTemplate; import com.dfsek.terra.addons.chunkgenerator.config.palette.slant.SlantLayerTemplate;
import com.dfsek.terra.addons.chunkgenerator.generation.NoiseChunkGenerator3D; import com.dfsek.terra.addons.chunkgenerator.generation.NoiseChunkGenerator3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo; import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder; import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.AddonInitializer;
@@ -45,8 +46,8 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer {
.priority(1000) .priority(1000)
.then(event -> { .then(event -> {
event.getPack().applyLoader(SlantHolder.CalculationMethod.class, event.getPack().applyLoader(SlantCalculationMethod.class,
(type, o, loader, depthTracker) -> SlantHolder.CalculationMethod.valueOf((String) o)); (type, o, loader, depthTracker) -> SlantCalculationMethod.valueOf((String) o));
NoiseChunkGeneratorPackConfigTemplate config = event.loadTemplate(new NoiseChunkGeneratorPackConfigTemplate()); NoiseChunkGeneratorPackConfigTemplate config = event.loadTemplate(new NoiseChunkGeneratorPackConfigTemplate());
event.getPack().getContext().put(config); event.getPack().getContext().put(config);
@@ -57,7 +58,7 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer {
pack -> new NoiseChunkGenerator3D(pack, platform, config.getElevationBlend(), pack -> new NoiseChunkGenerator3D(pack, platform, config.getElevationBlend(),
config.getHorizontalRes(), config.getHorizontalRes(),
config.getVerticalRes(), noisePropertiesPropertyKey, config.getVerticalRes(), noisePropertiesPropertyKey,
paletteInfoPropertyKey)); paletteInfoPropertyKey, config.getSlantCalculationMethod()));
event.getPack() event.getPack()
.applyLoader(SlantHolder.Layer.class, SlantLayerTemplate::new); .applyLoader(SlantHolder.Layer.class, SlantLayerTemplate::new);
}) })
@@ -4,7 +4,7 @@ import com.dfsek.tectonic.api.config.template.ConfigTemplate;
import com.dfsek.tectonic.api.config.template.annotations.Default; import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value; import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder; import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.properties.Properties; import com.dfsek.terra.api.properties.Properties;
@@ -24,7 +24,7 @@ public class NoiseChunkGeneratorPackConfigTemplate implements ConfigTemplate, Pr
@Value("slant.calculation-method") @Value("slant.calculation-method")
@Default @Default
private SlantHolder.@Meta CalculationMethod slantCalculationMethod = SlantHolder.CalculationMethod.Derivative; private @Meta SlantCalculationMethod slantCalculationMethod = SlantCalculationMethod.Derivative;
public int getElevationBlend() { public int getElevationBlend() {
return elevationBlend; return elevationBlend;
@@ -38,7 +38,7 @@ public class NoiseChunkGeneratorPackConfigTemplate implements ConfigTemplate, Pr
return verticalRes; return verticalRes;
} }
public SlantHolder.CalculationMethod getSlantCalculationMethod() { public SlantCalculationMethod getSlantCalculationMethod() {
return slantCalculationMethod; return slantCalculationMethod;
} }
} }
@@ -16,6 +16,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo; import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder; import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder;
@@ -27,7 +28,7 @@ import com.dfsek.terra.api.world.chunk.generation.util.Palette;
public class BiomePaletteTemplate implements ObjectTemplate<BiomePaletteInfo> { public class BiomePaletteTemplate implements ObjectTemplate<BiomePaletteInfo> {
private final Platform platform; private final Platform platform;
private final SlantHolder.CalculationMethod slantCalculationMethod; private final SlantCalculationMethod slantCalculationMethod;
@Value("slant") @Value("slant")
@Default @Default
@Description("The slant palettes to use in this biome.") @Description("The slant palettes to use in this biome.")
@@ -56,7 +57,7 @@ public class BiomePaletteTemplate implements ObjectTemplate<BiomePaletteInfo> {
@Default @Default
private @Meta boolean updatePalette = false; private @Meta boolean updatePalette = false;
public BiomePaletteTemplate(Platform platform, SlantHolder.CalculationMethod slantCalculationMethod) { public BiomePaletteTemplate(Platform platform, SlantCalculationMethod slantCalculationMethod) {
this.platform = platform; this.platform = platform;
this.slantCalculationMethod = slantCalculationMethod; this.slantCalculationMethod = slantCalculationMethod;
} }
@@ -8,10 +8,13 @@
package com.dfsek.terra.addons.chunkgenerator.generation; package com.dfsek.terra.addons.chunkgenerator.generation;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties;
import com.dfsek.terra.addons.chunkgenerator.generation.math.PaletteUtil;
import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.LazilyEvaluatedInterpolator; import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.LazilyEvaluatedInterpolator;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider; import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider;
@@ -42,16 +45,19 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
private final PropertyKey<BiomePaletteInfo> paletteInfoPropertyKey; private final PropertyKey<BiomePaletteInfo> paletteInfoPropertyKey;
private final PropertyKey<BiomeNoiseProperties> noisePropertiesKey; private final PropertyKey<BiomeNoiseProperties> noisePropertiesKey;
private final SlantCalculationMethod slantCalculationMethod;
public NoiseChunkGenerator3D(ConfigPack pack, Platform platform, int elevationBlend, int carverHorizontalResolution, public NoiseChunkGenerator3D(ConfigPack pack, Platform platform, int elevationBlend, int carverHorizontalResolution,
int carverVerticalResolution, int carverVerticalResolution,
PropertyKey<BiomeNoiseProperties> noisePropertiesKey, PropertyKey<BiomeNoiseProperties> noisePropertiesKey,
PropertyKey<BiomePaletteInfo> paletteInfoPropertyKey) { PropertyKey<BiomePaletteInfo> paletteInfoPropertyKey, SlantCalculationMethod slantCalculationMethod) {
this.platform = platform; this.platform = platform;
this.air = platform.getWorldHandle().air(); this.air = platform.getWorldHandle().air();
this.carverHorizontalResolution = carverHorizontalResolution; this.carverHorizontalResolution = carverHorizontalResolution;
this.carverVerticalResolution = carverVerticalResolution; this.carverVerticalResolution = carverVerticalResolution;
this.paletteInfoPropertyKey = paletteInfoPropertyKey; this.paletteInfoPropertyKey = paletteInfoPropertyKey;
this.noisePropertiesKey = noisePropertiesKey; this.noisePropertiesKey = noisePropertiesKey;
this.slantCalculationMethod = slantCalculationMethod;
int maxBlend = pack int maxBlend = pack
.getBiomeProvider() .getBiomeProvider()
.stream() .stream()
@@ -63,6 +69,17 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
this.samplerCache = new SamplerProvider(platform, elevationBlend, noisePropertiesKey, maxBlend); this.samplerCache = new SamplerProvider(platform, elevationBlend, noisePropertiesKey, maxBlend);
} }
private Palette paletteAt(int x, int y, int z, Sampler3D sampler, BiomePaletteInfo paletteInfo, int depth) {
SlantHolder slantHolder = paletteInfo.slantHolder();
if(slantHolder.isAboveDepth(depth)) {
double slant = slantCalculationMethod.slant(sampler, x, y, z);
if(slantHolder.isInSlantThreshold(slant)) {
return slantHolder.getPalette(slant).getPalette(y);
}
}
return paletteInfo.paletteHolder().getPalette(y);
}
@Override @Override
@SuppressWarnings("try") @SuppressWarnings("try")
public void generateChunkData(@NotNull ProtoChunk chunk, @NotNull WorldProperties world, public void generateChunkData(@NotNull ProtoChunk chunk, @NotNull WorldProperties world,
@@ -103,8 +120,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
if(sampler.sample(x, y, z) > 0) { if(sampler.sample(x, y, z) > 0) {
if(carver.sample(x, y, z) <= 0) { if(carver.sample(x, y, z) <= 0) {
data = PaletteUtil data = paletteAt(x, y, z, sampler, paletteInfo, paletteLevel)
.getPalette(x, y, z, sampler, paletteInfo, paletteLevel)
.get(paletteLevel, cx, y, cz, seed); .get(paletteLevel, cx, y, cz, seed);
chunk.setBlock(x, y, z, data); chunk.setBlock(x, y, z, data);
paletteLevel++; paletteLevel++;
@@ -135,7 +151,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
int fdX = Math.floorMod(x, 16); int fdX = Math.floorMod(x, 16);
int fdZ = Math.floorMod(z, 16); int fdZ = Math.floorMod(z, 16);
Palette palette = PaletteUtil.getPalette(fdX, y, fdZ, sampler, paletteInfo, 0); Palette palette = paletteAt(fdX, y, fdZ, sampler, paletteInfo, 0);
double noise = sampler.sample(fdX, y, fdZ); double noise = sampler.sample(fdX, y, fdZ);
if(noise > 0) { if(noise > 0) {
int level = 0; int level = 0;
@@ -157,11 +173,8 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
public double getSlant(int x, int y, int z, WorldProperties world, BiomeProvider biomeProvider) { public double getSlant(int x, int y, int z, WorldProperties world, BiomeProvider biomeProvider) {
int fdX = Math.floorMod(x, 16); int fdX = Math.floorMod(x, 16);
int fdZ = Math.floorMod(z, 16); int fdZ = Math.floorMod(z, 16);
return biomeProvider.getBiome(x, y, z, world.getSeed()) Sampler3D sampler = samplerCache.get(x, z, world, biomeProvider);
.getContext() return slantCalculationMethod.slant(sampler, fdX, y, fdZ);
.get(paletteInfoPropertyKey)
.slantHolder()
.calculateSlant(samplerCache.get(x, z, world, biomeProvider), fdX, y, fdZ);
} }
public SamplerProvider samplerProvider() { public SamplerProvider samplerProvider() {
@@ -1,29 +0,0 @@
/*
* Copyright (c) 2020-2023 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.generation.math;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder;
import com.dfsek.terra.api.world.chunk.generation.util.Palette;
public final class PaletteUtil {
public static Palette getPalette(int x, int y, int z, Sampler3D sampler, BiomePaletteInfo paletteInfo, int depth) {
SlantHolder slantHolder = paletteInfo.slantHolder();
if(slantHolder.isAboveDepth(depth)) {
double slant = slantHolder.calculateSlant(sampler, x, y, z);
if(slantHolder.isInSlantThreshold(slant)) {
return slantHolder.getPalette(slant).getPalette(y);
}
}
return paletteInfo.paletteHolder().getPalette(y);
}
}
@@ -0,0 +1,69 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.api.util.vector.Vector3;
public enum SlantCalculationMethod {
DotProduct {
private static final Vector3 DOT_PRODUCT_DIRECTION = Vector3.of(0, 1, 0);
private static final Vector3[] DOT_PRODUCT_SAMPLE_POINTS = {
Vector3.of(0, 0, -DERIVATIVE_DIST),
Vector3.of(0, 0, DERIVATIVE_DIST),
Vector3.of(0, -DERIVATIVE_DIST, 0),
Vector3.of(0, DERIVATIVE_DIST, 0),
Vector3.of(-DERIVATIVE_DIST, 0, 0),
Vector3.of(DERIVATIVE_DIST, 0, 0)
};
@Override
public double slant(Sampler3D sampler, double x, double y, double z) {
Vector3.Mutable normalApproximation = Vector3.Mutable.of(0, 0, 0);
for(Vector3 point : DOT_PRODUCT_SAMPLE_POINTS) {
var scalar = -sampler.sample(x + point.getX(), y + point.getY(), z + point.getZ());
normalApproximation.add(point.mutable().multiply(scalar));
}
return DOT_PRODUCT_DIRECTION.dot(normalApproximation.normalize());
}
@Override
public boolean floorToThreshold() {
return false;
}
},
Derivative {
@Override
public double slant(Sampler3D 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)));
}
@Override
public boolean floorToThreshold() {
return true;
}
};
private static final double DERIVATIVE_DIST = 0.55;
public abstract double slant(Sampler3D sampler, double x, double y, double z);
/*
* Controls whether palettes should be applied before or after their respective thresholds.
*
* If true, slant values will map to the palette of the next floor threshold, otherwise they
* will map to the ceiling.
*/
public abstract boolean floorToThreshold();
}
@@ -14,6 +14,7 @@ import java.util.TreeMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
@@ -21,7 +22,7 @@ public class MultipleSlantHolder extends SlantHolderImpl {
private final NavigableMap<Double, PaletteHolder> layers; private final NavigableMap<Double, PaletteHolder> layers;
private final double slantThreshold; private final double slantThreshold;
MultipleSlantHolder(List<SlantHolder.Layer> slant, int slantDepth, CalculationMethod calculationMethod) { MultipleSlantHolder(List<SlantHolder.Layer> slant, int slantDepth, SlantCalculationMethod calculationMethod) {
super(slantDepth, calculationMethod); super(slantDepth, calculationMethod);
NavigableMap<Double, PaletteHolder> layers = new TreeMap<>( NavigableMap<Double, PaletteHolder> layers = new TreeMap<>(
slant.stream().collect(Collectors.toMap(SlantHolder.Layer::threshold, SlantHolder.Layer::palette))); slant.stream().collect(Collectors.toMap(SlantHolder.Layer::threshold, SlantHolder.Layer::palette)));
@@ -1,5 +1,6 @@
package com.dfsek.terra.addons.chunkgenerator.palette.slant; package com.dfsek.terra.addons.chunkgenerator.palette.slant;
import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
@@ -7,7 +8,7 @@ final class SingleSlantHolder extends SlantHolderImpl {
private final SlantHolder.Layer layer; private final SlantHolder.Layer layer;
public SingleSlantHolder(SlantHolder.Layer layer, int slantDepth, CalculationMethod calculationMethod) { public SingleSlantHolder(SlantHolder.Layer layer, int slantDepth, SlantCalculationMethod calculationMethod) {
super(slantDepth, calculationMethod); super(slantDepth, calculationMethod);
this.layer = layer; this.layer = layer;
} }
@@ -2,19 +2,13 @@ package com.dfsek.terra.addons.chunkgenerator.palette.slant;
import java.util.List; import java.util.List;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
import com.dfsek.terra.api.util.vector.Vector3;
public interface SlantHolder { public interface SlantHolder {
SlantHolder EMPTY = new SlantHolder() { SlantHolder EMPTY = new SlantHolder() {
@Override
public double calculateSlant(Sampler3D sampler, double x, double y, double z) {
throw new UnsupportedOperationException("Empty holder should not calculate slant");
}
@Override @Override
public boolean isAboveDepth(int depth) { public boolean isAboveDepth(int depth) {
return false; return false;
@@ -31,7 +25,7 @@ public interface SlantHolder {
} }
}; };
static SlantHolder of(List<SlantHolder.Layer> layers, int slantDepth, CalculationMethod calculationMethod) { static SlantHolder of(List<SlantHolder.Layer> layers, int slantDepth, SlantCalculationMethod calculationMethod) {
if(layers.isEmpty()) { if(layers.isEmpty()) {
return EMPTY; return EMPTY;
} else if(layers.size() == 1) { } else if(layers.size() == 1) {
@@ -40,8 +34,6 @@ public interface SlantHolder {
return new MultipleSlantHolder(layers, slantDepth, calculationMethod); return new MultipleSlantHolder(layers, slantDepth, calculationMethod);
} }
double calculateSlant(Sampler3D sampler, double x, double y, double z);
boolean isAboveDepth(int depth); boolean isAboveDepth(int depth);
boolean isInSlantThreshold(double slant); boolean isInSlantThreshold(double slant);
@@ -49,71 +41,6 @@ public interface SlantHolder {
PaletteHolder getPalette(double slant); PaletteHolder getPalette(double slant);
enum CalculationMethod {
DotProduct {
private static final Vector3 DOT_PRODUCT_DIRECTION = Vector3.of(0, 1, 0);
private static final Vector3[] DOT_PRODUCT_SAMPLE_POINTS = {
Vector3.of(0, 0, -DERIVATIVE_DIST),
Vector3.of(0, 0, DERIVATIVE_DIST),
Vector3.of(0, -DERIVATIVE_DIST, 0),
Vector3.of(0, DERIVATIVE_DIST, 0),
Vector3.of(-DERIVATIVE_DIST, 0, 0),
Vector3.of(DERIVATIVE_DIST, 0, 0)
};
@Override
public double slant(Sampler3D sampler, double x, double y, double z) {
Vector3.Mutable normalApproximation = Vector3.Mutable.of(0, 0, 0);
for(Vector3 point : DOT_PRODUCT_SAMPLE_POINTS) {
var scalar = -sampler.sample(x + point.getX(), y + point.getY(), z + point.getZ());
normalApproximation.add(point.mutable().multiply(scalar));
}
return DOT_PRODUCT_DIRECTION.dot(normalApproximation.normalize());
}
@Override
public boolean floorToThreshold() {
return false;
}
},
Derivative {
@Override
public double slant(Sampler3D 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)));
}
@Override
public boolean floorToThreshold() {
return true;
}
};
private static final double DERIVATIVE_DIST = 0.55;
public abstract double slant(Sampler3D sampler, double x, double y, double z);
/*
* Controls whether palettes should be applied before or after their respective thresholds.
*
* If true, slant values will map to the palette of the next floor threshold, otherwise they
* will map to the ceiling.
*/
public abstract boolean floorToThreshold();
}
record Layer(PaletteHolder palette, double threshold) { record Layer(PaletteHolder palette, double threshold) {
} }
} }
@@ -1,26 +1,19 @@
package com.dfsek.terra.addons.chunkgenerator.palette.slant; package com.dfsek.terra.addons.chunkgenerator.palette.slant;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; import com.dfsek.terra.addons.chunkgenerator.generation.math.SlantCalculationMethod;
public abstract class SlantHolderImpl implements SlantHolder { public abstract class SlantHolderImpl implements SlantHolder {
protected final boolean floorToThreshold; protected final boolean floorToThreshold;
private final SlantHolder.CalculationMethod calculationMethod;
private final int slantDepth; private final int slantDepth;
protected SlantHolderImpl(int slantDepth, CalculationMethod calculationMethod) { protected SlantHolderImpl(int slantDepth, SlantCalculationMethod calculationMethod) {
this.floorToThreshold = calculationMethod.floorToThreshold(); this.floorToThreshold = calculationMethod.floorToThreshold();
this.calculationMethod = calculationMethod;
this.slantDepth = slantDepth; this.slantDepth = slantDepth;
} }
protected abstract double getSlantThreshold(); protected abstract double getSlantThreshold();
@Override
public final double calculateSlant(Sampler3D sampler, double x, double y, double z) {
return calculationMethod.slant(sampler, x, y, z);
}
@Override @Override
public final boolean isAboveDepth(int depth) { public final boolean isAboveDepth(int depth) {
return depth <= slantDepth; return depth <= slantDepth;
@@ -6,7 +6,8 @@ import cloud.commandframework.arguments.standard.EnumArgument;
import cloud.commandframework.arguments.standard.LongArgument; import cloud.commandframework.arguments.standard.LongArgument;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
@@ -56,7 +57,11 @@ public class StructureCommandAddon implements AddonInitializer {
structure.generate( structure.generate(
sender.position().toInt(), sender.position().toInt(),
sender.world(), sender.world(),
((Long) context.get("seed") == 0) ? new Random() : new Random(context.get("seed")), ((Long) context.get("seed") == 0)
? RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus")
.create()
: RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus")
.create(context.get("seed")),
context.get("rotation") context.get("rotation")
); );
}) })
@@ -1,6 +1,7 @@
package com.dfsek.terra.addons.feature.distributor.distributors; package com.dfsek.terra.addons.feature.distributor.distributors;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
import com.dfsek.terra.api.util.MathUtil; import com.dfsek.terra.api.util.MathUtil;
@@ -24,7 +25,8 @@ public class PaddedGridDistributor implements Distributor {
int cellX = Math.floorDiv(x, cellWidth); int cellX = Math.floorDiv(x, cellWidth);
int cellZ = Math.floorDiv(z, cellWidth); int cellZ = Math.floorDiv(z, cellWidth);
Random random = new Random((MathUtil.murmur64(MathUtil.squash(cellX, cellZ)) ^ seed) + salt); RandomGenerator random = RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(
(MathUtil.murmur64(MathUtil.squash(cellX, cellZ)) ^ seed) + salt);
int pointX = random.nextInt(width) + cellX * cellWidth; int pointX = random.nextInt(width) + cellX * cellWidth;
int pointZ = random.nextInt(width) + cellZ * cellWidth; int pointZ = random.nextInt(width) + cellZ * cellWidth;
@@ -10,7 +10,8 @@ package com.dfsek.terra.addons.flora.flora.gen;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.block.state.properties.enums.Direction; import com.dfsek.terra.api.block.state.properties.enums.Direction;
@@ -71,7 +72,7 @@ public class TerraFlora implements Structure {
} }
@Override @Override
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
boolean doRotation = testRotation.size() > 0; boolean doRotation = testRotation.size() > 0;
int size = layers.size(); int size = layers.size();
int c = ceiling ? -1 : 1; int c = ceiling ? -1 : 1;
@@ -86,7 +87,9 @@ public class TerraFlora implements Structure {
location.getZ(), world.getSeed()); location.getZ(), world.getSeed());
if(doRotation) { if(doRotation) {
Direction oneFace = new ArrayList<>(faces).get( Direction oneFace = new ArrayList<>(faces).get(
new Random(location.getX() ^ location.getZ()).nextInt(faces.size())); // Get random face. RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus")
.create(location.getX() ^ location.getZ())
.nextInt(faces.size())); // Get RandomGenerator face.
} }
world.setBlockState(location.mutable().add(0, i + c, 0).immutable(), data, physics); world.setBlockState(location.mutable().add(0, i + c, 0).immutable(), data, physics);
} }
@@ -7,7 +7,8 @@
package com.dfsek.terra.addons.feature.locator.locators; package com.dfsek.terra.addons.feature.locator.locators;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.api.structure.feature.BinaryColumn; import com.dfsek.terra.api.structure.feature.BinaryColumn;
import com.dfsek.terra.api.structure.feature.Locator; import com.dfsek.terra.api.structure.feature.Locator;
@@ -40,7 +41,7 @@ public class GaussianRandomLocator implements Locator {
seed = 31 * seed + column.getZ(); seed = 31 * seed + column.getZ();
seed += salt; seed += salt;
Random r = new Random(seed); RandomGenerator r = RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(seed);
int size = points.get(r); int size = points.get(r);
@@ -7,7 +7,8 @@
package com.dfsek.terra.addons.feature.locator.locators; package com.dfsek.terra.addons.feature.locator.locators;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.api.structure.feature.BinaryColumn; import com.dfsek.terra.api.structure.feature.BinaryColumn;
import com.dfsek.terra.api.structure.feature.Locator; import com.dfsek.terra.api.structure.feature.Locator;
@@ -36,7 +37,7 @@ public class RandomLocator implements Locator {
seed = 31 * seed + column.getZ(); seed = 31 * seed + column.getZ();
seed += salt; seed += salt;
Random r = new Random(seed); RandomGenerator r = RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(seed);
int size = points.get(r); int size = points.get(r);
@@ -24,7 +24,7 @@ public class BrownianMotionSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) { for(int i = 0; i < octaves; i++) {
double noise = input.noise(seed++, x, y); double noise = input.noise(seed++, x, y);
sum += noise * amp; sum += noise * amp;
amp *= MathUtil.lerp(1.0, Math.min(noise + 1, 2) * 0.5, weightedStrength); amp *= MathUtil.lerp(weightedStrength, 1.0, Math.min(noise + 1, 2) * 0.5);
x *= lacunarity; x *= lacunarity;
y *= lacunarity; y *= lacunarity;
@@ -42,7 +42,7 @@ public class BrownianMotionSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) { for(int i = 0; i < octaves; i++) {
double noise = input.noise(seed++, x, y, z); double noise = input.noise(seed++, x, y, z);
sum += noise * amp; sum += noise * amp;
amp *= MathUtil.lerp(1.0, (noise + 1) * 0.5, weightedStrength); amp *= MathUtil.lerp(weightedStrength, 1.0, (noise + 1) * 0.5);
x *= lacunarity; x *= lacunarity;
y *= lacunarity; y *= lacunarity;
@@ -36,7 +36,7 @@ public class PingPongSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) { for(int i = 0; i < octaves; i++) {
double noise = pingPong((input.noise(seed++, x, y) + 1) * pingPongStrength); double noise = pingPong((input.noise(seed++, x, y) + 1) * pingPongStrength);
sum += (noise - 0.5) * 2 * amp; sum += (noise - 0.5) * 2 * amp;
amp *= MathUtil.lerp(1.0, noise, weightedStrength); amp *= MathUtil.lerp(weightedStrength, 1.0, noise);
x *= lacunarity; x *= lacunarity;
y *= lacunarity; y *= lacunarity;
@@ -54,7 +54,7 @@ public class PingPongSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) { for(int i = 0; i < octaves; i++) {
double noise = pingPong((input.noise(seed++, x, y, z) + 1) * pingPongStrength); double noise = pingPong((input.noise(seed++, x, y, z) + 1) * pingPongStrength);
sum += (noise - 0.5) * 2 * amp; sum += (noise - 0.5) * 2 * amp;
amp *= MathUtil.lerp(1.0, noise, weightedStrength); amp *= MathUtil.lerp(weightedStrength, 1.0, noise);
x *= lacunarity; x *= lacunarity;
y *= lacunarity; y *= lacunarity;
@@ -25,7 +25,7 @@ public class RidgedFractalSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) { for(int i = 0; i < octaves; i++) {
double noise = Math.abs(input.noise(seed++, x, y)); double noise = Math.abs(input.noise(seed++, x, y));
sum += (noise * -2 + 1) * amp; sum += (noise * -2 + 1) * amp;
amp *= MathUtil.lerp(1.0, 1 - noise, weightedStrength); amp *= MathUtil.lerp(weightedStrength, 1.0, 1 - noise);
x *= lacunarity; x *= lacunarity;
y *= lacunarity; y *= lacunarity;
@@ -43,7 +43,7 @@ public class RidgedFractalSampler extends FractalNoiseFunction {
for(int i = 0; i < octaves; i++) { for(int i = 0; i < octaves; i++) {
double noise = Math.abs(input.noise(seed++, x, y, z)); double noise = Math.abs(input.noise(seed++, x, y, z));
sum += (noise * -2 + 1) * amp; sum += (noise * -2 + 1) * amp;
amp *= MathUtil.lerp(1.0, 1 - noise, weightedStrength); amp *= MathUtil.lerp(weightedStrength, 1.0, 1 - noise);
x *= lacunarity; x *= lacunarity;
y *= lacunarity; y *= lacunarity;
@@ -33,10 +33,10 @@ public class PerlinSampler extends SimplexStyleSampler {
int x1 = x0 + PRIME_X; int x1 = x0 + PRIME_X;
int y1 = y0 + PRIME_Y; int y1 = y0 + PRIME_Y;
double xf0 = MathUtil.lerp(gradCoord(seed, x0, y0, xd0, yd0), gradCoord(seed, x1, y0, xd1, yd0), xs); double xf0 = MathUtil.lerp(xs, gradCoord(seed, x0, y0, xd0, yd0), gradCoord(seed, x1, y0, xd1, yd0));
double xf1 = MathUtil.lerp(gradCoord(seed, x0, y1, xd0, yd1), gradCoord(seed, x1, y1, xd1, yd1), xs); double xf1 = MathUtil.lerp(xs, gradCoord(seed, x0, y1, xd0, yd1), gradCoord(seed, x1, y1, xd1, yd1));
return MathUtil.lerp(xf0, xf1, ys) * 1.4247691104677813; return MathUtil.lerp(ys, xf0, xf1) * 1.4247691104677813;
} }
@Override @Override
@@ -64,14 +64,14 @@ public class PerlinSampler extends SimplexStyleSampler {
int y1 = y0 + PRIME_Y; int y1 = y0 + PRIME_Y;
int z1 = z0 + PRIME_Z; int z1 = z0 + PRIME_Z;
double xf00 = MathUtil.lerp(gradCoord(seed, x0, y0, z0, xd0, yd0, zd0), gradCoord(seed, x1, y0, z0, xd1, yd0, zd0), xs); double xf00 = MathUtil.lerp(xs, gradCoord(seed, x0, y0, z0, xd0, yd0, zd0), gradCoord(seed, x1, y0, z0, xd1, yd0, zd0));
double xf10 = MathUtil.lerp(gradCoord(seed, x0, y1, z0, xd0, yd1, zd0), gradCoord(seed, x1, y1, z0, xd1, yd1, zd0), xs); double xf10 = MathUtil.lerp(xs, gradCoord(seed, x0, y1, z0, xd0, yd1, zd0), gradCoord(seed, x1, y1, z0, xd1, yd1, zd0));
double xf01 = MathUtil.lerp(gradCoord(seed, x0, y0, z1, xd0, yd0, zd1), gradCoord(seed, x1, y0, z1, xd1, yd0, zd1), xs); double xf01 = MathUtil.lerp(xs, gradCoord(seed, x0, y0, z1, xd0, yd0, zd1), gradCoord(seed, x1, y0, z1, xd1, yd0, zd1));
double xf11 = MathUtil.lerp(gradCoord(seed, x0, y1, z1, xd0, yd1, zd1), gradCoord(seed, x1, y1, z1, xd1, yd1, zd1), xs); double xf11 = MathUtil.lerp(xs, gradCoord(seed, x0, y1, z1, xd0, yd1, zd1), gradCoord(seed, x1, y1, z1, xd1, yd1, zd1));
double yf0 = MathUtil.lerp(xf00, xf10, ys); double yf0 = MathUtil.lerp(ys, xf00, xf10);
double yf1 = MathUtil.lerp(xf01, xf11, ys); double yf1 = MathUtil.lerp(ys, xf01, xf11);
return MathUtil.lerp(yf0, yf1, zs) * 0.964921414852142333984375; return MathUtil.lerp(zs, yf0, yf1) * 0.964921414852142333984375;
} }
} }
@@ -25,10 +25,10 @@ public class ValueSampler extends ValueStyleNoise {
int x1 = x0 + PRIME_X; int x1 = x0 + PRIME_X;
int y1 = y0 + PRIME_Y; int y1 = y0 + PRIME_Y;
double xf0 = MathUtil.lerp(valCoord(seed, x0, y0), valCoord(seed, x1, y0), xs); double xf0 = MathUtil.lerp(xs, valCoord(seed, x0, y0), valCoord(seed, x1, y0));
double xf1 = MathUtil.lerp(valCoord(seed, x0, y1), valCoord(seed, x1, y1), xs); double xf1 = MathUtil.lerp(xs, valCoord(seed, x0, y1), valCoord(seed, x1, y1));
return MathUtil.lerp(xf0, xf1, ys); return MathUtil.lerp(ys, xf0, xf1);
} }
@Override @Override
@@ -49,14 +49,14 @@ public class ValueSampler extends ValueStyleNoise {
int y1 = y0 + PRIME_Y; int y1 = y0 + PRIME_Y;
int z1 = z0 + PRIME_Z; int z1 = z0 + PRIME_Z;
double xf00 = MathUtil.lerp(valCoord(seed, x0, y0, z0), valCoord(seed, x1, y0, z0), xs); double xf00 = MathUtil.lerp(xs, valCoord(seed, x0, y0, z0), valCoord(seed, x1, y0, z0));
double xf10 = MathUtil.lerp(valCoord(seed, x0, y1, z0), valCoord(seed, x1, y1, z0), xs); double xf10 = MathUtil.lerp(xs, valCoord(seed, x0, y1, z0), valCoord(seed, x1, y1, z0));
double xf01 = MathUtil.lerp(valCoord(seed, x0, y0, z1), valCoord(seed, x1, y0, z1), xs); double xf01 = MathUtil.lerp(xs, valCoord(seed, x0, y0, z1), valCoord(seed, x1, y0, z1));
double xf11 = MathUtil.lerp(valCoord(seed, x0, y1, z1), valCoord(seed, x1, y1, z1), xs); double xf11 = MathUtil.lerp(xs, valCoord(seed, x0, y1, z1), valCoord(seed, x1, y1, z1));
double yf0 = MathUtil.lerp(xf00, xf10, ys); double yf0 = MathUtil.lerp(ys, xf00, xf10);
double yf1 = MathUtil.lerp(xf01, xf11, ys); double yf1 = MathUtil.lerp(ys, xf01, xf11);
return MathUtil.lerp(yf0, yf1, zs); return MathUtil.lerp(zs, yf0, yf1);
} }
} }
+1 -1
View File
@@ -1,4 +1,4 @@
version = version("1.1.0") version = version("1.1.1")
dependencies { dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader")) compileOnlyApi(project(":common:addons:manifest-addon-loader"))
@@ -9,7 +9,7 @@ package com.dfsek.terra.addons.ore.ores;
import java.util.BitSet; import java.util.BitSet;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.block.BlockType; import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
@@ -44,7 +44,7 @@ public class VanillaOre implements Structure {
} }
@Override @Override
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
float randomRadian = random.nextFloat() * (float) Math.PI; float randomRadian = random.nextFloat() * (float) Math.PI;
double eighthSize = size / 8.0F; double eighthSize = size / 8.0F;
@@ -1,7 +1,7 @@
package com.dfsek.terra.addons.ore.ores; package com.dfsek.terra.addons.ore.ores;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.block.BlockType; import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
@@ -24,7 +24,7 @@ public class VanillaScatteredOre extends VanillaOre {
} }
@Override @Override
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
int i = random.nextInt((int) (size + 1)); int i = random.nextInt((int) (size + 1));
Vector3Int.Mutable mutable = Vector3Int.zero().mutable(); Vector3Int.Mutable mutable = Vector3Int.zero().mutable();
@@ -39,7 +39,7 @@ public class VanillaScatteredOre extends VanillaOre {
return true; return true;
} }
private void setPos(Vector3Int.Mutable mutable, Random random, Vector3Int location, int spread) { private void setPos(Vector3Int.Mutable mutable, RandomGenerator random, Vector3Int location, int spread) {
int x = this.getSpread(random, spread); int x = this.getSpread(random, spread);
int y = this.getSpread(random, spread); int y = this.getSpread(random, spread);
int z = this.getSpread(random, spread); int z = this.getSpread(random, spread);
@@ -48,7 +48,7 @@ public class VanillaScatteredOre extends VanillaOre {
mutable.setZ(location.getZ() + z); mutable.setZ(location.getZ() + z);
} }
private int getSpread(Random random, int spread) { private int getSpread(RandomGenerator random, int spread) {
return Math.round((random.nextFloat() - random.nextFloat()) * (float) spread); return Math.round((random.nextFloat() - random.nextFloat()) * (float) spread);
} }
} }
@@ -1,6 +1,6 @@
package com.dfsek.terra.addons.ore.utils; package com.dfsek.terra.addons.ore.utils;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.block.BlockType; import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.util.collection.MaterialSet; import com.dfsek.terra.api.util.collection.MaterialSet;
@@ -8,31 +8,25 @@ import com.dfsek.terra.api.world.WritableWorld;
public class VanillaOreUtils { public class VanillaOreUtils {
protected static boolean shouldNotDiscard(Random random, double chance) { private static boolean shouldExpose(RandomGenerator random, double exposedChance) {
if(chance <= 0.0F) { if(exposedChance >= 1.0F) return true;
return true; if(exposedChance <= 0.0F) return false;
} else if(chance >= 1.0F) { return random.nextFloat() < exposedChance;
return false;
} else {
return random.nextFloat() >= chance;
}
} }
public static boolean shouldPlace(MaterialSet replaceable, BlockType type, Double exposed, Random random, WritableWorld world, int x, public static boolean shouldPlace(MaterialSet replaceable, BlockType type, Double exposedChance, RandomGenerator random,
WritableWorld world,
int x,
int y, int z) { int y, int z) {
if(!replaceable.contains(type)) { if(!replaceable.contains(type)) return false;
return false; if(shouldExpose(random, exposedChance)) return true; // Exposed blocks can be placed regardless of adjacency to air
} else if(shouldNotDiscard(random, exposed)) { // Adjacency is checked after determining not exposed rather than vice-versa, assuming block checks are more expensive
return true; boolean adjacentAir = world.getBlockState(x, y, z - 1).isAir() ||
} else { world.getBlockState(x, y, z + 1).isAir() ||
return !(world.getBlockState(x, y, z - 1).isAir() || world.getBlockState(x, y - 1, z).isAir() ||
world.getBlockState(x, y, z + 1).isAir() || world.getBlockState(x, y + 1, z).isAir() ||
world.getBlockState(x, y - 1, z).isAir() || world.getBlockState(x - 1, y, z).isAir() ||
world.getBlockState(x, y + 1, z).isAir() || world.getBlockState(x + 1, y, z).isAir();
world.getBlockState(x - 1, y, z).isAir() || return !adjacentAir; // Exposed check did not pass earlier so only blocks not adjacent air should place
world.getBlockState(x + 1, y, z).isAir());
}
} }
} }
@@ -12,7 +12,7 @@ import org.json.simple.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.addons.structure.structures.loot.functions.AmountFunction; import com.dfsek.terra.addons.structure.structures.loot.functions.AmountFunction;
import com.dfsek.terra.addons.structure.structures.loot.functions.DamageFunction; import com.dfsek.terra.addons.structure.structures.loot.functions.DamageFunction;
@@ -85,11 +85,11 @@ public class Entry {
/** /**
* Fetches a single ItemStack from the Entry, applying all functions to it. * Fetches a single ItemStack from the Entry, applying all functions to it.
* *
* @param r The Random instance to apply functions with * @param r The RandomGenerator instance to apply functions with
* *
* @return ItemStack - The ItemStack with all functions applied. * @return ItemStack - The ItemStack with all functions applied.
*/ */
public ItemStack getItem(Random r) { public ItemStack getItem(RandomGenerator r) {
ItemStack item = this.item.newItemStack(1); ItemStack item = this.item.newItemStack(1);
for(LootFunction f : functions) { for(LootFunction f : functions) {
item = f.apply(item, r); item = f.apply(item, r);
@@ -14,7 +14,7 @@ import org.json.simple.parser.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.inventory.Inventory; import com.dfsek.terra.api.inventory.Inventory;
@@ -44,7 +44,7 @@ public class LootTableImpl implements com.dfsek.terra.api.structure.LootTable {
} }
@Override @Override
public void fillInventory(Inventory i, Random r) { public void fillInventory(Inventory i, RandomGenerator r) {
List<ItemStack> loot = getLoot(r); List<ItemStack> loot = getLoot(r);
for(ItemStack stack : loot) { for(ItemStack stack : loot) {
int attempts = 0; int attempts = 0;
@@ -70,7 +70,7 @@ public class LootTableImpl implements com.dfsek.terra.api.structure.LootTable {
} }
@Override @Override
public List<ItemStack> getLoot(Random r) { public List<ItemStack> getLoot(RandomGenerator r) {
List<ItemStack> itemList = new ArrayList<>(); List<ItemStack> itemList = new ArrayList<>();
for(Pool pool : pools) { for(Pool pool : pools) {
itemList.addAll(pool.getItems(r)); itemList.addAll(pool.getItems(r));
@@ -12,7 +12,7 @@ import org.json.simple.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.inventory.ItemStack; import com.dfsek.terra.api.inventory.ItemStack;
@@ -50,13 +50,13 @@ public class Pool {
} }
/** /**
* Fetches a list of items from the pool using the provided Random instance. * Fetches a list of items from the pool using the provided RandomGenerator instance.
* *
* @param r The Random instance to use. * @param r The RandomGenerator instance to use.
* *
* @return List&lt;ItemStack&gt; - The list of items fetched. * @return List&lt;ItemStack&gt; - The list of items fetched.
*/ */
public List<ItemStack> getItems(Random r) { public List<ItemStack> getItems(RandomGenerator r) {
int rolls = r.nextInt(max - min + 1) + min; int rolls = r.nextInt(max - min + 1) + min;
List<ItemStack> items = new ArrayList<>(); List<ItemStack> items = new ArrayList<>();
@@ -8,7 +8,7 @@
package com.dfsek.terra.addons.structure.structures.loot.functions; package com.dfsek.terra.addons.structure.structures.loot.functions;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.inventory.ItemStack; import com.dfsek.terra.api.inventory.ItemStack;
@@ -35,12 +35,12 @@ public class AmountFunction implements LootFunction {
* Applies the function to an ItemStack. * Applies the function to an ItemStack.
* *
* @param original The ItemStack on which to apply the function. * @param original The ItemStack on which to apply the function.
* @param r The Random instance to use. * @param r The RandomGenerator instance to use.
* *
* @return - ItemStack - The mutated ItemStack. * @return - ItemStack - The mutated ItemStack.
*/ */
@Override @Override
public ItemStack apply(ItemStack original, Random r) { public ItemStack apply(ItemStack original, RandomGenerator r) {
original.setAmount(r.nextInt(max - min + 1) + min); original.setAmount(r.nextInt(max - min + 1) + min);
return original; return original;
} }
@@ -7,7 +7,7 @@
package com.dfsek.terra.addons.structure.structures.loot.functions; package com.dfsek.terra.addons.structure.structures.loot.functions;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.inventory.ItemStack; import com.dfsek.terra.api.inventory.ItemStack;
import com.dfsek.terra.api.inventory.item.Damageable; import com.dfsek.terra.api.inventory.item.Damageable;
@@ -36,12 +36,12 @@ public class DamageFunction implements LootFunction {
* Applies the function to an ItemStack. * Applies the function to an ItemStack.
* *
* @param original The ItemStack on which to apply the function. * @param original The ItemStack on which to apply the function.
* @param r The Random instance to use. * @param r The RandomGenerator instance to use.
* *
* @return - ItemStack - The mutated ItemStack. * @return - ItemStack - The mutated ItemStack.
*/ */
@Override @Override
public ItemStack apply(ItemStack original, Random r) { public ItemStack apply(ItemStack original, RandomGenerator r) {
if(original == null) return null; if(original == null) return null;
if(!original.isDamageable()) return original; if(!original.isDamageable()) return original;
ItemMeta meta = original.getItemMeta(); ItemMeta meta = original.getItemMeta();
@@ -14,7 +14,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.inventory.ItemStack; import com.dfsek.terra.api.inventory.ItemStack;
@@ -41,12 +41,12 @@ public class EnchantFunction implements LootFunction {
* Applies the function to an ItemStack. * Applies the function to an ItemStack.
* *
* @param original The ItemStack on which to apply the function. * @param original The ItemStack on which to apply the function.
* @param r The Random instance to use. * @param r The RandomGenerator instance to use.
* *
* @return - ItemStack - The mutated ItemStack. * @return - ItemStack - The mutated ItemStack.
*/ */
@Override @Override
public ItemStack apply(ItemStack original, Random r) { public ItemStack apply(ItemStack original, RandomGenerator r) {
if(original.getItemMeta() == null) return original; if(original.getItemMeta() == null) return original;
double enchant = (r.nextDouble() * (max - min)) + min; double enchant = (r.nextDouble() * (max - min)) + min;
@@ -8,7 +8,7 @@
package com.dfsek.terra.addons.structure.structures.loot.functions; package com.dfsek.terra.addons.structure.structures.loot.functions;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.inventory.ItemStack; import com.dfsek.terra.api.inventory.ItemStack;
@@ -21,9 +21,9 @@ public interface LootFunction {
* Applies the function to an ItemStack. * Applies the function to an ItemStack.
* *
* @param original The ItemStack on which to apply the function. * @param original The ItemStack on which to apply the function.
* @param r The Random instance to use. * @param r The RandomGenerator instance to use.
* *
* @return - ItemStack - The mutated ItemStack. * @return - ItemStack - The mutated ItemStack.
*/ */
ItemStack apply(ItemStack original, Random r); ItemStack apply(ItemStack original, RandomGenerator r);
} }
@@ -8,7 +8,8 @@
package com.dfsek.terra.addons.generation.feature; package com.dfsek.terra.addons.generation.feature;
import java.util.Collections; import java.util.Collections;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.addons.generation.feature.config.BiomeFeatures; import com.dfsek.terra.addons.generation.feature.config.BiomeFeatures;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
@@ -72,7 +73,9 @@ public class FeatureGenerationStage implements GenerationStage, StringIdentifiab
.forEach(y -> feature.getStructure(world, x, y, z) .forEach(y -> feature.getStructure(world, x, y, z)
.generate(Vector3Int.of(x, y, z), .generate(Vector3Int.of(x, y, z),
world, world,
new Random(coordinateSeed * 31 + y), RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of(
"Xoroshiro128PlusPlus")
.create(coordinateSeed * 31 + y),
Rotation.NONE) Rotation.NONE)
); );
} }
@@ -11,12 +11,16 @@ import com.dfsek.tectonic.yaml.YamlConfiguration;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.Files;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.event.events.config.ConfigurationDiscoveryEvent; import com.dfsek.terra.api.event.events.config.ConfigurationDiscoveryEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject; import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.util.FileUtil;
public class YamlAddon implements AddonInitializer { public class YamlAddon implements AddonInitializer {
@@ -33,10 +37,21 @@ public class YamlAddon implements AddonInitializer {
platform.getEventManager() platform.getEventManager()
.getHandler(FunctionalEventHandler.class) .getHandler(FunctionalEventHandler.class)
.register(addon, ConfigurationDiscoveryEvent.class) .register(addon, ConfigurationDiscoveryEvent.class)
.then(event -> event.getLoader().open("", ".yml").thenEntries(entries -> entries.forEach(entry -> { .then(event -> {
LOGGER.debug("Discovered config {}", entry.getKey()); try {
event.register(entry.getKey(), new YamlConfiguration(entry.getValue(), entry.getKey())); FileUtil.filesWithExtension(event.getPack().getRootPath(), ".yml")
})).close()) .forEach((key, value) -> {
LOGGER.debug("Discovered config {}", key);
try {
event.register(key, new YamlConfiguration(Files.newInputStream(value), key));
} catch(IOException e) {
throw new RuntimeException("Failed to load config " + key, e);
}
});
} catch(IOException e) {
throw new RuntimeException("Error occurred while reading config pack files", e);
}
})
.failThrough(); .failThrough();
} }
} }
@@ -60,8 +60,8 @@ public class ImageLibraryAddon implements AddonInitializer {
.then(event -> { .then(event -> {
ConfigPack pack = event.getPack(); ConfigPack pack = event.getPack();
CheckedRegistry<Supplier<ObjectTemplate<Image>>> imageRegistry = pack.getOrCreateRegistry(IMAGE_REGISTRY_KEY); CheckedRegistry<Supplier<ObjectTemplate<Image>>> imageRegistry = pack.getOrCreateRegistry(IMAGE_REGISTRY_KEY);
imageRegistry.register(addon.key("BITMAP"), () -> new ImageTemplate(pack.getLoader(), pack)); imageRegistry.register(addon.key("BITMAP"), () -> new ImageTemplate(pack));
imageRegistry.register(addon.key("STITCHED_BITMAP"), () -> new StitchedImageTemplate(pack.getLoader(), pack)); imageRegistry.register(addon.key("STITCHED_BITMAP"), () -> new StitchedImageTemplate(pack));
}) })
.then(event -> { .then(event -> {
event.getPack() event.getPack()
@@ -4,8 +4,10 @@ import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.dfsek.terra.addons.image.config.ImageLibraryPackConfigTemplate; import com.dfsek.terra.addons.image.config.ImageLibraryPackConfigTemplate;
@@ -13,7 +15,6 @@ import com.dfsek.terra.addons.image.image.BufferedImageWrapper;
import com.dfsek.terra.addons.image.image.Image; import com.dfsek.terra.addons.image.image.Image;
import com.dfsek.terra.addons.image.image.SuppliedImage; import com.dfsek.terra.addons.image.image.SuppliedImage;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.properties.Properties; import com.dfsek.terra.api.properties.Properties;
import com.dfsek.terra.api.util.generic.Lazy; import com.dfsek.terra.api.util.generic.Lazy;
@@ -22,13 +23,13 @@ import com.dfsek.terra.api.util.generic.Lazy;
* Cache prevents configs from loading the same image multiple times into memory * Cache prevents configs from loading the same image multiple times into memory
*/ */
record ImageCache(LoadingCache<String, Image> cache) implements Properties { record ImageCache(LoadingCache<String, Image> cache) implements Properties {
public static Image load(String path, ConfigPack pack, Loader files) throws IOException { public static Image load(String path, ConfigPack pack) throws IOException {
ImageLibraryPackConfigTemplate config = pack.getContext().get(ImageLibraryPackConfigTemplate.class); ImageLibraryPackConfigTemplate config = pack.getContext().get(ImageLibraryPackConfigTemplate.class);
ImageCache images; ImageCache images;
if(!pack.getContext().has(ImageCache.class)) { if(!pack.getContext().has(ImageCache.class)) {
var cacheBuilder = Caffeine.newBuilder(); var cacheBuilder = Caffeine.newBuilder();
if(config.unloadOnTimeout()) cacheBuilder.expireAfterAccess(config.getCacheTimeout(), TimeUnit.SECONDS); if(config.unloadOnTimeout()) cacheBuilder.expireAfterAccess(config.getCacheTimeout(), TimeUnit.SECONDS);
images = new ImageCache(cacheBuilder.build(s -> loadImage(s, files))); images = new ImageCache(cacheBuilder.build(s -> loadImage(s, pack.getRootPath())));
pack.getContext().put(images); pack.getContext().put(images);
} else images = pack.getContext().get(ImageCache.class); } else images = pack.getContext().get(ImageCache.class);
@@ -45,17 +46,8 @@ record ImageCache(LoadingCache<String, Image> cache) implements Properties {
return images.cache.get(path); return images.cache.get(path);
} }
private static Image loadImage(String path, Loader files) throws IOException { private static Image loadImage(String path, Path directory) throws IOException {
try { InputStream is = Files.newInputStream(directory.resolve(path));
return new BufferedImageWrapper(ImageIO.read(files.get(path))); return new BufferedImageWrapper(ImageIO.read(is));
} catch(IllegalArgumentException e) {
throw new IllegalArgumentException("Unable to load image (image might be too large?)", e);
} catch(IOException e) {
if(e instanceof FileNotFoundException) {
// Rethrow using nicer message
throw new IOException("Unable to load image: No such file or directory: " + path, e);
}
throw new IOException("Unable to load image", e);
}
} }
} }
@@ -7,25 +7,22 @@ import java.io.IOException;
import com.dfsek.terra.addons.image.image.Image; import com.dfsek.terra.addons.image.image.Image;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
public class ImageTemplate implements ObjectTemplate<Image> { public class ImageTemplate implements ObjectTemplate<Image> {
private final Loader files;
private final ConfigPack pack; private final ConfigPack pack;
@Value("path") @Value("path")
private String path; private String path;
public ImageTemplate(Loader files, ConfigPack pack) { public ImageTemplate(ConfigPack pack) {
this.files = files;
this.pack = pack; this.pack = pack;
} }
@Override @Override
public Image get() { public Image get() {
try { try {
return ImageCache.load(path, pack, files); return ImageCache.load(path, pack);
} catch(IOException e) { } catch(IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -11,12 +11,10 @@ import java.io.IOException;
import com.dfsek.terra.addons.image.image.Image; import com.dfsek.terra.addons.image.image.Image;
import com.dfsek.terra.addons.image.image.StitchedImage; import com.dfsek.terra.addons.image.image.StitchedImage;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
public class StitchedImageTemplate implements ObjectTemplate<Image>, ValidatedConfigTemplate { public class StitchedImageTemplate implements ObjectTemplate<Image>, ValidatedConfigTemplate {
private final Loader files;
private final ConfigPack pack; private final ConfigPack pack;
@Value("path-format") @Value("path-format")
private String path; private String path;
@@ -28,8 +26,7 @@ public class StitchedImageTemplate implements ObjectTemplate<Image>, ValidatedCo
@Default @Default
private boolean zeroIndexed = false; private boolean zeroIndexed = false;
public StitchedImageTemplate(Loader files, ConfigPack pack) { public StitchedImageTemplate(ConfigPack pack) {
this.files = files;
this.pack = pack; this.pack = pack;
} }
@@ -39,7 +36,7 @@ public class StitchedImageTemplate implements ObjectTemplate<Image>, ValidatedCo
for(int i = 0; i < rows; i++) { for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) { for(int j = 0; j < cols; j++) {
try { try {
grid[i][j] = ImageCache.load(getFormattedPath(i, j), pack, files); grid[i][j] = ImageCache.load(getFormattedPath(i, j), pack);
} catch(IOException e) { } catch(IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -1,6 +1,6 @@
package com.dfsek.terra.addons.palette.shortcut.block; package com.dfsek.terra.addons.palette.shortcut.block;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.structure.Structure; import com.dfsek.terra.api.structure.Structure;
@@ -17,7 +17,7 @@ public class SingletonStructure implements Structure {
} }
@Override @Override
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
world.setBlockState(location, blockState); world.setBlockState(location, blockState);
return true; return true;
} }
@@ -1,7 +1,5 @@
package com.dfsek.terra.addons.structure.mutator; package com.dfsek.terra.addons.structure.mutator;
import java.util.Random;
import com.dfsek.terra.api.registry.key.Keyed; import com.dfsek.terra.api.registry.key.Keyed;
import com.dfsek.terra.api.registry.key.RegistryKey; import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.structure.Structure; import com.dfsek.terra.api.structure.Structure;
@@ -11,6 +9,8 @@ import com.dfsek.terra.api.world.WritableWorld;
import com.dfsek.terra.api.world.util.ReadInterceptor; import com.dfsek.terra.api.world.util.ReadInterceptor;
import com.dfsek.terra.api.world.util.WriteInterceptor; import com.dfsek.terra.api.world.util.WriteInterceptor;
import java.util.random.RandomGenerator;
public class MutatedStructure implements Structure, Keyed<MutatedStructure> { public class MutatedStructure implements Structure, Keyed<MutatedStructure> {
private final RegistryKey key; private final RegistryKey key;
@@ -32,7 +32,7 @@ public class MutatedStructure implements Structure, Keyed<MutatedStructure> {
} }
@Override @Override
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
return base.generate(location, return base.generate(location,
world world
.buffer() .buffer()
@@ -16,6 +16,7 @@ import net.querz.nbt.tag.Tag;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PushbackInputStream; import java.io.PushbackInputStream;
import java.nio.file.Files;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -29,7 +30,7 @@ import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject; import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.Structure; import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.util.StringUtil; import com.dfsek.terra.api.util.FileUtil;
import com.dfsek.terra.api.util.vector.Vector3Int; import com.dfsek.terra.api.util.vector.Vector3Int;
@@ -58,13 +59,21 @@ public class SpongeSchematicAddon implements AddonInitializer {
.register(addon, ConfigPackPreLoadEvent.class) .register(addon, ConfigPackPreLoadEvent.class)
.then(event -> { .then(event -> {
CheckedRegistry<Structure> structureRegistry = event.getPack().getOrCreateRegistry(Structure.class); CheckedRegistry<Structure> structureRegistry = event.getPack().getOrCreateRegistry(Structure.class);
event.getPack() try {
.getLoader() FileUtil.filesWithExtension(event.getPack().getRootPath(), ".schem")
.open("", ".schem") .entrySet()
.thenEntries(entries -> entries
.stream() .stream()
.map(entry -> convert(entry.getValue(), StringUtil.fileName(entry.getKey()))) .map(entry -> {
.forEach(structureRegistry::register)).close(); try {
return convert(Files.newInputStream(entry.getValue()), FileUtil.fileName(entry.getKey()));
} catch(IOException e) {
throw new RuntimeException("Failed to load config " + entry.getKey(), e);
}
})
.forEach(structureRegistry::register);
} catch(IOException e) {
throw new RuntimeException("Error occurred while reading config pack files", e);
}
}) })
.failThrough(); .failThrough();
} }
@@ -7,7 +7,7 @@
package com.dfsek.terra.addons.sponge; package com.dfsek.terra.addons.sponge;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.registry.key.Keyed; import com.dfsek.terra.api.registry.key.Keyed;
@@ -36,7 +36,7 @@ public class SpongeStructure implements Structure, Keyed<SpongeStructure> {
} }
@Override @Override
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
int bX = location.getX(); int bX = location.getX();
int bY = location.getY(); int bY = location.getY();
int bZ = location.getZ(); int bZ = location.getZ();
@@ -7,6 +7,9 @@
package com.dfsek.terra.addons.terrascript; package com.dfsek.terra.addons.terrascript;
import java.io.IOException;
import java.nio.file.Files;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
@@ -19,7 +22,7 @@ import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.LootTable; import com.dfsek.terra.api.structure.LootTable;
import com.dfsek.terra.api.structure.Structure; import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.util.StringUtil; import com.dfsek.terra.api.util.FileUtil;
public class TerraScriptAddon implements AddonInitializer { public class TerraScriptAddon implements AddonInitializer {
@@ -37,26 +40,28 @@ public class TerraScriptAddon implements AddonInitializer {
.then(event -> { .then(event -> {
CheckedRegistry<Structure> structureRegistry = event.getPack().getOrCreateRegistry(Structure.class); CheckedRegistry<Structure> structureRegistry = event.getPack().getOrCreateRegistry(Structure.class);
CheckedRegistry<LootTable> lootRegistry = event.getPack().getOrCreateRegistry(LootTable.class); CheckedRegistry<LootTable> lootRegistry = event.getPack().getOrCreateRegistry(LootTable.class);
event.getPack().getLoader().open("", ".tesf").thenEntries( try {
entries -> FileUtil.filesWithExtension(event.getPack().getRootPath(), ".tesf")
entries.stream() .entrySet()
.parallel() .stream()
.map(entry -> { .parallel()
try { .map(entry -> {
String id = StringUtil.fileName(entry.getKey()); try {
return new StructureScript(entry.getValue(), String id = FileUtil.fileName(entry.getKey());
addon.key(id), return new StructureScript(Files.newInputStream(entry.getValue()),
platform, addon.key(id),
structureRegistry, platform,
lootRegistry, structureRegistry,
event.getPack().getOrCreateRegistry(FunctionBuilder.class)); lootRegistry,
} catch(ParseException e) { event.getPack().getOrCreateRegistry(FunctionBuilder.class));
throw new RuntimeException("Failed to load script \"" + entry.getKey() + "\"", e); } catch(ParseException | IOException e) {
} throw new RuntimeException("Failed to load script \"" + entry.getKey() + "\"", e);
}) }
.toList() })
.forEach(structureRegistry::register)) .forEach(structureRegistry::register);
.close(); } catch(IOException e) {
throw new RuntimeException("Error occurred while reading config pack files", e);
}
}) })
.priority(100) .priority(100)
.failThrough(); .failThrough();
@@ -14,7 +14,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.addons.terrascript.parser.Parser; import com.dfsek.terra.addons.terrascript.parser.Parser;
import com.dfsek.terra.addons.terrascript.parser.lang.Executable; import com.dfsek.terra.addons.terrascript.parser.lang.Executable;
@@ -131,14 +131,14 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
@Override @Override
@SuppressWarnings("try") @SuppressWarnings("try")
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation) {
platform.getProfiler().push(profile); platform.getProfiler().push(profile);
boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, 0)); boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, 0));
platform.getProfiler().pop(profile); platform.getProfiler().pop(profile);
return result; return result;
} }
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation, int recursions) { public boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation, int recursions) {
platform.getProfiler().push(profile); platform.getProfiler().push(profile);
boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, recursions)); boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, recursions));
platform.getProfiler().pop(profile); platform.getProfiler().pop(profile);
@@ -9,7 +9,7 @@ package com.dfsek.terra.addons.terrascript.script;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
import com.dfsek.terra.api.util.Rotation; import com.dfsek.terra.api.util.Rotation;
@@ -20,14 +20,14 @@ import com.dfsek.terra.api.world.WritableWorld;
public class TerraImplementationArguments implements ImplementationArguments { public class TerraImplementationArguments implements ImplementationArguments {
private final Rotation rotation; private final Rotation rotation;
private final Random random; private final RandomGenerator random;
private final WritableWorld world; private final WritableWorld world;
private final Map<Vector3, String> marks = new HashMap<>(); private final Map<Vector3, String> marks = new HashMap<>();
private final int recursions; private final int recursions;
private final Vector3Int origin; private final Vector3Int origin;
private boolean waterlog = false; private boolean waterlog = false;
public TerraImplementationArguments(Vector3Int origin, Rotation rotation, Random random, WritableWorld world, int recursions) { public TerraImplementationArguments(Vector3Int origin, Rotation rotation, RandomGenerator random, WritableWorld world, int recursions) {
this.rotation = rotation; this.rotation = rotation;
this.random = random; this.random = random;
this.world = world; this.world = world;
@@ -39,7 +39,7 @@ public class TerraImplementationArguments implements ImplementationArguments {
return recursions; return recursions;
} }
public Random getRandom() { public RandomGenerator getRandom() {
return random; return random;
} }
@@ -10,8 +10,8 @@ package com.dfsek.terra.addons.terrascript.script.functions;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
@@ -32,7 +32,7 @@ public class BlockFunction implements Function<Void> {
protected final Returnable<Number> x, y, z; protected final Returnable<Number> x, y, z;
protected final Returnable<String> blockData; protected final Returnable<String> blockData;
protected final Platform platform; protected final Platform platform;
private final Map<String, BlockState> data = new HashMap<>(); private final Map<String, BlockState> data = new ConcurrentHashMap<>();
private final Returnable<Boolean> overwrite; private final Returnable<Boolean> overwrite;
private final Returnable<Boolean> physics; private final Returnable<Boolean> physics;
private final Position position; private final Position position;
@@ -10,7 +10,8 @@ package com.dfsek.terra.addons.terrascript.script.functions;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
@@ -84,7 +85,8 @@ public class LootFunction implements Function<Void> {
if(event.isCancelled()) return; if(event.isCancelled()) return;
event.getTable().fillInventory(container.getInventory(), event.getTable().fillInventory(container.getInventory(),
new Random(apply.hashCode())); RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of(
"Xoroshiro128PlusPlus").create(apply.hashCode()));
data.update(false); data.update(false);
} catch(Exception e) { } catch(Exception e) {
LOGGER.error("Could not apply loot at {}", apply, e); LOGGER.error("Could not apply loot at {}", apply, e);
+1 -1
View File
@@ -6,6 +6,6 @@ dependencies {
api("com.dfsek.tectonic", "common", Versions.Libraries.tectonic) api("com.dfsek.tectonic", "common", Versions.Libraries.tectonic)
api("com.github.ben-manes.caffeine:caffeine:3.1.0") api("com.github.ben-manes.caffeine", "caffeine", Versions.Libraries.caffeine)
} }
@@ -14,6 +14,7 @@ import java.io.File;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.config.PluginConfig; import com.dfsek.terra.api.config.PluginConfig;
import com.dfsek.terra.api.event.EventManager; import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.handle.ItemHandle; import com.dfsek.terra.api.handle.ItemHandle;
@@ -61,6 +62,10 @@ public interface Platform extends LoaderRegistrar {
@Contract(pure = true) @Contract(pure = true)
CheckedRegistry<ConfigPack> getConfigRegistry(); CheckedRegistry<ConfigPack> getConfigRegistry();
@NotNull
@Contract(pure = true)
CheckedRegistry<MetaPack> getMetaConfigRegistry();
@NotNull @NotNull
@Contract(pure = true) @Contract(pure = true)
Registry<BaseAddon> getAddons(); Registry<BaseAddon> getAddons();
@@ -10,6 +10,7 @@ package com.dfsek.terra.api.config;
import ca.solostudios.strata.version.Version; import ca.solostudios.strata.version.Version;
import ca.solostudios.strata.version.VersionRange; import ca.solostudios.strata.version.VersionRange;
import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -43,7 +44,7 @@ public interface ConfigPack extends LoaderRegistrar,
List<GenerationStage> getStages(); List<GenerationStage> getStages();
Loader getLoader(); Path getRootPath();
String getAuthor(); String getAuthor();
@@ -1,47 +0,0 @@
/*
* Copyright (c) 2020-2023 Polyhedral Development
*
* The Terra API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the common/api directory.
*/
package com.dfsek.terra.api.config;
import com.dfsek.tectonic.api.exception.ConfigException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public interface Loader {
Loader thenNames(Consumer<List<String>> consumer) throws ConfigException;
Loader thenEntries(Consumer<Set<Map.Entry<String, InputStream>>> consumer) throws ConfigException;
/**
* Get a single file from this Loader.
*
* @param singleFile File to get
*
* @return InputStream from file.
*/
InputStream get(String singleFile) throws IOException;
/**
* Open a subdirectory.
*
* @param directory Directory to open
* @param extension File extension
*/
Loader open(String directory, String extension);
/**
* Close all InputStreams opened.
*/
Loader close();
}
@@ -0,0 +1,27 @@
package com.dfsek.terra.api.config;
import ca.solostudios.strata.version.Version;
import java.util.Map;
import com.dfsek.terra.api.properties.PropertyHolder;
import com.dfsek.terra.api.registry.key.Keyed;
import com.dfsek.terra.api.registry.meta.CheckedRegistryHolder;
import com.dfsek.terra.api.registry.meta.RegistryProvider;
import com.dfsek.terra.api.tectonic.ConfigLoadingDelegate;
import com.dfsek.terra.api.tectonic.LoaderRegistrar;
public interface MetaPack extends LoaderRegistrar,
ConfigLoadingDelegate,
CheckedRegistryHolder,
RegistryProvider,
Keyed<MetaPack>,
PropertyHolder {
Map<String, ConfigPack> packs();
String getAuthor();
Version getVersion();
}
@@ -12,7 +12,6 @@ import com.dfsek.tectonic.api.config.Configuration;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.event.events.FailThroughEvent; import com.dfsek.terra.api.event.events.FailThroughEvent;
import com.dfsek.terra.api.event.events.PackEvent; import com.dfsek.terra.api.event.events.PackEvent;
@@ -25,13 +24,11 @@ import com.dfsek.terra.api.event.events.PackEvent;
*/ */
public class ConfigurationDiscoveryEvent implements PackEvent, FailThroughEvent { public class ConfigurationDiscoveryEvent implements PackEvent, FailThroughEvent {
private final ConfigPack pack; private final ConfigPack pack;
private final Loader loader;
private final BiConsumer<String, Configuration> consumer; private final BiConsumer<String, Configuration> consumer;
public ConfigurationDiscoveryEvent(ConfigPack pack, Loader loader, BiConsumer<String, Configuration> consumer) { public ConfigurationDiscoveryEvent(ConfigPack pack, BiConsumer<String, Configuration> consumer) {
this.pack = pack; this.pack = pack;
this.loader = loader;
this.consumer = consumer; this.consumer = consumer;
} }
@@ -43,8 +40,4 @@ public class ConfigurationDiscoveryEvent implements PackEvent, FailThroughEvent
public ConfigPack getPack() { public ConfigPack getPack() {
return pack; return pack;
} }
public Loader getLoader() {
return loader;
}
} }
@@ -10,7 +10,7 @@ package com.dfsek.terra.api.structure;
import org.jetbrains.annotations.ApiStatus.Experimental; import org.jetbrains.annotations.ApiStatus.Experimental;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.inventory.Inventory; import com.dfsek.terra.api.inventory.Inventory;
import com.dfsek.terra.api.inventory.ItemStack; import com.dfsek.terra.api.inventory.ItemStack;
@@ -22,16 +22,16 @@ public interface LootTable {
* Fills an Inventory with loot. * Fills an Inventory with loot.
* *
* @param i The Inventory to fill. * @param i The Inventory to fill.
* @param r The The Random instance to use. * @param r The The RandomGenerator instance to use.
*/ */
void fillInventory(Inventory i, Random r); void fillInventory(Inventory i, RandomGenerator r);
/** /**
* Fetches a list of ItemStacks from the loot table using the given Random instance. * Fetches a list of ItemStacks from the loot table using the given RandomGenerator instance.
* *
* @param r The Random instance to use. * @param r The RandomGenerator instance to use.
* *
* @return List&lt;ItemStack&gt; - The list of loot fetched. * @return List&lt;ItemStack&gt; - The list of loot fetched.
*/ */
List<ItemStack> getLoot(Random r); List<ItemStack> getLoot(RandomGenerator r);
} }
@@ -7,7 +7,7 @@
package com.dfsek.terra.api.structure; package com.dfsek.terra.api.structure;
import java.util.Random; import java.util.random.RandomGenerator;
import com.dfsek.terra.api.util.Rotation; import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.vector.Vector3Int; import com.dfsek.terra.api.util.vector.Vector3Int;
@@ -15,5 +15,5 @@ import com.dfsek.terra.api.world.WritableWorld;
public interface Structure { public interface Structure {
boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation); boolean generate(Vector3Int location, WritableWorld world, RandomGenerator random, Rotation rotation);
} }
@@ -10,7 +10,7 @@ package com.dfsek.terra.api.util;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Iterator; import java.util.Iterator;
import java.util.Random; import java.util.random.RandomGenerator;
public class ConstantRange implements Range { public class ConstantRange implements Range {
@@ -36,7 +36,7 @@ public class ConstantRange implements Range {
} }
@Override @Override
public int get(Random r) { public int get(RandomGenerator r) {
return r.nextInt(min, max); return r.nextInt(min, max);
} }
@@ -0,0 +1,38 @@
package com.dfsek.terra.api.util;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.function.Function.identity;
public class FileUtil {
public static Map<String, Path> filesWithExtension(Path start, String... extensions) throws IOException {
if(Files.notExists(start) || !Files.isDirectory(start)) return Collections.emptyMap();
try(Stream<Path> paths = Files.walk(start)) {
return paths
.filter(Files::isRegularFile)
.filter(p -> Arrays.stream(extensions).anyMatch(e -> p.getFileName().toString().endsWith(e)))
.collect(Collectors.toMap(p -> start.relativize(p).toString(), identity()));
}
}
public static String fileName(String path) {
if(path.contains(File.separator)) {
return path.substring(path.lastIndexOf(File.separatorChar) + 1, path.lastIndexOf('.'));
} else if(path.contains("/")) {
return path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf('.'));
} else if(path.contains(".")) {
return path.substring(0, path.lastIndexOf('.'));
} else {
return path;
}
}
}
@@ -7,18 +7,20 @@
package com.dfsek.terra.api.util; package com.dfsek.terra.api.util;
import java.util.Random; import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import com.dfsek.terra.api.world.chunk.Chunk; import com.dfsek.terra.api.world.chunk.Chunk;
public final class PopulationUtil { public final class PopulationUtil {
public static Random getRandom(Chunk c) { public static RandomGenerator getRandom(Chunk c) {
return getRandom(c, 0); return getRandom(c, 0);
} }
public static Random getRandom(Chunk c, long salt) { public static RandomGenerator getRandom(Chunk c, long salt) {
return new Random(getCarverChunkSeed(c.getX(), c.getZ(), c.getWorld().getSeed() + salt)); return RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(
getCarverChunkSeed(c.getX(), c.getZ(), c.getWorld().getSeed() + salt));
} }
/** /**
@@ -31,7 +33,7 @@ public final class PopulationUtil {
* @return long - The carver seed. * @return long - The carver seed.
*/ */
public static long getCarverChunkSeed(int chunkX, int chunkZ, long seed) { public static long getCarverChunkSeed(int chunkX, int chunkZ, long seed) {
Random r = new Random(seed); RandomGenerator r = RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(seed);
return chunkX * r.nextLong() ^ chunkZ * r.nextLong() ^ seed; return chunkX * r.nextLong() ^ chunkZ * r.nextLong() ^ seed;
} }
} }
@@ -10,8 +10,8 @@ package com.dfsek.terra.api.util;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Iterator; import java.util.Iterator;
import java.util.Random;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.random.RandomGenerator;
public interface Range extends Iterable<Integer> { public interface Range extends Iterable<Integer> {
@@ -19,7 +19,7 @@ public interface Range extends Iterable<Integer> {
Range reflect(int pt); Range reflect(int pt);
int get(Random r); int get(RandomGenerator r);
Range intersects(Range other); Range intersects(Range other);
@@ -1,25 +0,0 @@
/*
* Copyright (c) 2020-2023 Polyhedral Development
*
* The Terra API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the common/api directory.
*/
package com.dfsek.terra.api.util;
import java.io.File;
public class StringUtil {
public static String fileName(String path) {
if(path.contains(File.separator)) {
return path.substring(path.lastIndexOf(File.separatorChar) + 1, path.lastIndexOf('.'));
} else if(path.contains("/")) {
return path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf('.'));
} else if(path.contains(".")) {
return path.substring(0, path.lastIndexOf('.'));
} else {
return path;
}
}
}
@@ -15,9 +15,9 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.random.RandomGenerator;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil; import com.dfsek.terra.api.util.MathUtil;
@@ -43,7 +43,7 @@ public class ProbabilityCollection<E> implements Collection<E> {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public E get(Random r) { public E get(RandomGenerator r) {
if(array.length == 0) return null; if(array.length == 0) return null;
return (E) array[r.nextInt(array.length)]; return (E) array[r.nextInt(array.length)];
} }
@@ -197,7 +197,7 @@ public class ProbabilityCollection<E> implements Collection<E> {
} }
@Override @Override
public T get(Random r) { public T get(RandomGenerator r) {
return single; return single;
} }
@@ -51,6 +51,7 @@ import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.addon.bootstrap.BootstrapAddonClassLoader; import com.dfsek.terra.api.addon.bootstrap.BootstrapAddonClassLoader;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.config.PluginConfig; import com.dfsek.terra.api.config.PluginConfig;
import com.dfsek.terra.api.event.EventManager; import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent;
@@ -72,6 +73,8 @@ import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.LockedRegistryImpl; import com.dfsek.terra.registry.LockedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl; import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry; import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry.PackLoadFailuresException;
import com.dfsek.terra.registry.master.MetaConfigRegistry;
/** /**
@@ -85,9 +88,12 @@ public abstract class AbstractPlatform implements Platform {
private static final MutableBoolean LOADED = new MutableBoolean(false); private static final MutableBoolean LOADED = new MutableBoolean(false);
private final EventManager eventManager = new EventManagerImpl(); private final EventManager eventManager = new EventManagerImpl();
private final ConfigRegistry configRegistry = new ConfigRegistry(); private final ConfigRegistry configRegistry = new ConfigRegistry();
private final MetaConfigRegistry metaConfigRegistry = new MetaConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedConfigRegistry = new CheckedRegistryImpl<>(configRegistry); private final CheckedRegistry<ConfigPack> checkedConfigRegistry = new CheckedRegistryImpl<>(configRegistry);
private final CheckedRegistry<MetaPack> checkedMetaConfigRegistry = new CheckedRegistryImpl<>(metaConfigRegistry);
private final Profiler profiler = new ProfilerImpl(); private final Profiler profiler = new ProfilerImpl();
private final GenericLoaders loaders = new GenericLoaders(this); private final GenericLoaders loaders = new GenericLoaders(this);
@@ -102,6 +108,10 @@ public abstract class AbstractPlatform implements Platform {
return configRegistry; return configRegistry;
} }
public MetaConfigRegistry getRawMetaConfigRegistry() {
return metaConfigRegistry;
}
protected Iterable<BaseAddon> platformAddon() { protected Iterable<BaseAddon> platformAddon() {
return Collections.emptySet(); return Collections.emptySet();
} }
@@ -147,11 +157,12 @@ public abstract class AbstractPlatform implements Platform {
eventManager.getHandler(FunctionalEventHandler.class) eventManager.getHandler(FunctionalEventHandler.class)
.register(internalAddon, PlatformInitializationEvent.class) .register(internalAddon, PlatformInitializationEvent.class)
.then(event -> { .then(event -> loadConfigPacks())
logger.info("Loading config packs..."); .global();
configRegistry.loadAll(this);
logger.info("Loaded packs."); eventManager.getHandler(FunctionalEventHandler.class)
}) .register(internalAddon, PlatformInitializationEvent.class)
.then(event -> loadMetaConfigPacks())
.global(); .global();
@@ -159,6 +170,38 @@ public abstract class AbstractPlatform implements Platform {
logger.info("Finished initialization."); logger.info("Finished initialization.");
} }
protected boolean loadConfigPacks() {
logger.info("Loading config packs...");
ConfigRegistry configRegistry = getRawConfigRegistry();
configRegistry.clear();
try {
configRegistry.loadAll(this);
} catch(IOException e) {
logger.error("Failed to load config packs", e);
return false;
} catch(PackLoadFailuresException e) {
e.getExceptions().forEach(ex -> logger.error("Failed to load config pack", ex));
return false;
}
return true;
}
protected boolean loadMetaConfigPacks() {
logger.info("Loading meta config packs...");
MetaConfigRegistry metaConfigRegistry = getRawMetaConfigRegistry();
metaConfigRegistry.clear();
try {
metaConfigRegistry.loadAll(this, configRegistry);
} catch(IOException e) {
logger.error("Failed to load meta config packs", e);
return false;
} catch(PackLoadFailuresException e) {
e.getExceptions().forEach(ex -> logger.error("Failed to meta load config pack", ex));
return false;
}
return true;
}
protected InternalAddon loadAddons() { protected InternalAddon loadAddons() {
List<BaseAddon> addonList = new ArrayList<>(); List<BaseAddon> addonList = new ArrayList<>();
@@ -325,6 +368,12 @@ public abstract class AbstractPlatform implements Platform {
return checkedConfigRegistry; return checkedConfigRegistry;
} }
@Override
public @NotNull CheckedRegistry<MetaPack> getMetaConfigRegistry() {
return checkedMetaConfigRegistry;
}
@Override @Override
public @NotNull Registry<BaseAddon> getAddons() { public @NotNull Registry<BaseAddon> getAddons() {
return lockedAddonRegistry; return lockedAddonRegistry;
@@ -1,66 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.config.fileloaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
/**
* Load all {@code *.yml} files from a {@link java.nio.file.Path}.
*/
public class FolderLoader extends LoaderImpl {
private static final Logger logger = LoggerFactory.getLogger(FolderLoader.class);
private final Path path;
public FolderLoader(Path path) {
this.path = path;
}
@Override
public InputStream get(String singleFile) throws IOException {
return new FileInputStream(new File(path.toFile(), singleFile));
}
protected void load(String directory, String extension) {
File newPath = new File(path.toFile(), directory);
newPath.mkdirs();
try(Stream<Path> paths = Files.walk(newPath.toPath())) {
paths.filter(Files::isRegularFile).filter(file -> file.toString().toLowerCase().endsWith(extension)).forEach(file -> {
try {
String rel = newPath.toPath().relativize(file).toString();
streams.put(rel, new FileInputStream(file.toFile()));
} catch(FileNotFoundException e) {
logger.error("Could not find file to load", e);
}
});
} catch(IOException e) {
logger.error("Error while loading files", e);
}
}
}
@@ -1,83 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.config.fileloaders;
import com.dfsek.tectonic.api.exception.ConfigException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import com.dfsek.terra.api.config.Loader;
public abstract class LoaderImpl implements Loader {
private static final Logger logger = LoggerFactory.getLogger(LoaderImpl.class);
protected final Map<String, InputStream> streams = new HashMap<>();
@Override
public Loader thenNames(Consumer<List<String>> consumer) throws ConfigException {
consumer.accept(new ArrayList<>(streams.keySet()));
return this;
}
@Override
public Loader thenEntries(Consumer<Set<Map.Entry<String, InputStream>>> consumer) throws ConfigException {
consumer.accept(streams.entrySet());
return this;
}
/**
* Open a subdirectory.
*
* @param directory Directory to open
* @param extension File extension
*/
@Override
public LoaderImpl open(String directory, String extension) {
if(!streams.isEmpty()) throw new IllegalStateException("Attempted to load new directory before closing existing InputStreams");
load(directory, extension);
return this;
}
/**
* Close all InputStreams opened.
*/
@Override
public Loader close() {
streams.forEach((name, input) -> {
try {
input.close();
} catch(IOException e) {
logger.error("Error occurred while loading", e);
}
});
streams.clear();
return this;
}
protected abstract void load(String directory, String extension);
}
@@ -1,63 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.config.fileloaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ZIPLoader extends LoaderImpl {
private static final Logger logger = LoggerFactory.getLogger(ZIPLoader.class);
private final ZipFile file;
public ZIPLoader(ZipFile file) {
this.file = file;
}
@Override
public InputStream get(String singleFile) throws IOException {
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(!entry.isDirectory() && entry.getName().equals(singleFile)) return file.getInputStream(entry);
}
throw new IllegalArgumentException("No such file: " + singleFile);
}
protected void load(String directory, String extension) {
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(!entry.isDirectory() && entry.getName().startsWith(directory) && entry.getName().endsWith(extension)) {
try {
String rel = entry.getName().substring(directory.length());
streams.put(rel, file.getInputStream(entry));
} catch(IOException e) {
logger.error("Error while loading file from zip", e);
}
}
}
}
}
@@ -27,10 +27,10 @@ import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.AnnotatedType; import java.lang.reflect.AnnotatedType;
import java.nio.file.Files;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.properties.Properties; import com.dfsek.terra.api.properties.Properties;
@@ -39,12 +39,10 @@ import com.dfsek.terra.api.properties.Properties;
*/ */
@Deprecated @Deprecated
public class BufferedImageLoader implements TypeLoader<BufferedImage> { public class BufferedImageLoader implements TypeLoader<BufferedImage> {
private final Loader files;
private final ConfigPack pack; private final ConfigPack pack;
public BufferedImageLoader(Loader files, ConfigPack pack) { public BufferedImageLoader(ConfigPack pack) {
this.files = files;
this.pack = pack; this.pack = pack;
if(!pack.getContext().has(ImageCache.class)) if(!pack.getContext().has(ImageCache.class))
pack.getContext().put(new ImageCache(new ConcurrentHashMap<>())); pack.getContext().put(new ImageCache(new ConcurrentHashMap<>()));
@@ -55,7 +53,7 @@ public class BufferedImageLoader implements TypeLoader<BufferedImage> {
throws LoadException { throws LoadException {
return pack.getContext().get(ImageCache.class).map.computeIfAbsent((String) c, s -> { return pack.getContext().get(ImageCache.class).map.computeIfAbsent((String) c, s -> {
try { try {
return ImageIO.read(files.get(s)); return ImageIO.read(Files.newInputStream(pack.getRootPath().resolve(s)));
} catch(IOException e) { } catch(IOException e) {
throw new LoadException("Unable to load image", e, depthTracker); throw new LoadException("Unable to load image", e, depthTracker);
} }
@@ -26,13 +26,37 @@ import com.dfsek.tectonic.api.loader.AbstractConfigLoader;
import com.dfsek.tectonic.api.loader.ConfigLoader; import com.dfsek.tectonic.api.loader.ConfigLoader;
import com.dfsek.tectonic.api.loader.type.TypeLoader; import com.dfsek.tectonic.api.loader.type.TypeLoader;
import com.dfsek.tectonic.yaml.YamlConfiguration; import com.dfsek.tectonic.yaml.YamlConfiguration;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.config.ConfigFactory; import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType; import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.event.events.config.ConfigurationDiscoveryEvent; import com.dfsek.terra.api.event.events.config.ConfigurationDiscoveryEvent;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
@@ -45,39 +69,24 @@ import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.Registry; import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey; import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.tectonic.ShortcutLoader; import com.dfsek.terra.api.tectonic.ShortcutLoader;
import com.dfsek.terra.api.util.generic.Construct;
import com.dfsek.terra.api.util.generic.pair.Pair; import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.api.util.reflection.ReflectionUtil; import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage; import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
import com.dfsek.terra.api.world.chunk.generation.util.provider.ChunkGeneratorProvider; import com.dfsek.terra.api.world.chunk.generation.util.provider.ChunkGeneratorProvider;
import com.dfsek.terra.config.fileloaders.FolderLoader;
import com.dfsek.terra.config.fileloaders.ZIPLoader;
import com.dfsek.terra.config.loaders.GenericTemplateSupplierLoader; import com.dfsek.terra.config.loaders.GenericTemplateSupplierLoader;
import com.dfsek.terra.config.loaders.config.BufferedImageLoader; import com.dfsek.terra.config.loaders.config.BufferedImageLoader;
import com.dfsek.terra.config.preprocessor.*; import com.dfsek.terra.config.preprocessor.MetaListLikePreprocessor;
import com.dfsek.terra.config.preprocessor.MetaMapPreprocessor;
import com.dfsek.terra.config.preprocessor.MetaNumberPreprocessor;
import com.dfsek.terra.config.preprocessor.MetaStringPreprocessor;
import com.dfsek.terra.config.preprocessor.MetaValuePreprocessor;
import com.dfsek.terra.config.prototype.ProtoConfig; import com.dfsek.terra.config.prototype.ProtoConfig;
import com.dfsek.terra.registry.CheckedRegistryImpl; import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl; import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.ShortcutHolder; import com.dfsek.terra.registry.ShortcutHolder;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/** /**
* Represents a Terra configuration pack. * Represents a Terra configuration pack.
@@ -92,7 +101,7 @@ public class ConfigPackImpl implements ConfigPack {
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader(); private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
private final ConfigLoader selfLoader = new ConfigLoader(); private final ConfigLoader selfLoader = new ConfigLoader();
private final Platform platform; private final Platform platform;
private final Loader loader; private final Path rootPath;
private final Map<BaseAddon, VersionRange> addons; private final Map<BaseAddon, VersionRange> addons;
@@ -106,40 +115,29 @@ public class ConfigPackImpl implements ConfigPack {
private final RegistryKey key; private final RegistryKey key;
public ConfigPackImpl(File folder, Platform platform) { @SuppressWarnings({ "rawtypes" })
this(new FolderLoader(folder.toPath()), Construct.construct(() -> { public ConfigPackImpl(Path path, Platform platform) throws IOException {
try {
return new YamlConfiguration(new FileInputStream(new File(folder, "pack.yml")), "pack.yml");
} catch(FileNotFoundException e) {
throw new UncheckedIOException("No pack.yml file found in " + folder.getAbsolutePath(), e);
}
}), platform);
}
public ConfigPackImpl(ZipFile file, Platform platform) {
this(new ZIPLoader(file), Construct.construct(() -> {
ZipEntry pack = null;
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(entry.getName().equals("pack.yml")) pack = entry;
}
if(pack == null) throw new IllegalArgumentException("No pack.yml file found in " + file.getName());
try {
return new YamlConfiguration(file.getInputStream(pack), "pack.yml");
} catch(IOException e) {
throw new UncheckedIOException("Unable to load pack.yml from ZIP file", e);
}
}), platform);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private ConfigPackImpl(Loader loader, Configuration packManifest, Platform platform) {
long start = System.nanoTime(); long start = System.nanoTime();
this.loader = loader; if(Files.notExists(path)) throw new FileNotFoundException("Could not load config pack, " + path + " does not exist");
if(Files.isDirectory(path)) {
this.rootPath = path;
} else if(Files.isRegularFile(path)) {
if(!path.getFileName().toString().endsWith(".zip")) {
throw new IOException("Could not load config pack, file " + path + " is not a zip");
}
FileSystem zipfs = FileSystems.newFileSystem(path);
this.rootPath = zipfs.getPath("/");
} else {
throw new IOException("Could not load config pack from " + path);
}
Path packManifestPath = rootPath.resolve("pack.yml");
if(Files.notExists(packManifestPath)) throw new IOException("No pack.yml found in " + path);
Configuration packManifest = new YamlConfiguration(Files.newInputStream(packManifestPath),
packManifestPath.getFileName().toString());
this.platform = platform; this.platform = platform;
this.configTypeRegistry = createConfigRegistry(); this.configTypeRegistry = createConfigRegistry();
@@ -223,7 +221,7 @@ public class ConfigPackImpl implements ConfigPack {
private Map<String, Configuration> discoverConfigurations() { private Map<String, Configuration> discoverConfigurations() {
Map<String, Configuration> configurations = new HashMap<>(); Map<String, Configuration> configurations = new HashMap<>();
platform.getEventManager().callEvent(new ConfigurationDiscoveryEvent(this, loader, platform.getEventManager().callEvent(new ConfigurationDiscoveryEvent(this,
(s, c) -> configurations.put(s.replace("\\", "/"), (s, c) -> configurations.put(s.replace("\\", "/"),
c))); // Create all the configs. c))); // Create all the configs.
return configurations; return configurations;
@@ -268,7 +266,7 @@ public class ConfigPackImpl implements ConfigPack {
@Override @Override
public void register(TypeRegistry registry) { public void register(TypeRegistry registry) {
registry.registerLoader(ConfigType.class, configTypeRegistry) registry.registerLoader(ConfigType.class, configTypeRegistry)
.registerLoader(BufferedImage.class, new BufferedImageLoader(loader, this)); .registerLoader(BufferedImage.class, new BufferedImageLoader(this));
registryMap.forEach(registry::registerLoader); registryMap.forEach(registry::registerLoader);
shortcuts.forEach(registry::registerLoader); // overwrite with delegated shortcuts if present shortcuts.forEach(registry::registerLoader); // overwrite with delegated shortcuts if present
} }
@@ -294,7 +292,6 @@ public class ConfigPackImpl implements ConfigPack {
return seededBiomeProvider; return seededBiomeProvider;
} }
@SuppressWarnings("unchecked")
@Override @Override
public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) { public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) {
return (CheckedRegistry<T>) registryMap.computeIfAbsent(typeKey.getType(), c -> { return (CheckedRegistry<T>) registryMap.computeIfAbsent(typeKey.getType(), c -> {
@@ -333,8 +330,8 @@ public class ConfigPackImpl implements ConfigPack {
} }
@Override @Override
public Loader getLoader() { public Path getRootPath() {
return loader; return rootPath;
} }
@Override @Override
@@ -347,7 +344,7 @@ public class ConfigPackImpl implements ConfigPack {
return template.getVersion(); return template.getVersion();
} }
@SuppressWarnings("unchecked,rawtypes") @SuppressWarnings("rawtypes")
@Override @Override
public <T> ConfigPack registerShortcut(TypeKey<T> clazz, String shortcut, ShortcutLoader<T> loader) { public <T> ConfigPack registerShortcut(TypeKey<T> clazz, String shortcut, ShortcutLoader<T> loader) {
ShortcutHolder<?> holder = shortcuts ShortcutHolder<?> holder = shortcuts
@@ -391,12 +388,10 @@ public class ConfigPackImpl implements ConfigPack {
} }
@Override @Override
@SuppressWarnings("unchecked")
public <T> CheckedRegistry<T> getRegistry(Type type) { public <T> CheckedRegistry<T> getRegistry(Type type) {
return (CheckedRegistry<T>) registryMap.get(type); return (CheckedRegistry<T>) registryMap.get(type);
} }
@SuppressWarnings("unchecked")
@Override @Override
public <T> CheckedRegistry<T> getCheckedRegistry(Type type) throws IllegalStateException { public <T> CheckedRegistry<T> getCheckedRegistry(Type type) throws IllegalStateException {
return (CheckedRegistry<T>) registryMap.get(type); return (CheckedRegistry<T>) registryMap.get(type);
@@ -0,0 +1,215 @@
package com.dfsek.terra.config.pack;
import ca.solostudios.strata.version.Version;
import com.dfsek.tectonic.api.TypeRegistry;
import com.dfsek.tectonic.api.config.Configuration;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.tectonic.api.loader.AbstractConfigLoader;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import com.dfsek.tectonic.api.loader.type.TypeLoader;
import com.dfsek.tectonic.yaml.YamlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.loaders.GenericTemplateSupplierLoader;
import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class MetaPackImpl implements MetaPack {
private static final Pattern PATTERN = Pattern.compile(", ");
private static final Logger logger = LoggerFactory.getLogger(MetaPackImpl.class);
private final MetaPackTemplate template = new MetaPackTemplate();
private final Platform platform;
private final Path rootPath;
private final Map<String, ConfigPack> packs = new HashMap<>();
private final ConfigLoader selfLoader = new ConfigLoader();
private final Context context = new Context();
private final RegistryKey key;
private final Map<Type, CheckedRegistryImpl<?>> registryMap = new HashMap<>();
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
private final String author;
public MetaPackImpl(Path path, Platform platform, ConfigRegistry configRegistry) throws IOException {
long start = System.nanoTime();
if(Files.notExists(path)) throw new FileNotFoundException("Could not load metapack, " + path + " does not exist");
if(Files.isDirectory(path)) {
this.rootPath = path;
} else if(Files.isRegularFile(path)) {
if(!path.getFileName().toString().endsWith(".zip")) {
throw new IOException("Could not load metapack, file " + path + " is not a zip");
}
FileSystem zipfs = FileSystems.newFileSystem(path);
this.rootPath = zipfs.getPath("/");
} else {
throw new IOException("Could not load metapack from " + path);
}
Path packManifestPath = rootPath.resolve("metapack.yml");
if(Files.notExists(packManifestPath)) throw new IOException("No metapack.yml found in " + path);
Configuration packManifest = new YamlConfiguration(Files.newInputStream(packManifestPath),
packManifestPath.getFileName().toString());
this.platform = platform;
register(selfLoader);
platform.register(selfLoader);
register(abstractConfigLoader);
platform.register(abstractConfigLoader);
selfLoader.load(template, packManifest);
String namespace;
String id;
if(template.getID().contains(":")) {
namespace = template.getID().substring(0, template.getID().indexOf(":"));
id = template.getID().substring(template.getID().indexOf(":") + 1);
} else {
id = template.getID();
namespace = template.getID();
}
this.key = RegistryKey.of(namespace, id);
logger.info("Loading metapack \"{}:{}\"", id, namespace);
template.getPacks().forEach((k, v) -> {
RegistryKey registryKey = RegistryKey.parse(v);
if(configRegistry.contains(registryKey)) {
packs.put(k, configRegistry.get(registryKey).get());
logger.info("Linked config pack \"{}\" to metapack \"{}:{}\".", v, namespace, id);
} else {
logger.warn("Failed to link config pack \"{}\" to metapack \"{}:{}\".", v, namespace, id);
}
});
HashSet<String> authors = new HashSet<>();
packs.forEach((k, v) -> {
authors.addAll(Arrays.asList(PATTERN.split(v.getAuthor())));
});
authors.addAll(Arrays.asList(PATTERN.split(template.getAuthor())));
this.author = String.join(", ", authors);
logger.info("Loaded metapack \"{}:{}\" v{} by {} in {}ms.",
namespace, id, getVersion().getFormatted(), author, (System.nanoTime() - start) / 1000000.0D);
}
@Override
public String getAuthor() {
return author;
}
@Override
public Version getVersion() {
return template.getVersion();
}
@Override
public Map<String, ConfigPack> packs() {
return packs;
}
@Override
public Context getContext() {
return context;
}
@Override
public RegistryKey getRegistryKey() {
return key;
}
@Override
public <T> CheckedRegistry<T> getRegistry(Type type) {
return (CheckedRegistry<T>) registryMap.get(type);
}
@Override
public <T> CheckedRegistry<T> getCheckedRegistry(Type type) throws IllegalStateException {
return (CheckedRegistry<T>) registryMap.get(type);
}
@Override
public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) {
return (CheckedRegistry<T>) registryMap.computeIfAbsent(typeKey.getType(), c -> {
OpenRegistry<T> registry = new OpenRegistryImpl<>(typeKey);
selfLoader.registerLoader(c, registry);
abstractConfigLoader.registerLoader(c, registry);
logger.debug("Registered loader for registry of class {}", ReflectionUtil.typeToString(c));
if(typeKey.getType() instanceof ParameterizedType param) {
Type base = param.getRawType();
if(base instanceof Class // should always be true but we'll check anyways
&& Supplier.class.isAssignableFrom((Class<?>) base)) { // If it's a supplier
Type supplied = param.getActualTypeArguments()[0]; // Grab the supplied type
if(supplied instanceof ParameterizedType suppliedParam) {
Type suppliedBase = suppliedParam.getRawType();
if(suppliedBase instanceof Class // should always be true but we'll check anyways
&& ObjectTemplate.class.isAssignableFrom((Class<?>) suppliedBase)) {
Type templateType = suppliedParam.getActualTypeArguments()[0];
GenericTemplateSupplierLoader<?> loader = new GenericTemplateSupplierLoader<>(
(Registry<Supplier<ObjectTemplate<Supplier<ObjectTemplate<?>>>>>) registry);
selfLoader.registerLoader(templateType, loader);
abstractConfigLoader.registerLoader(templateType, loader);
logger.debug("Registered template loader for registry of class {}", ReflectionUtil.typeToString(templateType));
}
}
}
}
return new CheckedRegistryImpl<>(registry);
});
}
@Override
public <T> MetaPackImpl applyLoader(Type type, TypeLoader<T> loader) {
abstractConfigLoader.registerLoader(type, loader);
selfLoader.registerLoader(type, loader);
return this;
}
@Override
public <T> MetaPackImpl applyLoader(Type type, Supplier<ObjectTemplate<T>> loader) {
abstractConfigLoader.registerLoader(type, loader);
selfLoader.registerLoader(type, loader);
return this;
}
@Override
public void register(TypeRegistry registry) {
registryMap.forEach(registry::registerLoader);
}
}
@@ -0,0 +1,41 @@
package com.dfsek.terra.config.pack;
import ca.solostudios.strata.version.Version;
import com.dfsek.tectonic.api.config.template.ConfigTemplate;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import java.util.Map;
@SuppressWarnings({ "unused", "FieldMayBeFinal" })
public class MetaPackTemplate implements ConfigTemplate {
@Value("id")
private String id;
@Value("author")
@Default
private String author = "Anon Y. Mous";
@Value("version")
private Version version;
@Value("packs")
private Map<String, String> packs;
public String getID() {
return id;
}
public String getAuthor() {
return author;
}
public Version getVersion() {
return version;
}
public Map<String, String> getPacks() {
return packs;
}
}
@@ -17,14 +17,13 @@
package com.dfsek.terra.registry.master; package com.dfsek.terra.registry.master;
import com.dfsek.tectonic.api.exception.ConfigException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.io.Serial;
import java.util.zip.ZipFile; import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
@@ -37,44 +36,42 @@ import com.dfsek.terra.registry.OpenRegistryImpl;
* Class to hold config packs * Class to hold config packs
*/ */
public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> { public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
private static final Logger logger = LoggerFactory.getLogger(ConfigRegistry.class);
public ConfigRegistry() { public ConfigRegistry() {
super(TypeKey.of(ConfigPack.class)); super(TypeKey.of(ConfigPack.class));
} }
public void load(File folder, Platform platform) throws ConfigException { public void loadAll(Platform platform) throws IOException, PackLoadFailuresException {
ConfigPack pack = new ConfigPackImpl(folder, platform); Path packsDirectory = platform.getDataFolder().toPath().resolve("packs");
registerChecked(pack.getRegistryKey(), pack); Files.createDirectories(packsDirectory);
List<IOException> failedLoads = new ArrayList<>();
try(Stream<Path> packs = Files.list(packsDirectory)) {
packs.forEach(path -> {
try {
ConfigPack pack = new ConfigPackImpl(path, platform);
registerChecked(pack.getRegistryKey(), pack);
} catch(IOException e) {
failedLoads.add(e);
}
});
}
if(!failedLoads.isEmpty()) {
throw new PackLoadFailuresException(failedLoads);
}
} }
public boolean loadAll(Platform platform) { public static class PackLoadFailuresException extends Exception {
boolean valid = true; @Serial
File packsFolder = new File(platform.getDataFolder(), "packs"); private static final long serialVersionUID = 538998844645186306L;
packsFolder.mkdirs();
for(File dir : Objects.requireNonNull(packsFolder.listFiles(File::isDirectory))) {
try {
load(dir, platform);
} catch(ConfigException e) {
logger.error("Error loading config pack {}", dir.getName(), e);
valid = false;
}
}
for(File zip : Objects.requireNonNull(
packsFolder.listFiles(file -> file.getName().endsWith(".zip") || file.getName().endsWith(".terra")))) {
try {
logger.info("Loading ZIP archive: {}", zip.getName());
load(new ZipFile(zip), platform);
} catch(IOException | ConfigException e) {
logger.error("Error loading config pack {}", zip.getName(), e);
valid = false;
}
}
return valid;
}
public void load(ZipFile file, Platform platform) throws ConfigException { private final List<Throwable> exceptions;
ConfigPackImpl pack = new ConfigPackImpl(file, platform);
registerChecked(pack.getRegistryKey(), pack); public PackLoadFailuresException(List<? extends Throwable> exceptions) {
this.exceptions = (List<Throwable>) exceptions;
}
public List<Throwable> getExceptions() {
return exceptions;
}
} }
} }
@@ -0,0 +1,62 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.registry.master;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.pack.MetaPackImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry.PackLoadFailuresException;
/**
* Class to hold config packs
*/
public class MetaConfigRegistry extends OpenRegistryImpl<MetaPack> {
public MetaConfigRegistry() {
super(TypeKey.of(MetaPack.class));
}
public void loadAll(Platform platform, ConfigRegistry configRegistry) throws IOException, PackLoadFailuresException {
Path packsDirectory = platform.getDataFolder().toPath().resolve("metapacks");
Files.createDirectories(packsDirectory);
List<IOException> failedLoads = new ArrayList<>();
try(Stream<Path> packs = Files.list(packsDirectory)) {
packs.forEach(path -> {
try {
MetaPack pack = new MetaPackImpl(path, platform, configRegistry);
registerChecked(pack.getRegistryKey(), pack);
} catch(IOException e) {
failedLoads.add(e);
}
});
}
if(!failedLoads.isEmpty()) {
throw new PackLoadFailuresException(failedLoads);
}
}
}
Binary file not shown.
+2 -1
View File
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
Vendored
+7 -7
View File
@@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
@@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@@ -202,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command:
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# shell script including quotes and variable substitutions, so put them in # and any embedded shellness will be escaped.
# double quotes to make sure that they get re-expanded; and # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# * put everything else in single quotes, so that it's not re-expanded. # treated as '${Hostname}' itself on the command line.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+1 -7
View File
@@ -10,19 +10,13 @@ repositories {
dependencies { dependencies {
shaded(project(":platforms:bukkit:common")) shaded(project(":platforms:bukkit:common"))
shaded(project(":platforms:bukkit:nms:v1_18_R2", configuration = "reobf")) shaded(project(":platforms:bukkit:nms:v1_20_R3", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R1", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R2", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R3", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_20_R1", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_20_R2", configuration = "reobf"))
shaded("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper) shaded("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
} }
tasks { tasks {
shadowJar { shadowJar {
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib") relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
relocate("com.tcoded.folialib", "com.dfsek.terra.lib.folialib")
relocate("com.google.common", "com.dfsek.terra.lib.google.common") relocate("com.google.common", "com.dfsek.terra.lib.google.common")
relocate("org.apache.logging.slf4j", "com.dfsek.terra.lib.slf4j-over-log4j") relocate("org.apache.logging.slf4j", "com.dfsek.terra.lib.slf4j-over-log4j")
exclude("org/slf4j/**") exclude("org/slf4j/**")
+1 -3
View File
@@ -8,9 +8,7 @@ dependencies {
compileOnly("io.papermc.paper", "paper-api", Versions.Bukkit.paper) compileOnly("io.papermc.paper", "paper-api", Versions.Bukkit.paper)
shadedApi("io.papermc", "paperlib", Versions.Bukkit.paperLib) shadedApi("io.papermc", "paperlib", Versions.Bukkit.paperLib)
// TODO: 2023-11-08 When we drop support for 1.18 and 1.19, we can remove FoliaLib and instead use `RegionScheduler`,
// AsyncScheduler, or GlobalRegionScheduler.
shadedApi("com.tcoded", "FoliaLib", Versions.Bukkit.foliaLib)
shadedApi("com.google.guava", "guava", Versions.Libraries.Internal.guava) shadedApi("com.google.guava", "guava", Versions.Libraries.Internal.guava)
shadedApi("cloud.commandframework", "cloud-paper", Versions.Libraries.cloud) shadedApi("cloud.commandframework", "cloud-paper", Versions.Libraries.cloud)
@@ -63,8 +63,7 @@ public class PlatformImpl extends AbstractPlatform {
@Override @Override
public boolean reload() { public boolean reload() {
getTerraConfig().load(this); getTerraConfig().load(this);
getRawConfigRegistry().clear(); boolean succeed = loadConfigPacks();
boolean succeed = getRawConfigRegistry().loadAll(this);
Bukkit.getWorlds().forEach(world -> { Bukkit.getWorlds().forEach(world -> {
if(world.getGenerator() instanceof BukkitChunkGeneratorWrapper wrapper) { if(world.getGenerator() instanceof BukkitChunkGeneratorWrapper wrapper) {
@@ -84,8 +83,8 @@ public class PlatformImpl extends AbstractPlatform {
} }
@Override @Override
public void runPossiblyUnsafeTask(@NotNull Runnable task) { public void runPossiblyUnsafeTask(@NotNull Runnable runnable) {
plugin.getFoliaLib().getImpl().runAsync(task); plugin.getGlobalRegionScheduler().run(plugin, task -> runnable.run());
} }
@Override @Override
@@ -21,7 +21,8 @@ import cloud.commandframework.brigadier.CloudBrigadierManager;
import cloud.commandframework.bukkit.CloudBukkitCapabilities; import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.execution.CommandExecutionCoordinator; import cloud.commandframework.execution.CommandExecutionCoordinator;
import cloud.commandframework.paper.PaperCommandManager; import cloud.commandframework.paper.PaperCommandManager;
import com.tcoded.folialib.FoliaLib; import io.papermc.paper.threadedregions.scheduler.AsyncScheduler;
import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
@@ -32,6 +33,7 @@ import org.slf4j.LoggerFactory;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.dfsek.terra.api.command.CommandSender; import com.dfsek.terra.api.command.CommandSender;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
@@ -51,7 +53,9 @@ public class TerraBukkitPlugin extends JavaPlugin {
private final PlatformImpl platform = new PlatformImpl(this); private final PlatformImpl platform = new PlatformImpl(this);
private final Map<String, com.dfsek.terra.api.world.chunk.generation.ChunkGenerator> generatorMap = new HashMap<>(); private final Map<String, com.dfsek.terra.api.world.chunk.generation.ChunkGenerator> generatorMap = new HashMap<>();
private final FoliaLib foliaLib = new FoliaLib(this); private AsyncScheduler asyncScheduler = this.getServer().getAsyncScheduler();
private GlobalRegionScheduler globalRegionScheduler = this.getServer().getGlobalRegionScheduler();
@Override @Override
public void onEnable() { public void onEnable() {
@@ -61,6 +65,10 @@ public class TerraBukkitPlugin extends JavaPlugin {
platform.getEventManager().callEvent(new PlatformInitializationEvent()); platform.getEventManager().callEvent(new PlatformInitializationEvent());
if(!Initializer.init(platform)) {
Bukkit.getPluginManager().disablePlugin(this);
return;
}
try { try {
PaperCommandManager<CommandSender> commandManager = getCommandSenderPaperCommandManager(); PaperCommandManager<CommandSender> commandManager = getCommandSenderPaperCommandManager();
@@ -80,8 +88,6 @@ public class TerraBukkitPlugin extends JavaPlugin {
Bukkit.getPluginManager().registerEvents(new CommonListener(), this); // Register master event listener Bukkit.getPluginManager().registerEvents(new CommonListener(), this); // Register master event listener
PaperUtil.checkPaper(this); PaperUtil.checkPaper(this);
Initializer.init(platform);
} }
@NotNull @NotNull
@@ -116,6 +122,9 @@ public class TerraBukkitPlugin extends JavaPlugin {
if(!VersionUtil.getSpigotVersionInfo().isSpigot()) if(!VersionUtil.getSpigotVersionInfo().isSpigot())
logger.error("YOU ARE RUNNING A CRAFTBUKKIT OR BUKKIT SERVER. PLEASE UPGRADE TO PAPER."); logger.error("YOU ARE RUNNING A CRAFTBUKKIT OR BUKKIT SERVER. PLEASE UPGRADE TO PAPER.");
if(!VersionUtil.getSpigotVersionInfo().isPaper())
logger.error("YOU ARE RUNNING A SPIGOT SERVER. PLEASE UPGRADE TO PAPER.");
if(VersionUtil.getSpigotVersionInfo().isMohist()) { if(VersionUtil.getSpigotVersionInfo().isMohist()) {
if(System.getProperty("IKnowMohistCausesLotsOfIssuesButIWillUseItAnyways") == null) { if(System.getProperty("IKnowMohistCausesLotsOfIssuesButIWillUseItAnyways") == null) {
Runnable runnable = () -> { // scary big block of text Runnable runnable = () -> { // scary big block of text
@@ -159,7 +168,7 @@ public class TerraBukkitPlugin extends JavaPlugin {
""".strip()); """.strip());
}; };
runnable.run(); runnable.run();
foliaLib.getImpl().runLaterAsync(runnable, 200L); asyncScheduler.runDelayed(this, task -> runnable.run(), 200L, TimeUnit.SECONDS);
// Bukkit.shutdown(); // we're not *that* evil // Bukkit.shutdown(); // we're not *that* evil
Bukkit.getPluginManager().disablePlugin(this); Bukkit.getPluginManager().disablePlugin(this);
return false; return false;
@@ -187,7 +196,11 @@ public class TerraBukkitPlugin extends JavaPlugin {
}), platform.getRawConfigRegistry().getByID(id).orElseThrow(), platform.getWorldHandle().air()); }), platform.getRawConfigRegistry().getByID(id).orElseThrow(), platform.getWorldHandle().air());
} }
public FoliaLib getFoliaLib() { public AsyncScheduler getAsyncScheduler() {
return foliaLib; return asyncScheduler;
}
public GlobalRegionScheduler getGlobalRegionScheduler() {
return globalRegionScheduler;
} }
} }
@@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.random.RandomGenerator;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
@@ -20,6 +20,8 @@ package com.dfsek.terra.bukkit.handles;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Locale; import java.util.Locale;
@@ -31,6 +33,7 @@ import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;
public class BukkitWorldHandle implements WorldHandle { public class BukkitWorldHandle implements WorldHandle {
private static final Logger logger = LoggerFactory.getLogger(BukkitWorldHandle.class);
private final BlockState air; private final BlockState air;
public BukkitWorldHandle() { public BukkitWorldHandle() {
@@ -39,6 +42,13 @@ public class BukkitWorldHandle implements WorldHandle {
@Override @Override
public synchronized @NotNull BlockState createBlockState(@NotNull String data) { public synchronized @NotNull BlockState createBlockState(@NotNull String data) {
if(data.equals("minecraft:grass")) { //TODO: remove in 7.0
data = "minecraft:short_grass";
logger.warn(
"Translating minecraft:grass to minecraft:short_grass. In 1.20.3 minecraft:grass was renamed to minecraft:short_grass" +
". You are advised to perform this rename in your config backs as this translation will be removed in the next major " +
"version of Terra.");
}
org.bukkit.block.data.BlockData bukkitData = Bukkit.createBlockData( org.bukkit.block.data.BlockData bukkitData = Bukkit.createBlockData(
data); // somehow bukkit managed to make this not thread safe! :) data); // somehow bukkit managed to make this not thread safe! :)
return BukkitBlockState.newInstance(bukkitData); return BukkitBlockState.newInstance(bukkitData);
@@ -51,6 +61,13 @@ public class BukkitWorldHandle implements WorldHandle {
@Override @Override
public @NotNull EntityType getEntity(@NotNull String id) { public @NotNull EntityType getEntity(@NotNull String id) {
if(!id.contains(":")) { //TODO: remove in 7.0
String newid = "minecraft:" + id.toLowerCase();
logger.warn(
"Translating " + id + " to " + newid + ". In 1.20.3 entity parsing was reworked" +
". You are advised to perform this rename in your config backs as this translation will be removed in the next major " +
"version of Terra.");
}
if(!id.startsWith("minecraft:")) throw new IllegalArgumentException("Invalid entity identifier " + id); if(!id.startsWith("minecraft:")) throw new IllegalArgumentException("Invalid entity identifier " + id);
String entityID = id.toUpperCase(Locale.ROOT).substring(10); String entityID = id.toUpperCase(Locale.ROOT).substring(10);
@@ -11,7 +11,7 @@ public interface Initializer {
String NMS = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; String NMS = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
String TERRA_PACKAGE = Initializer.class.getPackageName(); String TERRA_PACKAGE = Initializer.class.getPackageName();
static void init(PlatformImpl platform) { static boolean init(PlatformImpl platform) {
Logger logger = LoggerFactory.getLogger(Initializer.class); Logger logger = LoggerFactory.getLogger(Initializer.class);
try { try {
Class<?> initializerClass = Class.forName(TERRA_PACKAGE + "." + NMS + ".NMSInitializer"); Class<?> initializerClass = Class.forName(TERRA_PACKAGE + "." + NMS + ".NMSInitializer");
@@ -24,16 +24,27 @@ public interface Initializer {
} catch(ClassNotFoundException e) { } catch(ClassNotFoundException e) {
logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS); logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS);
logger.error("This is usually due to running Terra on an unsupported Minecraft version."); logger.error("This is usually due to running Terra on an unsupported Minecraft version.");
logger.error(""); String bypassKey = "IKnowThereAreNoNMSBindingsFor" + NMS + "ButIWillProceedAnyway";
logger.error(""); if(System.getProperty(bypassKey) == null) {
for(int i = 0; i < 20; i++) { logger.error("Because of this **TERRA HAS BEEN DISABLED**.");
logger.error("PROCEEDING WITH AN EXISTING TERRA WORLD WILL RESULT IN CORRUPTION!!!"); logger.error("Do not come ask us why it is not working.");
logger.error("If you wish to proceed anyways, you can add the JVM System Property \"{}\" to enable the plugin.", bypassKey);
return false;
} else {
logger.error("");
logger.error("");
for(int i = 0; i < 20; i++) {
logger.error("PROCEEDING WITH AN EXISTING TERRA WORLD WILL RESULT IN CORRUPTION!!!");
}
logger.error("");
logger.error("");
logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS);
logger.error("This is usually due to running Terra on an unsupported Minecraft version.");
logger.error("We will not give you any support for issues that may arise.");
logger.error("Since you enabled the \"{}\" flag, we won't disable Terra. But be warned.", bypassKey);
} }
logger.error("");
logger.error("");
logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS);
logger.error("This is usually due to running Terra on an unsupported Minecraft version.");
} }
return true;
} }
void initialize(PlatformImpl plugin); void initialize(PlatformImpl plugin);
@@ -19,6 +19,8 @@ package com.dfsek.terra.bukkit.util;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import java.util.concurrent.TimeUnit;
import com.dfsek.terra.bukkit.TerraBukkitPlugin; import com.dfsek.terra.bukkit.TerraBukkitPlugin;
import static io.papermc.lib.PaperLib.suggestPaper; import static io.papermc.lib.PaperLib.suggestPaper;
@@ -26,10 +28,10 @@ import static io.papermc.lib.PaperLib.suggestPaper;
public final class PaperUtil { public final class PaperUtil {
public static void checkPaper(TerraBukkitPlugin plugin) { public static void checkPaper(TerraBukkitPlugin plugin) {
plugin.getFoliaLib().getImpl().runLaterAsync(() -> { plugin.getAsyncScheduler().runDelayed(plugin, task -> {
if(!PaperLib.isPaper()) { if(!PaperLib.isPaper()) {
suggestPaper(plugin); suggestPaper(plugin);
} }
}, 100L); }, 100L, TimeUnit.SECONDS);
} }
} }
@@ -4,6 +4,6 @@ version: "@VERSION@"
load: "STARTUP" load: "STARTUP"
author: dfsek author: dfsek
website: "@WIKI@" website: "@WIKI@"
api-version: "1.13" api-version: "1.20"
description: "@DESCRIPTION@" description: "@DESCRIPTION@"
folia-supported: true folia-supported: true
@@ -1,17 +0,0 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle("1.18.2-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
tasks {
assemble {
dependsOn("reobfJar")
}
}
@@ -1,115 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSBiomeInjector.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) Registries.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(
biome,
biomeRegistry.get(vanillaMinecraftKey) // get
);
ResourceKey<Biome> delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY, new ResourceLocation("terra",
NMSBiomeInjector.createBiomeID(
pack, key)));
BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform);
biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
platformBiome.getContext().put(new NMSBiomeInfo(delegateKey));
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<TagKey<Biome>, List<Holder<Biome>>> collect = biomeRegistry
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
terraBiomeMap
.forEach((vb, terraBiomes) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb)
.ifPresentOrElse(
vanilla -> terraBiomes
.forEach(tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb)
.ifPresentOrElse(
terra -> {
LOGGER.debug(
vanilla.unwrapKey()
.orElseThrow()
.location() +
" (vanilla for " +
terra.unwrapKey()
.orElseThrow()
.location() +
": " +
vanilla.tags()
.toList());
vanilla.tags()
.forEach(
tag -> collect
.computeIfAbsent(
tag,
t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error(
"No such biome: {}",
tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.resetTags(); // clearTags
biomeRegistry.bindTags(ImmutableMap.copyOf(collect)); // populateTags
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}
}
}
@@ -1,10 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import com.dfsek.terra.api.properties.Properties;
public record NMSBiomeInfo(ResourceKey<Biome> biomeKey) implements Properties {
}

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