mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-05-20 08:40:26 +00:00
Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2e3ce78521 | |||
| c6eb2f49f3 | |||
| 6929de7b61 | |||
| a159debe3e | |||
| 99e2907b2d | |||
| ac71b3ec0c | |||
| e184937743 | |||
| 8c155c78eb | |||
| fc779e1120 | |||
| be964da4fa | |||
| 6ca401413b | |||
| e556e2bca1 | |||
| 1fc97a480a | |||
| bba55f2669 | |||
| 97b4ea6d94 | |||
| cf4f7822e2 | |||
| d6285a5901 | |||
| 8b933b0d5c | |||
| f9a5dfbfce | |||
| 24bca3ed98 | |||
| f8f6b0b4bc | |||
| dd2f0365b0 | |||
| ae2d801be0 | |||
| 8578bba7b9 | |||
| d262831107 | |||
| ddc8cc7db5 | |||
| 12f1b3f8fc | |||
| dc7c57d1a3 | |||
| 309fb5af96 | |||
| 9d747aed71 | |||
| 3cf11a9ad4 | |||
| 9f766b0647 | |||
| 8fa3978dc8 | |||
| c282e55f90 | |||
| 8b62badbdb | |||
| 8bceb255c0 | |||
| ad80769d67 | |||
| 9d0fa0a7c4 | |||
| 8c532ede8e | |||
| c3d26527a7 | |||
| 1fe56335c8 | |||
| 3b377d91ee | |||
| 0144200ec9 | |||
| d1ad3d04e1 | |||
| d640b49ded | |||
| ecbfd1740c | |||
| dc5952add7 | |||
| 1b6ebeb05f | |||
| 234ff3e49c | |||
| 243c523b57 | |||
| 1700650753 | |||
| 12d2221d49 | |||
| 42e1adfc3a | |||
| 4ff91c9fea | |||
| 81bc51f5a1 | |||
| ac98726f81 | |||
| 1d2c6d4294 | |||
| 9ca7014344 | |||
| 8d153998fa | |||
| 2b09ed8fd9 | |||
| 96493ede15 | |||
| 48586eb523 | |||
| a80b94ad45 | |||
| 089850d633 | |||
| 42f3c56b71 | |||
| 874ef56025 | |||
| 06f04005ea | |||
| 774d076f77 | |||
| e4561bd48f | |||
| 550a037661 | |||
| 3b25e82a73 | |||
| 9b3a105672 | |||
| 10558b5446 | |||
| 326300bcce | |||
| a7826dec49 | |||
| fd3d1ce830 | |||
| 84a6cd0c26 | |||
| d1faac8b96 | |||
| de4656d01f | |||
| 6dba2e9394 | |||
| 8a8db4a9b8 | |||
| 3ef60f4b33 | |||
| b7864bb6fb | |||
| 757ed6ad4d |
@@ -44,6 +44,7 @@ You must put an x in all the boxes that it applies to. (Like this: [x])
|
||||
<!-- There is an included `.editorconfig` file in the base of the repo. Please use a plugin for your IDE of choice that follows those settings. -->
|
||||
- [ ] I have read the [`CONTRIBUTING.md`](https://github.com/PolyhedralDev/Terra/blob/master/CONTRIBUTING.md)
|
||||
document in the root of the git repository.
|
||||
- [ ] LLM-based tools were not used to create this PR. (ChatGPT, Claude, etc)
|
||||
|
||||
#### Types of changes
|
||||
|
||||
@@ -98,7 +99,7 @@ You must put an x in all the boxes that it applies to. (Like this: [x])
|
||||
- [ ] I am not the original author of this code, but it is in public domain or
|
||||
released under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html) or a compatible license.
|
||||
<!--
|
||||
Please provide reliable evidence of this.
|
||||
Please provide reliable evidence of this. LLM-generated code does not satisfy this requirement.
|
||||
NOTE: for compatible licenses, you must make sure to add the included license somewhere in the program, if so required.
|
||||
(And even if it's not required, it's still nice to do it. Also add attribution somewhere.)
|
||||
-->
|
||||
|
||||
+5
-2
@@ -258,6 +258,9 @@ as [GitHub Pull Requests](https://guides.github.com/activities/forking/#making-a
|
||||
see instead** and why.
|
||||
- **Explain why this enhancement would be useful** to most Terra users and isn't
|
||||
something that can or should be implemented as an addon.
|
||||
- **Do not use LLM/"AI" tools to create your pull request.** Your pr should be written
|
||||
by you. Using an LLM to automate small, tedious tasks (regex and other fiddly things like it)
|
||||
is acceptable, but submitting a low-effort, completely LLM-generated PR will result in a ban.
|
||||
|
||||
## Styleguides
|
||||
|
||||
@@ -381,7 +384,7 @@ compatibilities are welcome and encouraged, in the form of addons.**
|
||||
|
||||
### Platform-Agnostic Design
|
||||
|
||||
Terra must, at all times, remain platform agnostic. This means it must be able
|
||||
Terra must, at all times, remain platform-agnostic. This means it must be able
|
||||
to run on theoretically any voxel based platform. Including non-minecraft games
|
||||
like Terasology.
|
||||
|
||||
@@ -391,7 +394,7 @@ it'll be running on.
|
||||
Examples:
|
||||
|
||||
- Don't assume the world height is 256.
|
||||
- Don't assume that a specific block, item, or entity exists. (Eg. don't assume
|
||||
- Don't assume that a specific block, item, or entity exists. (E.g. don't assume
|
||||
there exists a block called `minecraft:grass_block`)
|
||||
|
||||
### Data-Driven
|
||||
|
||||
Vendored
+149
@@ -0,0 +1,149 @@
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
tools {
|
||||
jdk "Temurin Java 21"
|
||||
}
|
||||
|
||||
triggers {
|
||||
githubPush()
|
||||
}
|
||||
|
||||
environment {
|
||||
DISCORD_WEBHOOK_URL = credentials('polydev-discord-webhook-url')
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
scmSkip(deleteBuild: true)
|
||||
}
|
||||
}
|
||||
|
||||
stage('Setup Gradle') {
|
||||
steps {
|
||||
sh 'chmod +x gradlew'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
steps {
|
||||
withGradle {
|
||||
sh './gradlew build --rerun-tasks -x check'
|
||||
sh './gradlew javadoc'
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts artifacts: 'platforms/fabric/build/libs/Terra-fabric*.jar,platforms/bukkit/build/libs/Terra-bukkit*-shaded.jar,platforms/allay/build/libs/Terra-allay*.jar,platforms/minestom/build/libs/Terra-minestom*.jar', fingerprint: true, onlyIfSuccessful: true
|
||||
|
||||
javadoc javadocDir: 'common/api/build/docs/javadoc', keepAll: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Tests') {
|
||||
steps {
|
||||
withGradle {
|
||||
sh './gradlew test --rerun-tasks'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stage('Deploy to snapshots repositories') {
|
||||
// when {
|
||||
// allOf {
|
||||
// not { buildingTag() }
|
||||
// not { expression { env.TAG_NAME != null && env.TAG_NAME.matches('v\\d+\\.\\d+\\.\\d+') } }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// steps {
|
||||
// withCredentials([
|
||||
// string(credentialsId: 'maven-signing-key', variable: 'ORG_GRADLE_PROJECT_signingKey'),
|
||||
// string(credentialsId: 'maven-signing-key-password', variable: 'ORG_GRADLE_PROJECT_signingPassword'),
|
||||
// usernamePassword(
|
||||
// credentialsId: 'solo-studios-maven',
|
||||
// passwordVariable: 'ORG_GRADLE_PROJECT_SoloStudiosSnapshotsPassword',
|
||||
// usernameVariable: 'ORG_GRADLE_PROJECT_SoloStudiosSnapshotsUsername'
|
||||
// )
|
||||
// ]) {
|
||||
// withGradle {
|
||||
// sh './gradlew publishAllPublicationsToSoloStudiosSnapshotsRepository'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
stage('Deploy to releases repositories') {
|
||||
// when {
|
||||
// allOf {
|
||||
// buildingTag()
|
||||
// expression { env.TAG_NAME != null && env.TAG_NAME.matches('v\\d+\\.\\d+\\.\\d+') }
|
||||
// }
|
||||
// }
|
||||
|
||||
steps {
|
||||
withCredentials([
|
||||
string(credentialsId: 'maven-signing-key', variable: 'ORG_GRADLE_PROJECT_signingKey'),
|
||||
string(credentialsId: 'maven-signing-key-password', variable: 'ORG_GRADLE_PROJECT_signingPassword'),
|
||||
usernamePassword(
|
||||
credentialsId: 'solo-studios-maven',
|
||||
passwordVariable: 'ORG_GRADLE_PROJECT_SoloStudiosReleasesPassword',
|
||||
usernameVariable: 'ORG_GRADLE_PROJECT_SoloStudiosReleasesUsername'
|
||||
),
|
||||
// TODO: does not yet exist (uncomment once added)
|
||||
// usernamePassword(
|
||||
// credentialsId: 'sonatype-maven-credentials',
|
||||
// passwordVariable: 'ORG_GRADLE_PROJECT_SonatypePassword',
|
||||
// usernameVariable: 'ORG_GRADLE_PROJECT_SonatypeUsername'
|
||||
// ),
|
||||
// usernamePassword(
|
||||
// credentialsId: 'codemc-maven-credentials',
|
||||
// passwordVariable: 'ORG_GRADLE_PROJECT_CodeMCPassword',
|
||||
// usernameVariable: 'ORG_GRADLE_PROJECT_CodeMCUsername'
|
||||
// )
|
||||
]) {
|
||||
withGradle {
|
||||
sh './gradlew publish'
|
||||
//sh './gradlew publishAllPublicationsToSoloStudiosReleasesRepository'
|
||||
// sh './gradlew publishAllPublicationsToSonatypeRepository'
|
||||
// sh './gradlew publishAllPublicationsToCodeMCRepository'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
discoverReferenceBuild()
|
||||
|
||||
// junit testResults: '**/build/test-results/*/TEST-*.xml'
|
||||
|
||||
recordIssues(
|
||||
aggregatingResults: true,
|
||||
enabledForFailure: true,
|
||||
minimumSeverity: 'ERROR',
|
||||
sourceCodeEncoding: 'UTF-8',
|
||||
checksAnnotationScope: 'ALL',
|
||||
sourceCodeRetention: 'LAST_BUILD',
|
||||
tools: [java(), javaDoc()]
|
||||
)
|
||||
|
||||
discordSend(
|
||||
title: env.JOB_NAME + ' ' + env.BUILD_DISPLAY_NAME,
|
||||
showChangeset: true,
|
||||
enableArtifactsList: true,
|
||||
link: env.BUILD_URL,
|
||||
result: currentBuild.currentResult,
|
||||
customAvatarUrl: 'https://github.com/PolyhedralDev.png',
|
||||
customUsername: 'Solo Studios Jenkins',
|
||||
webhookURL: env.DISCORD_WEBHOOK_URL,
|
||||
)
|
||||
|
||||
cleanWs()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,11 +22,11 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
//TODO Allow pulling from Versions.kt
|
||||
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.6")
|
||||
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.9")
|
||||
|
||||
implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "2.0.0-beta.17")
|
||||
implementation("org.ow2.asm", "asm", "9.8")
|
||||
implementation("org.ow2.asm", "asm-tree", "9.8")
|
||||
implementation("com.dfsek.tectonic", "common", "4.2.1")
|
||||
implementation("org.yaml", "snakeyaml", "2.4")
|
||||
implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "2.0.0-beta.18")
|
||||
implementation("org.ow2.asm", "asm", "9.9")
|
||||
implementation("org.ow2.asm", "asm-tree", "9.9")
|
||||
implementation("com.dfsek.tectonic", "common", "4.3.1")
|
||||
implementation("org.yaml", "snakeyaml", "2.5")
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import org.gradle.kotlin.dsl.getByName
|
||||
import org.gradle.kotlin.dsl.register
|
||||
import org.gradle.kotlin.dsl.withType
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
import org.gradle.plugins.ide.idea.model.IdeaModel
|
||||
|
||||
fun Project.configureCompilation() {
|
||||
apply(plugin = "maven-publish")
|
||||
@@ -21,6 +22,13 @@ fun Project.configureCompilation() {
|
||||
apply(plugin = "idea")
|
||||
apply<TectonicDocPlugin>()
|
||||
|
||||
configure<IdeaModel> {
|
||||
module {
|
||||
isDownloadJavadoc = true
|
||||
isDownloadSources = true
|
||||
}
|
||||
}
|
||||
|
||||
configure<JavaPluginExtension> {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
|
||||
@@ -57,15 +57,6 @@ fun Project.configureDependencies() {
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
|
||||
name = "Sonatype Snapshots"
|
||||
}
|
||||
maven("https://repo.opencollab.dev/maven-releases/") {
|
||||
name = "OpenCollab Releases"
|
||||
}
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/") {
|
||||
name = "OpenCollab Snapshots"
|
||||
}
|
||||
maven("https://storehouse.okaeri.eu/repository/maven-public/") {
|
||||
name = "Okaeri"
|
||||
}
|
||||
maven("https://repo.onarandombox.com/multiverse-releases") {
|
||||
name = "onarandombox"
|
||||
}
|
||||
|
||||
@@ -49,9 +49,19 @@ fun Project.configureDistribution() {
|
||||
doFirst {
|
||||
try {
|
||||
file("${buildDir}/resources/main/packs/").deleteRecursively()
|
||||
file("${buildDir}/resources/main/metapacks/").deleteRecursively()
|
||||
val overworldPackUrl =
|
||||
URL("https://github.com/PolyhedralDev/TerraOverworldConfig/releases/download/" + Versions.Terra.overworldConfig + "/Overworld.zip")
|
||||
val reimagENDPackUrl =
|
||||
URL("https://github.com/PolyhedralDev/ReimagEND/releases/download/" + Versions.Terra.reimagENDConfig + "/ReimagEND.zip")
|
||||
val tartarusPackUrl =
|
||||
URL("https://github.com/PolyhedralDev/Tartarus/releases/download/" + Versions.Terra.tartarusConfig + "/Tartarus.zip")
|
||||
val defaultPackUrl =
|
||||
URL("https://github.com/PolyhedralDev/TerraOverworldConfig/releases/download/" + Versions.Terra.overworldConfig + "/default.zip")
|
||||
downloadPack(defaultPackUrl, project)
|
||||
URL("https://github.com/PolyhedralDev/DefaultMetapack/releases/download/" + Versions.Terra.defaultConfig + "/default.zip")
|
||||
downloadPack(overworldPackUrl, project)
|
||||
downloadPack(reimagENDPackUrl, project)
|
||||
downloadPack(tartarusPackUrl, project)
|
||||
downloadPack(defaultPackUrl, project, true)
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
@@ -97,6 +107,13 @@ fun Project.configureDistribution() {
|
||||
resources.computeIfAbsent("packs") { ArrayList() }.add(it.name)
|
||||
}
|
||||
|
||||
val metaPacksDir = File("${project.buildDir}/resources/main/metapacks/")
|
||||
|
||||
metaPacksDir.walkTopDown().forEach {
|
||||
if (it.isDirectory || !it.name.endsWith(".zip")) return@forEach
|
||||
resources.computeIfAbsent("metapacks") { ArrayList() }.add(it.name)
|
||||
}
|
||||
|
||||
val langDir = File("${project(":common:implementation").buildDir}/resources/main/lang/")
|
||||
|
||||
langDir.walkTopDown().forEach {
|
||||
@@ -164,9 +181,10 @@ fun Project.configureDistribution() {
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadPack(packUrl: URL, project: Project) {
|
||||
fun downloadPack(packUrl: URL, project: Project, metapack: Boolean = false) {
|
||||
val fileName = packUrl.file.substring(packUrl.file.lastIndexOf("/"))
|
||||
val file = File("${project.buildDir}/resources/main/packs/${fileName}")
|
||||
val resourceType = if (metapack) "metapacks" else "packs"
|
||||
val file = File("${project.buildDir}/resources/main/${resourceType}/${fileName}")
|
||||
file.parentFile.mkdirs()
|
||||
file.outputStream().write(packUrl.readBytes())
|
||||
}
|
||||
|
||||
@@ -16,16 +16,17 @@ fun Project.configurePublishing() {
|
||||
}
|
||||
|
||||
repositories {
|
||||
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
|
||||
val mavenUrl = "https://maven.solo-studios.ca/releases/"
|
||||
//val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
|
||||
|
||||
maven(mavenUrl) {
|
||||
val mavenUsername: String? by project
|
||||
val mavenPassword: String? by project
|
||||
if (mavenUsername != null && mavenPassword != null) {
|
||||
val SoloStudiosReleasesUsername: String? by project
|
||||
val SoloStudiosReleasesPassword: String? by project
|
||||
|
||||
if (SoloStudiosReleasesUsername != null && SoloStudiosReleasesPassword != null) {
|
||||
credentials {
|
||||
username = mavenUsername
|
||||
password = mavenPassword
|
||||
username = SoloStudiosReleasesUsername
|
||||
password = SoloStudiosReleasesPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,39 @@
|
||||
object Versions {
|
||||
object Terra {
|
||||
const val overworldConfig = "v1.5.2"
|
||||
const val overworldConfig = "latest"
|
||||
const val reimagENDConfig = "latest"
|
||||
const val tartarusConfig = "latest"
|
||||
const val defaultConfig = "latest"
|
||||
}
|
||||
|
||||
object Libraries {
|
||||
const val tectonic = "4.2.1"
|
||||
const val tectonic = "4.3.1"
|
||||
const val paralithic = "2.0.1"
|
||||
const val strata = "1.3.2"
|
||||
const val seismic = "2.0.4"
|
||||
const val seismic = "2.5.7"
|
||||
|
||||
const val cloud = "2.0.0"
|
||||
|
||||
const val caffeine = "3.2.1"
|
||||
const val caffeine = "3.2.2"
|
||||
|
||||
const val slf4j = "2.0.17"
|
||||
|
||||
object Internal {
|
||||
const val shadow = "8.3.6"
|
||||
const val apacheText = "1.13.1"
|
||||
const val apacheIO = "2.19.0"
|
||||
const val guava = "33.4.8-jre"
|
||||
const val asm = "9.8"
|
||||
const val snakeYml = "2.4"
|
||||
const val jetBrainsAnnotations = "26.0.2"
|
||||
const val junit = "5.13.1"
|
||||
const val shadow = "8.3.9"
|
||||
const val apacheText = "1.14.0"
|
||||
const val apacheIO = "2.20.0"
|
||||
const val guava = "33.5.0-jre"
|
||||
const val asm = "9.9"
|
||||
const val snakeYml = "2.5"
|
||||
const val jetBrainsAnnotations = "26.0.2-1"
|
||||
const val junit = "6.0.0"
|
||||
const val nbt = "6.1"
|
||||
}
|
||||
}
|
||||
|
||||
object Fabric {
|
||||
const val fabricAPI = "0.133.14+${Mod.minecraft}"
|
||||
const val cloud = "2.0.0-beta.11"
|
||||
const val fabricAPI = "0.134.1+${Mod.minecraft}"
|
||||
const val cloud = "2.0.0-beta.13"
|
||||
}
|
||||
//
|
||||
// object Quilt {
|
||||
@@ -39,14 +42,14 @@ object Versions {
|
||||
// }
|
||||
|
||||
object Mod {
|
||||
const val mixin = "0.15.5+mixin.0.8.7"
|
||||
const val mixinExtras = "0.4.1"
|
||||
const val mixin = "0.16.4+mixin.0.8.7"
|
||||
const val mixinExtras = "0.5.0"
|
||||
|
||||
const val minecraft = "1.21.9"
|
||||
const val minecraft = "1.21.10"
|
||||
const val yarn = "$minecraft+build.1"
|
||||
const val fabricLoader = "0.17.2"
|
||||
const val fabricLoader = "0.18.2"
|
||||
|
||||
const val architecuryLoom = "1.11.440"
|
||||
const val architecuryLoom = "1.11.451"
|
||||
const val architecturyPlugin = "3.4.162"
|
||||
|
||||
}
|
||||
@@ -57,17 +60,17 @@ object Versions {
|
||||
// }
|
||||
|
||||
object Bukkit {
|
||||
const val minecraft = "1.21.9-rc1-R0.1"
|
||||
const val paperBuild = "$minecraft-20250930.133904-13"
|
||||
const val minecraft = "1.21.10"
|
||||
const val nms = "$minecraft-R0.1"
|
||||
const val paperBuild = "$nms-20251012.013929-7"
|
||||
const val paper = paperBuild
|
||||
const val paperLib = "1.0.8"
|
||||
const val reflectionRemapper = "0.1.2"
|
||||
const val reflectionRemapper = "0.1.3"
|
||||
const val paperDevBundle = paperBuild
|
||||
const val runPaper = "2.3.1"
|
||||
const val runPaperMinecraft = "1.21.9"
|
||||
const val paperWeight = "2.0.0-beta.17"
|
||||
const val cloud = "2.0.0-beta.11"
|
||||
const val multiverse = "5.0.2"
|
||||
const val paperWeight = "2.0.0-beta.19"
|
||||
const val cloud = "2.0.0-beta.12"
|
||||
const val multiverse = "5.3.0"
|
||||
}
|
||||
|
||||
//
|
||||
@@ -78,18 +81,21 @@ object Versions {
|
||||
// }
|
||||
//
|
||||
object CLI {
|
||||
const val logback = "1.5.18"
|
||||
const val logback = "1.5.19"
|
||||
const val picocli = "4.7.7"
|
||||
}
|
||||
|
||||
object Allay {
|
||||
const val api = "0.4.1"
|
||||
const val gson = "2.13.1"
|
||||
const val mappings = "3626653"
|
||||
const val mappingsGenerator = "366618e"
|
||||
const val api = "0.13.0"
|
||||
const val gson = "2.13.2"
|
||||
|
||||
const val mappings = "15398c1"
|
||||
const val mappingsGenerator = "8fa6058"
|
||||
|
||||
const val mcmeta = "e85a17c"
|
||||
}
|
||||
|
||||
object Minestom {
|
||||
const val minestom = "1_21_6-a40d7115d4"
|
||||
const val minestom = "2025.10.04-1.21.8"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,6 +46,6 @@ class BaseBiomeColumn implements Column<Biome> {
|
||||
|
||||
@Override
|
||||
public Biome get(int y) {
|
||||
return biomeProvider.extrude(base, x, y, z, seed);
|
||||
return biomeProvider.pipeline.extrude(base, x, y, z, seed);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-12
@@ -6,37 +6,33 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.addons.biome.extrusion.utils.ExtrusionPipeline;
|
||||
import com.dfsek.terra.addons.biome.extrusion.utils.ExtrusionPipelineFactory;
|
||||
import com.dfsek.terra.api.util.Column;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
|
||||
|
||||
public class BiomeExtrusionProvider implements BiomeProvider {
|
||||
public final ExtrusionPipeline pipeline;
|
||||
private final BiomeProvider delegate;
|
||||
private final Set<Biome> biomes;
|
||||
private final Extrusion[] extrusions;
|
||||
private final int resolution;
|
||||
|
||||
public BiomeExtrusionProvider(BiomeProvider delegate, List<Extrusion> extrusions, int resolution) {
|
||||
this.delegate = delegate;
|
||||
this.biomes = delegate.stream().collect(Collectors.toSet());
|
||||
extrusions.forEach(e -> biomes.addAll(e.getBiomes()));
|
||||
this.extrusions = extrusions.toArray(new Extrusion[0]);
|
||||
|
||||
this.pipeline = ExtrusionPipelineFactory.create(extrusions);
|
||||
|
||||
this.resolution = resolution;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int y, int z, long seed) {
|
||||
Biome delegated = delegate.getBiome(x, y, z, seed);
|
||||
|
||||
return extrude(delegated, x, y, z, seed);
|
||||
}
|
||||
|
||||
public Biome extrude(Biome original, int x, int y, int z, long seed) {
|
||||
for(int i = 0; i < extrusions.length; i++) {
|
||||
original = extrusions[i].extrude(original, x, y, z, seed);
|
||||
}
|
||||
return original;
|
||||
return pipeline.extrude(delegated, x, y, z, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,4 +60,4 @@ public class BiomeExtrusionProvider implements BiomeProvider {
|
||||
public BiomeProvider getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-5
@@ -10,6 +10,7 @@ import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
|
||||
import com.dfsek.terra.addons.biome.query.api.BiomeQueries;
|
||||
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.util.collection.TriStateIntCache;
|
||||
import com.dfsek.terra.api.util.range.Range;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
@@ -19,25 +20,41 @@ import com.dfsek.terra.api.world.biome.Biome;
|
||||
*/
|
||||
public class ReplaceExtrusion implements Extrusion {
|
||||
private final Sampler sampler;
|
||||
|
||||
private final Range range;
|
||||
|
||||
private final ProbabilityCollection<ReplaceableBiome> biomes;
|
||||
|
||||
private final Predicate<Biome> hasTag;
|
||||
private final TriStateIntCache cache;
|
||||
|
||||
public ReplaceExtrusion(Sampler sampler, Range range, ProbabilityCollection<ReplaceableBiome> biomes, String tag) {
|
||||
this.sampler = sampler;
|
||||
this.range = range;
|
||||
this.biomes = biomes;
|
||||
this.hasTag = BiomeQueries.has(tag);
|
||||
this.cache = new TriStateIntCache(Biome.INT_ID_COUNTER.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome extrude(Biome original, int x, int y, int z, long seed) {
|
||||
if(hasTag.test(original)) {
|
||||
return range.ifInRange(y, () -> biomes.get(sampler, x, y, z, seed).get(original), original);
|
||||
int id = original.getIntID();
|
||||
|
||||
long state = cache.get(id);
|
||||
boolean passes;
|
||||
|
||||
if(state == TriStateIntCache.STATE_UNSET) {
|
||||
// Only run the test if unset in cache
|
||||
passes = hasTag.test(original);
|
||||
cache.set(id, passes);
|
||||
} else {
|
||||
// Read the primitive long directly
|
||||
passes = (state == TriStateIntCache.STATE_TRUE);
|
||||
}
|
||||
|
||||
if(passes) {
|
||||
if(range.isInRange(y)) {
|
||||
return biomes.get(sampler, x, y, z, seed).get(original);
|
||||
}
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.utils;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public interface ExtrusionPipeline {
|
||||
Biome extrude(Biome original, int x, int y, int z, long seed);
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.utils;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.AALOAD;
|
||||
import static org.objectweb.asm.Opcodes.ACC_FINAL;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static org.objectweb.asm.Opcodes.ARETURN;
|
||||
import static org.objectweb.asm.Opcodes.GETFIELD;
|
||||
import static org.objectweb.asm.Opcodes.ILOAD;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
|
||||
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
||||
import static org.objectweb.asm.Opcodes.LLOAD;
|
||||
import static org.objectweb.asm.Opcodes.PUTFIELD;
|
||||
import static org.objectweb.asm.Opcodes.RETURN;
|
||||
import static org.objectweb.asm.Opcodes.SIPUSH;
|
||||
import static org.objectweb.asm.Opcodes.SWAP;
|
||||
import static org.objectweb.asm.Opcodes.V1_8;
|
||||
|
||||
|
||||
public class ExtrusionPipelineFactory {
|
||||
private static final AtomicInteger ID_COUNTER = new AtomicInteger(0);
|
||||
|
||||
// Type Descriptors
|
||||
private static final String EXTRUSION_TYPE = Type.getInternalName(Extrusion.class);
|
||||
private static final String EXTRUSION_DESC = Type.getDescriptor(Extrusion.class);
|
||||
private static final String BIOME_DESC = Type.getDescriptor(Biome.class);
|
||||
private static final String PIPELINE_INTERFACE = Type.getInternalName(ExtrusionPipeline.class);
|
||||
|
||||
// Method Signature: (Biome, int, int, int, long) -> Biome
|
||||
private static final String EXTRUDE_SIG = "(" + BIOME_DESC + "IIIJ)" + BIOME_DESC;
|
||||
|
||||
public static ExtrusionPipeline create(List<Extrusion> extrusions) {
|
||||
// Optimization: If empty, return identity
|
||||
if(extrusions.isEmpty()) {
|
||||
return (original, x, y, z, seed) -> original;
|
||||
}
|
||||
|
||||
String className = "com/dfsek/terra/addons/biome/extrusion/GeneratedExtrusionPipeline_" + ID_COUNTER.getAndIncrement();
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
|
||||
// 1. Define Class
|
||||
cw.visit(V1_8, ACC_PUBLIC | ACC_FINAL, className, null, "java/lang/Object", new String[]{ PIPELINE_INTERFACE });
|
||||
|
||||
// 2. Define Fields (e0, e1, e2...)
|
||||
for(int i = 0; i < extrusions.size(); i++) {
|
||||
FieldVisitor fv = cw.visitField(ACC_PRIVATE | ACC_FINAL, "e" + i, EXTRUSION_DESC, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
|
||||
// 3. Generate Constructor(Extrusion[])
|
||||
generateConstructor(cw, className, extrusions.size());
|
||||
|
||||
// 4. Generate extrude() method
|
||||
generateExtrudeMethod(cw, className, extrusions.size());
|
||||
|
||||
cw.visitEnd();
|
||||
|
||||
// 5. Load and Instantiate
|
||||
byte[] bytecode = cw.toByteArray();
|
||||
try {
|
||||
Class<?> generatedClass = new PipelineClassLoader(ExtrusionPipelineFactory.class.getClassLoader())
|
||||
.defineClass(className.replace('/', '.'), bytecode);
|
||||
|
||||
return (ExtrusionPipeline) generatedClass.getConstructor(Extrusion[].class)
|
||||
.newInstance((Object) extrusions.toArray(new Extrusion[0]));
|
||||
} catch(Exception e) {
|
||||
throw new RuntimeException("Failed to generate ExtrusionPipeline", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateConstructor(ClassWriter cw, String className, int count) {
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "([L" + EXTRUSION_TYPE + ";)V", null, null);
|
||||
mv.visitCode();
|
||||
|
||||
// super()
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
|
||||
// Assign array elements to fields
|
||||
for(int i = 0; i < count; i++) {
|
||||
mv.visitVarInsn(ALOAD, 0); // Load this
|
||||
mv.visitVarInsn(ALOAD, 1); // Load array argument
|
||||
mv.visitIntInsn(SIPUSH, i); // Load index
|
||||
mv.visitInsn(AALOAD); // Load array[i]
|
||||
mv.visitFieldInsn(PUTFIELD, className, "e" + i, EXTRUSION_DESC);
|
||||
}
|
||||
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0); // Computed automatically
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static void generateExtrudeMethod(ClassWriter cw, String className, int count) {
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "extrude", EXTRUDE_SIG, null, null);
|
||||
mv.visitCode();
|
||||
|
||||
// Helper var indices:
|
||||
// 0: this
|
||||
// 1: Biome original (We will update this or chain it on stack)
|
||||
// 2: int x
|
||||
// 3: int y
|
||||
// 4: int z
|
||||
// 5: long seed
|
||||
|
||||
mv.visitVarInsn(ALOAD, 1); // Load 'original' Biome onto stack initially
|
||||
|
||||
for(int i = 0; i < count; i++) {
|
||||
// Stack contains: [CurrentBiome]
|
||||
|
||||
mv.visitVarInsn(ALOAD, 0); // Load 'this'
|
||||
mv.visitFieldInsn(GETFIELD, className, "e" + i, EXTRUSION_DESC); // Load Extrusion field
|
||||
|
||||
// Stack: [CurrentBiome, Extrusion]
|
||||
// We need: [Extrusion, CurrentBiome, x, y, z, seed]
|
||||
|
||||
mv.visitInsn(SWAP); // Swap to get [Extrusion, CurrentBiome]
|
||||
|
||||
mv.visitVarInsn(ILOAD, 2); // x
|
||||
mv.visitVarInsn(ILOAD, 3); // y
|
||||
mv.visitVarInsn(ILOAD, 4); // z
|
||||
mv.visitVarInsn(LLOAD, 5); // seed
|
||||
|
||||
// Invoke Extrusion.extrude(Biome, x, y, z, seed)
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, EXTRUSION_TYPE, "extrude", EXTRUDE_SIG, true);
|
||||
|
||||
// Stack now contains: [NewBiome]
|
||||
// Loop continues using this result as input for the next one
|
||||
}
|
||||
|
||||
mv.visitInsn(ARETURN); // Return the final Biome
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
// Custom ClassLoader to inject the bytes
|
||||
private static class PipelineClassLoader extends ClassLoader {
|
||||
public PipelineClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public Class<?> defineClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-10
@@ -73,12 +73,13 @@ public class BiomeChunkImpl implements BiomeChunk {
|
||||
lookupArray = tempArray;
|
||||
|
||||
// Apply stage to working grid
|
||||
ViewPoint viewPoint = new ViewPoint(this, gridInterval, lookupArray, size);
|
||||
for(int gridZ = 0; gridZ < gridSize; gridZ = gridZ + 1) {
|
||||
for(int gridX = 0; gridX < gridSize; gridX = gridX + 1) {
|
||||
int xIndex = gridOrigin + gridX * gridInterval;
|
||||
int zIndex = gridOrigin + gridZ * gridInterval;
|
||||
biomes[(xIndex * size) + zIndex] = stage.apply(
|
||||
new ViewPoint(this, gridInterval, gridX, gridZ, xIndex, zIndex, lookupArray, size));
|
||||
viewPoint.set(gridX, gridZ, xIndex, zIndex);
|
||||
biomes[(xIndex * size) + zIndex] = stage.apply(viewPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,25 +158,32 @@ public class BiomeChunkImpl implements BiomeChunk {
|
||||
*/
|
||||
public static class ViewPoint {
|
||||
private final BiomeChunkImpl chunk;
|
||||
private final PipelineBiome biome;
|
||||
private PipelineBiome biome;
|
||||
private final int gridInterval;
|
||||
private final int gridX;
|
||||
private final int gridZ;
|
||||
private final int xIndex;
|
||||
private final int zIndex;
|
||||
private int gridX;
|
||||
private int gridZ;
|
||||
private int xIndex;
|
||||
private int zIndex;
|
||||
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,
|
||||
PipelineBiome[] lookupArray, int size) {
|
||||
this.chunk = chunk;
|
||||
this.gridInterval = gridInterval;
|
||||
this.gridX = 0;
|
||||
this.gridZ = 0;
|
||||
this.xIndex = 0;
|
||||
this.zIndex = 0;
|
||||
this.lookupArray = lookupArray;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void set(int gridX, int gridZ, int xIndex, int zIndex) {
|
||||
this.gridX = gridX;
|
||||
this.gridZ = gridZ;
|
||||
this.xIndex = xIndex;
|
||||
this.zIndex = zIndex;
|
||||
this.lookupArray = lookupArray;
|
||||
this.size = size;
|
||||
this.biome = lookupArray[(this.xIndex * this.size) + this.zIndex];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
version = version("1.0.0")
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(project(":common:addons:manifest-addon-loader"))
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
package com.dfsek.terra.addons.commands.locate;
|
||||
|
||||
import com.dfsek.seismic.type.vector.Vector2Int;
|
||||
import com.dfsek.seismic.type.vector.Vector3Int;
|
||||
import com.dfsek.terra.api.util.generic.either.Either;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class BiomeLocator {
|
||||
|
||||
/**
|
||||
* Locates the nearest biome matching the given predicate using a parallelized square spiral search.
|
||||
*
|
||||
* @param provider The BiomeProvider to search in.
|
||||
* @param properties The world properties (needed for seed and height bounds).
|
||||
* @param originX Starting X coordinate.
|
||||
* @param originZ Starting Z coordinate.
|
||||
* @param radius The maximum radius (in blocks) to search.
|
||||
* @param step The search step/increment. Higher values are faster but less accurate.
|
||||
* @param filter The condition to match the biome.
|
||||
* @param search3D If true, searches the entire vertical column at each step. If false, only checks originY.
|
||||
* @return An Optional containing the location of the found biome, or empty if not found.
|
||||
*/
|
||||
public static Optional<Either<Vector3Int, Vector2Int>> search(
|
||||
@NotNull BiomeProvider provider,
|
||||
@NotNull WorldProperties properties,
|
||||
int originX,
|
||||
int originZ,
|
||||
int radius,
|
||||
int step,
|
||||
@NotNull Predicate<Biome> filter,
|
||||
boolean search3D
|
||||
) {
|
||||
long seed = properties.getSeed();
|
||||
int minHeight = properties.getMinHeight();
|
||||
int maxHeight = properties.getMaxHeight();
|
||||
|
||||
// 1. Check the exact center first
|
||||
Optional<Either<Vector3Int, Vector2Int>> centerResult = check(provider, seed, originX, originZ, step, filter, search3D, minHeight, maxHeight);
|
||||
if (centerResult.isPresent()) {
|
||||
return centerResult;
|
||||
}
|
||||
|
||||
// 2. Begin Parallel Square Spiral Search
|
||||
// We iterate rings sequentially to guarantee finding the *nearest* result.
|
||||
// However, we process all points within a specific ring in parallel.
|
||||
for (int r = step; r <= radius; r += step) {
|
||||
final int currentRadius = r;
|
||||
final int minX = -currentRadius;
|
||||
final int maxX = currentRadius;
|
||||
final int minZ = -currentRadius;
|
||||
final int maxZ = currentRadius;
|
||||
|
||||
Stream<int[]> northSide = IntStream.iterate(minX, n -> n < maxX, n -> n + step)
|
||||
.mapToObj(x -> new int[]{x, minZ}); // Fixed Z (min), varying X
|
||||
|
||||
Stream<int[]> eastSide = IntStream.iterate(minZ, n -> n < maxZ, n -> n + step)
|
||||
.mapToObj(z -> new int[]{maxX, z}); // Fixed X (max), varying Z
|
||||
|
||||
Stream<int[]> southSide = IntStream.iterate(maxX, n -> n > minX, n -> n - step)
|
||||
.mapToObj(x -> new int[]{x, maxZ}); // Fixed Z (max), varying X
|
||||
|
||||
Stream<int[]> westSide = IntStream.iterate(maxZ, n -> n > minZ, n -> n - step)
|
||||
.mapToObj(z -> new int[]{minX, z}); // Fixed X (min), varying Z
|
||||
|
||||
Optional<Either<Vector3Int, Vector2Int>> ringResult = Stream.of(northSide, eastSide, southSide, westSide)
|
||||
.flatMap(Function.identity())
|
||||
.parallel()
|
||||
.map(coords -> check(
|
||||
provider,
|
||||
seed,
|
||||
originX + coords[0],
|
||||
originZ + coords[1],
|
||||
step,
|
||||
filter,
|
||||
search3D,
|
||||
minHeight,
|
||||
maxHeight
|
||||
))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.findFirst(); // findFirst() respects encounter order (North -> East -> South -> West)
|
||||
|
||||
if (ringResult.isPresent()) {
|
||||
return ringResult;
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to check a specific coordinate column or point.
|
||||
* This logic is executed inside the worker threads.
|
||||
*/
|
||||
private static Optional<Either<Vector3Int, Vector2Int>> check(
|
||||
BiomeProvider provider,
|
||||
long seed,
|
||||
int x,
|
||||
int z,
|
||||
int step,
|
||||
Predicate<Biome> filter,
|
||||
boolean search3D,
|
||||
int minHeight,
|
||||
int maxHeight
|
||||
) {
|
||||
if (search3D) {
|
||||
// Iterate from bottom to top of the world using the step
|
||||
for (int y = minHeight; y < maxHeight; y += step) {
|
||||
if (filter.test(provider.getBiome(x, y, z, seed))) {
|
||||
return Optional.of(Either.left(Vector3Int.of(x, y, z)));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
} else {
|
||||
// 2D Mode: Check only the base biome
|
||||
// We use a flatMap approach here to be safe with Optionals inside the stream
|
||||
return provider.getBaseBiome(x, z, seed)
|
||||
.filter(filter)
|
||||
.map(b -> Either.right(Vector2Int.of(x, z)));
|
||||
}
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
package com.dfsek.terra.addons.commands.locate;
|
||||
|
||||
|
||||
import com.dfsek.seismic.type.vector.Vector2Int;
|
||||
import com.dfsek.seismic.type.vector.Vector3Int;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.component.DefaultValue;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.description.Description;
|
||||
import org.incendo.cloud.parser.standard.IntegerParser;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
import com.dfsek.terra.api.command.CommandSender;
|
||||
import com.dfsek.terra.api.command.arguments.RegistryArgument;
|
||||
import com.dfsek.terra.api.entity.Entity;
|
||||
import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent;
|
||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||
import com.dfsek.terra.api.registry.Registry;
|
||||
import com.dfsek.terra.api.util.generic.either.Either;
|
||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
import com.dfsek.terra.api.world.World;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public class LocateCommandAddon implements AddonInitializer {
|
||||
@Inject
|
||||
private Platform platform;
|
||||
|
||||
@Inject
|
||||
private BaseAddon addon;
|
||||
|
||||
private static Registry<Biome> getBiomeRegistry(CommandContext<CommandSender> sender) {
|
||||
return sender.sender().getEntity().orElseThrow().world().getPack().getRegistry(Biome.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
platform.getEventManager()
|
||||
.getHandler(FunctionalEventHandler.class)
|
||||
.register(addon, CommandRegistrationEvent.class)
|
||||
.then(event -> {
|
||||
CommandManager<CommandSender> manager = event.getCommandManager();
|
||||
manager.command(
|
||||
manager.commandBuilder("search", Description.of("Locate things in the world"))
|
||||
.literal("biome")
|
||||
// Argument 1: The Biome to search for
|
||||
.argument(RegistryArgument.builder("biome",
|
||||
LocateCommandAddon::getBiomeRegistry,
|
||||
TypeKey.of(Biome.class)))
|
||||
// Argument 2: Radius (Optional, default 5000)
|
||||
.optional("radius", IntegerParser.integerParser(100), DefaultValue.constant(5000))
|
||||
// Argument 3: Step/Resolution (Optional, default 16)
|
||||
.optional("step", IntegerParser.integerParser(1), DefaultValue.constant(16))
|
||||
// Flag: Toggle 3D search (e.g., --3d or -3)
|
||||
.flag(manager.flagBuilder("3d").withAliases("3").build())
|
||||
// Flag: Auto resolution mode (e.g., --auto or -a)
|
||||
.flag(manager.flagBuilder("auto").withAliases("a").build())
|
||||
.handler(context -> {
|
||||
// 1. Gather Context & Arguments
|
||||
Biome targetBiome = context.get("biome");
|
||||
Entity sender = context.sender().getEntity().orElseThrow(
|
||||
() -> new Error("Only entities can run this command."));
|
||||
World world = sender.world();
|
||||
|
||||
// Fetch properties needed for the locator
|
||||
int radius = context.get("radius");
|
||||
boolean search3D = context.flags().hasFlag("3d");
|
||||
boolean autoMode = context.flags().hasFlag("auto");
|
||||
|
||||
// 2. Determine Initial Step
|
||||
// If Auto: Start at radius / 2 (very coarse check).
|
||||
// If Manual: Use provided step.
|
||||
int stepArg = context.get("step");
|
||||
int currentStep = autoMode ? Integer.highestOneBit(radius - 1) : stepArg;
|
||||
|
||||
// Notify player
|
||||
String modeMsg = autoMode ? " (Auto Mode)" : " (Step: " + currentStep + ")";
|
||||
context.sender().sendMessage(
|
||||
"Searching for " + targetBiome.getID() + " within " + radius + " blocks" + modeMsg + "...");
|
||||
|
||||
Optional<Either<Vector3Int, Vector2Int>> result;
|
||||
|
||||
// 3. Execute Search Loop
|
||||
while(true) {
|
||||
result = BiomeLocator.search(
|
||||
world.getBiomeProvider(),
|
||||
world,
|
||||
sender.position().getFloorX(),
|
||||
sender.position().getFloorZ(),
|
||||
radius,
|
||||
currentStep,
|
||||
found -> found.equals(targetBiome), // Match specific biome instance
|
||||
search3D
|
||||
);
|
||||
|
||||
// Exit Conditions:
|
||||
// 1. Found a result
|
||||
if(result.isPresent()) {
|
||||
break;
|
||||
}
|
||||
// 2. Not in auto mode (only run once)
|
||||
if(!autoMode) {
|
||||
break;
|
||||
}
|
||||
// 3. We just ran a search at step arg and failed (lowest resolution)
|
||||
if(currentStep <= stepArg) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reduce step for next iteration (Adaptive Search)
|
||||
currentStep /= 2;
|
||||
context.sender().sendMessage("No result found, refining search (Step: " + currentStep + ")...");
|
||||
}
|
||||
|
||||
// 4. Handle Result
|
||||
if(result.isPresent()) {
|
||||
Either<Vector3Int, Vector2Int> location = result.get();
|
||||
String coords;
|
||||
|
||||
if(location.hasLeft()) { // 3D Result
|
||||
Vector3Int vec = location.getLeft().get();
|
||||
coords = String.format("%d, %d, %d", vec.getX(), vec.getY(), vec.getZ());
|
||||
} else { // 2D Result
|
||||
Vector2Int vec = location.getRight().get();
|
||||
coords = String.format("%d, ~, %d", vec.getX(), vec.getZ());
|
||||
}
|
||||
|
||||
context.sender().sendMessage("Found " + targetBiome.getID() + " at [" + coords + "]");
|
||||
} else {
|
||||
context.sender().sendMessage("Could not find " + targetBiome.getID() + " within " + radius + " blocks.");
|
||||
}
|
||||
})
|
||||
.permission("terra.locate.biome")
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
schema-version: 1
|
||||
contributors:
|
||||
- Terra contributors
|
||||
id: command-locate
|
||||
version: @VERSION@
|
||||
entrypoints:
|
||||
- "com.dfsek.terra.addons.commands.locate.LocateCommandAddon"
|
||||
website:
|
||||
issues: https://github.com/PolyhedralDev/Terra/issues
|
||||
source: https://github.com/PolyhedralDev/Terra
|
||||
docs: https://terra.polydev.org
|
||||
license: MIT License
|
||||
+8
@@ -8,6 +8,7 @@
|
||||
package com.dfsek.terra.addons.biome;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.dfsek.terra.api.properties.Context;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
@@ -25,6 +26,7 @@ public class UserDefinedBiome implements Biome {
|
||||
private final Set<String> tags;
|
||||
|
||||
private final Context context = new Context();
|
||||
private final int intID;
|
||||
|
||||
public UserDefinedBiome(PlatformBiome vanilla, BiomeTemplate config) {
|
||||
this.vanilla = vanilla;
|
||||
@@ -32,6 +34,7 @@ public class UserDefinedBiome implements Biome {
|
||||
this.config = config;
|
||||
this.color = config.getColor();
|
||||
this.tags = config.getTags();
|
||||
this.intID = INT_ID_COUNTER.getAndIncrement();
|
||||
tags.add("BIOME:" + id);
|
||||
tags.add("ALL");
|
||||
}
|
||||
@@ -61,6 +64,11 @@ public class UserDefinedBiome implements Biome {
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntID() {
|
||||
return intID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return id;
|
||||
|
||||
+19
-12
@@ -2,18 +2,11 @@ package com.dfsek.terra.addons.feature.distributor.distributors;
|
||||
|
||||
import com.dfsek.seismic.algorithms.hashing.HashingFunctions;
|
||||
import com.dfsek.seismic.math.integer.IntegerFunctions;
|
||||
|
||||
import java.util.random.RandomGenerator;
|
||||
import java.util.random.RandomGeneratorFactory;
|
||||
|
||||
import com.dfsek.terra.api.structure.feature.Distributor;
|
||||
|
||||
|
||||
public class PaddedGridDistributor implements Distributor {
|
||||
private final int width;
|
||||
|
||||
private final int cellWidth;
|
||||
|
||||
private final int salt;
|
||||
|
||||
public PaddedGridDistributor(int width, int padding, int salt) {
|
||||
@@ -27,12 +20,26 @@ public class PaddedGridDistributor implements Distributor {
|
||||
int cellX = Math.floorDiv(x, cellWidth);
|
||||
int cellZ = Math.floorDiv(z, cellWidth);
|
||||
|
||||
RandomGenerator random = RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("Xoroshiro128PlusPlus").create(
|
||||
(HashingFunctions.murmur64(IntegerFunctions.squash(cellX, cellZ)) ^ seed) + salt);
|
||||
int localX = x - (cellX * cellWidth);
|
||||
int localZ = z - (cellZ * cellWidth);
|
||||
|
||||
int pointX = random.nextInt(width) + cellX * cellWidth;
|
||||
int pointZ = random.nextInt(width) + cellZ * cellWidth;
|
||||
if (localX >= width || localZ >= width) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return x == pointX && z == pointZ;
|
||||
long hash = HashingFunctions.murmur64(IntegerFunctions.squash(cellX, cellZ)) ^ seed;
|
||||
hash += salt;
|
||||
|
||||
hash = HashingFunctions.splitMix64(hash);
|
||||
int targetX = (int) ((hash & 0x7FFFFFFFFFFFFFFFL) % width);
|
||||
|
||||
if (localX != targetX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hash = HashingFunctions.splitMix64(hash);
|
||||
int targetZ = (int) ((hash & 0x7FFFFFFFFFFFFFFFL) % width);
|
||||
|
||||
return localZ == targetZ;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,13 +3,13 @@ package com.dfsek.terra.addons.biome.pipeline.image.config.converter.mapping;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
|
||||
import com.dfsek.terra.addons.image.config.ColorLoader.ColorString;
|
||||
import com.dfsek.terra.addons.image.converter.mapping.ColorMapping;
|
||||
import com.dfsek.terra.addons.image.util.MapUtil;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class DefinedPipelineBiomeColorMappingTemplate implements ObjectTemplate<ColorMapping<PipelineBiome>> {
|
||||
|
||||
|
||||
@@ -12,12 +12,13 @@ import java.util.function.Consumer;
|
||||
import com.dfsek.terra.api.Handle;
|
||||
import com.dfsek.terra.api.block.BlockType;
|
||||
import com.dfsek.terra.api.block.state.properties.Property;
|
||||
import com.dfsek.terra.api.data.Extendable;
|
||||
|
||||
|
||||
/**
|
||||
* Contains basic data about a {@link BlockType} in the world
|
||||
*/
|
||||
public interface BlockState extends Handle {
|
||||
public interface BlockState extends Handle, Extendable {
|
||||
|
||||
/**
|
||||
* Whether this {@link BlockState} matches another.
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.dfsek.terra.api.block.state;
|
||||
|
||||
import com.dfsek.terra.api.data.ExtendedData;
|
||||
|
||||
|
||||
public interface BlockStateExtended extends BlockState {
|
||||
/**
|
||||
* Gets the BlockData.
|
||||
*
|
||||
* @return BlockData of this BlockStateExtended
|
||||
*/
|
||||
ExtendedData getData();
|
||||
|
||||
/**
|
||||
* Sets the BlockData.
|
||||
*
|
||||
* @param data BlockData to set
|
||||
*
|
||||
* @return New BlockStateExtended with the given BlockData
|
||||
*/
|
||||
BlockStateExtended setData(ExtendedData data);
|
||||
|
||||
/**
|
||||
* Gets the BlockState.
|
||||
*
|
||||
* @return Raw BlockState of this BlockStateExtended
|
||||
*/
|
||||
BlockState getState();
|
||||
|
||||
@Override
|
||||
default boolean isExtended() { return true; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.data;
|
||||
|
||||
public interface Extendable {
|
||||
/**
|
||||
* Get whether this BlockState is an extended state.
|
||||
* Extended states are states that contain extra data not normally present in a BlockState.
|
||||
*
|
||||
* @return Whether this state is extended.
|
||||
*/
|
||||
default boolean isExtended() { return false; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.dfsek.terra.api.data;
|
||||
|
||||
import com.dfsek.terra.api.Handle;
|
||||
|
||||
|
||||
public interface ExtendedData extends Handle {
|
||||
String toString();
|
||||
}
|
||||
@@ -8,7 +8,8 @@
|
||||
package com.dfsek.terra.api.entity;
|
||||
|
||||
import com.dfsek.terra.api.Handle;
|
||||
import com.dfsek.terra.api.data.Extendable;
|
||||
|
||||
|
||||
public interface EntityType extends Handle {
|
||||
public interface EntityType extends Handle, Extendable {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.dfsek.terra.api.entity;
|
||||
|
||||
import com.dfsek.terra.api.data.ExtendedData;
|
||||
|
||||
|
||||
public interface EntityTypeExtended extends EntityType {
|
||||
/**
|
||||
* Gets the BlockData.
|
||||
*
|
||||
* @return BlockData of this EntityTypeExtended
|
||||
*/
|
||||
ExtendedData getData();
|
||||
|
||||
/**
|
||||
* Sets the BlockData.
|
||||
*
|
||||
* @param data BlockData to set
|
||||
*
|
||||
* @return New EntityTypeExtended with the given BlockData
|
||||
*/
|
||||
EntityTypeExtended setData(ExtendedData data);
|
||||
|
||||
/**
|
||||
* Gets the EntityType.
|
||||
*
|
||||
* @return Raw EntityType of this EntityTypeExtended
|
||||
*/
|
||||
EntityType getType();
|
||||
|
||||
@Override
|
||||
default boolean isExtended() { return true; }
|
||||
}
|
||||
+2
-2
@@ -7,14 +7,14 @@
|
||||
|
||||
package com.dfsek.terra.api.structure.configured;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Experimental;
|
||||
|
||||
import com.dfsek.terra.api.registry.key.StringIdentifiable;
|
||||
import com.dfsek.terra.api.structure.Structure;
|
||||
import com.dfsek.terra.api.structure.StructureSpawn;
|
||||
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.util.range.Range;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Experimental;
|
||||
|
||||
|
||||
@Experimental
|
||||
public interface ConfiguredStructure extends StringIdentifiable {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.dfsek.terra.api.util.collection;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
|
||||
import com.dfsek.seismic.util.UnsafeUtils;
|
||||
|
||||
|
||||
public class TriStateIntCache {
|
||||
public static final long STATE_UNSET = 0L;
|
||||
public static final long STATE_FALSE = 1L;
|
||||
public static final long STATE_TRUE = 2L;
|
||||
|
||||
private static final long BIT_MASK = 3L;
|
||||
private final long[] data;
|
||||
|
||||
private static final VarHandle ARRAY_HANDLE = MethodHandles.arrayElementVarHandle(long[].class);
|
||||
|
||||
private static int getOptimalMaxKeys(int requestedKeys) {
|
||||
// 192 keys fill the first cache line exactly (along with the 16-byte header)
|
||||
if (requestedKeys <= 192) {
|
||||
return 192;
|
||||
}
|
||||
|
||||
// For every additional line, we fit 256 keys (64 bytes * 4 keys/byte)
|
||||
// We calculate the overflow beyond 192, round up to the nearest 256, and add it back.
|
||||
int overflow = requestedKeys - 192;
|
||||
int chunks = (overflow + 255) >>> 8; // Fast ceil division by 256
|
||||
|
||||
return 192 + (chunks << 8); // chunks * 256
|
||||
}
|
||||
|
||||
public TriStateIntCache(int maxKeySize) {
|
||||
this.data = new long[(getOptimalMaxKeys(maxKeySize) + 31) >>> 5];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the cache state without any allocation.
|
||||
*
|
||||
* @return STATE_UNSET (0), STATE_FALSE (1), or STATE_TRUE (2)
|
||||
*/
|
||||
public long get(int key) {
|
||||
long offset = UnsafeUtils.LONG_ARRAY_BASE + ((long)(key >>> 5) << UnsafeUtils.LONG_ARRAY_SHIFT);
|
||||
long currentWord = UnsafeUtils.UNSAFE.getLong(data, offset);
|
||||
return (currentWord >>> ((key << 1) & 63)) & BIT_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value safely. Handles race conditions internally.
|
||||
*/
|
||||
public void set(int key, boolean value) {
|
||||
int index = key >>> 5;
|
||||
int shift = (key << 1) & 63;
|
||||
|
||||
long targetWord = (value ? STATE_TRUE : STATE_FALSE) << shift;
|
||||
|
||||
long current;
|
||||
do {
|
||||
current = (long) ARRAY_HANDLE.getVolatile(data, index);
|
||||
|
||||
if (((current >>> shift) & BIT_MASK) != STATE_UNSET) {
|
||||
return;
|
||||
}
|
||||
|
||||
} while (!ARRAY_HANDLE.compareAndSet(data, index, current, current | targetWord));
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ public class ConstantRange implements Range {
|
||||
private int max;
|
||||
|
||||
public ConstantRange(int min, int max) {
|
||||
if(min >= max) throw new IllegalArgumentException("Minimum must not be greater than or equal to maximum!");
|
||||
if(min > max) throw new IllegalArgumentException("Minimum must not be greater than maximum!");
|
||||
this.max = max;
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ package com.dfsek.terra.api.world.biome;
|
||||
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.dfsek.terra.api.properties.PropertyHolder;
|
||||
import com.dfsek.terra.api.registry.key.StringIdentifiable;
|
||||
@@ -18,6 +19,7 @@ import com.dfsek.terra.api.registry.key.StringIdentifiable;
|
||||
* Represents a Terra biome
|
||||
*/
|
||||
public interface Biome extends PropertyHolder, StringIdentifiable {
|
||||
AtomicInteger INT_ID_COUNTER = new AtomicInteger(0);
|
||||
|
||||
/**
|
||||
* Gets the platform biome this custom biome delegates to.
|
||||
@@ -39,4 +41,12 @@ public interface Biome extends PropertyHolder, StringIdentifiable {
|
||||
* @return A {@link Set} of String tags this biome holds.
|
||||
*/
|
||||
Set<String> getTags();
|
||||
|
||||
|
||||
/**
|
||||
* Get the numeric ID of this biome, generated at registration time
|
||||
*
|
||||
* @return The numeric ID.
|
||||
*/
|
||||
int getIntID();
|
||||
}
|
||||
|
||||
-68
@@ -1,68 +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.loaders.config;
|
||||
|
||||
import com.dfsek.tectonic.api.depth.DepthTracker;
|
||||
import com.dfsek.tectonic.api.exception.LoadException;
|
||||
import com.dfsek.tectonic.api.loader.ConfigLoader;
|
||||
import com.dfsek.tectonic.api.loader.type.TypeLoader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.nio.file.Files;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.properties.Properties;
|
||||
|
||||
|
||||
/*
|
||||
* @deprecated Use the Image and ImageLoader class provided by the library-image addon instead. This is subject to removal in v7.
|
||||
*/
|
||||
@Deprecated
|
||||
public class BufferedImageLoader implements TypeLoader<BufferedImage> {
|
||||
|
||||
private final ConfigPack pack;
|
||||
|
||||
public BufferedImageLoader(ConfigPack pack) {
|
||||
this.pack = pack;
|
||||
if(!pack.getContext().has(ImageCache.class))
|
||||
pack.getContext().put(new ImageCache(new ConcurrentHashMap<>()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
|
||||
throws LoadException {
|
||||
return pack.getContext().get(ImageCache.class).map.computeIfAbsent((String) c, s -> {
|
||||
try {
|
||||
return ImageIO.read(Files.newInputStream(pack.getRootPath().resolve(s)));
|
||||
} catch(IOException e) {
|
||||
throw new LoadException("Unable to load image", e, depthTracker);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache prevents configs from loading the same image multiple times into memory
|
||||
*/
|
||||
private record ImageCache(ConcurrentHashMap<String, BufferedImage> map) implements Properties {
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -33,7 +33,6 @@ 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;
|
||||
@@ -77,7 +76,6 @@ 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.util.provider.ChunkGeneratorProvider;
|
||||
import com.dfsek.terra.config.loaders.GenericTemplateSupplierLoader;
|
||||
import com.dfsek.terra.config.loaders.config.BufferedImageLoader;
|
||||
import com.dfsek.terra.config.preprocessor.MetaListLikePreprocessor;
|
||||
import com.dfsek.terra.config.preprocessor.MetaMapPreprocessor;
|
||||
import com.dfsek.terra.config.preprocessor.MetaNumberPreprocessor;
|
||||
@@ -273,8 +271,7 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
|
||||
@Override
|
||||
public void register(TypeRegistry registry) {
|
||||
registry.registerLoader(ConfigType.class, configTypeRegistry)
|
||||
.registerLoader(BufferedImage.class, new BufferedImageLoader(this));
|
||||
registry.registerLoader(ConfigType.class, configTypeRegistry);
|
||||
registryMap.forEach(registry::registerLoader);
|
||||
shortcuts.forEach(registry::registerLoader); // overwrite with delegated shortcuts if present
|
||||
}
|
||||
|
||||
+4
-2
@@ -31,6 +31,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
@@ -51,11 +52,12 @@ import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
private static final Entry<?> NULL = new Entry<>(null);
|
||||
private final Map<RegistryKey, Entry<T>> objects;
|
||||
private final ListMultimap<String, Pair<RegistryKey, Entry<T>>> objectIDs = Multimaps.newListMultimap(new HashMap<>(), ArrayList::new);
|
||||
private final ListMultimap<String, Pair<RegistryKey, Entry<T>>> objectIDs = Multimaps.newListMultimap(new ConcurrentHashMap<>(),
|
||||
ArrayList::new);
|
||||
private final TypeKey<T> typeKey;
|
||||
|
||||
public OpenRegistryImpl(TypeKey<T> typeKey) {
|
||||
this(new HashMap<>(), typeKey);
|
||||
this(new ConcurrentHashMap<>(), typeKey);
|
||||
}
|
||||
|
||||
protected OpenRegistryImpl(Map<RegistryKey, Entry<T>> init, TypeKey<T> typeKey) {
|
||||
|
||||
+4
-4
@@ -21,8 +21,8 @@ import java.io.IOException;
|
||||
import java.io.Serial;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.dfsek.terra.api.Platform;
|
||||
@@ -41,12 +41,12 @@ public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
|
||||
super(TypeKey.of(ConfigPack.class));
|
||||
}
|
||||
|
||||
public void loadAll(Platform platform) throws IOException, PackLoadFailuresException {
|
||||
public synchronized void loadAll(Platform platform) throws IOException, PackLoadFailuresException {
|
||||
Path packsDirectory = platform.getDataFolder().toPath().resolve("packs");
|
||||
Files.createDirectories(packsDirectory);
|
||||
List<Exception> failedLoads = new ArrayList<>();
|
||||
List<Exception> failedLoads = new CopyOnWriteArrayList<>();
|
||||
try(Stream<Path> packs = Files.list(packsDirectory)) {
|
||||
packs.forEach(path -> {
|
||||
packs.parallel().forEach(path -> {
|
||||
try {
|
||||
ConfigPack pack = new ConfigPackImpl(path, platform);
|
||||
registerChecked(pack.getRegistryKey(), pack);
|
||||
|
||||
@@ -19,4 +19,5 @@ script:
|
||||
max-recursion: 1000
|
||||
ignored-resources:
|
||||
# - "addons"
|
||||
# - "packs"
|
||||
# - "packs"
|
||||
# - "metapacks"
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Resource files
|
||||
|
||||
Current mapping version: je 1.21.4 to be 1.21.50
|
||||
Current mapping version: je 1.21.9 to be 1.21.111
|
||||
|
||||
- `mapping/biomes.json` and `mapping/items.json` obtain from [GeyserMC/mappings](https://github.com/GeyserMC/mappings).
|
||||
- `mapping/blocks.json` generated by using [GeyserMC/mappings-generator](https://github.com/GeyserMC/mappings-generator), and it's origin name is `generator_blocks.json`.
|
||||
- `je_block_default_states.json` converted from [Block state values](https://zh.minecraft.wiki/w/Module:Block_state_values).
|
||||
- `mapping/biomes.json` and `mapping/items.json` are obtained from [GeyserMC/mappings](https://github.com/GeyserMC/mappings).
|
||||
- `mapping/blocks.json` is obtained from [GeyserMC/mappings-generator](https://github.com/GeyserMC/mappings-generator) (path: `https://github.com/GeyserMC/mappings-generator/blob/master/generator_blocks.json`).
|
||||
- `je_blocks.json` is obtained from [misode/mcmeta](https://github.com/misode/mcmeta) (path: `https://github.com/misode/mcmeta/blob/<version>-summary/blocks/data.json`).
|
||||
|
||||
@@ -15,6 +15,10 @@ val geyserMappings: Configuration by configurations.register("geyserMappings") {
|
||||
isCanBeConsumed = false
|
||||
}
|
||||
|
||||
val mcmeta: Configuration by configurations.register("mcmeta") {
|
||||
isCanBeConsumed = false
|
||||
}
|
||||
|
||||
dependencies {
|
||||
shadedApi(project(":common:implementation:base"))
|
||||
|
||||
@@ -25,6 +29,8 @@ dependencies {
|
||||
geyserMappings("GeyserMC.mappings", "items", Versions.Allay.mappings, ext = "json")
|
||||
geyserMappings("GeyserMC.mappings", "biomes", Versions.Allay.mappings, ext = "json")
|
||||
geyserMappings("GeyserMC.mappings-generator", "generator_blocks", Versions.Allay.mappingsGenerator, ext = "json")
|
||||
|
||||
mcmeta("misode.mcmeta", "blocks/data", Versions.Allay.mcmeta, ext = "json")
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
@@ -34,4 +40,7 @@ tasks.processResources {
|
||||
// rather jank, but whatever
|
||||
rename("(?:generator_)?([^-]+)-(.*)\\.json", "$1.json")
|
||||
}
|
||||
from(mcmeta) {
|
||||
rename("data-(.*)\\.json", "je_blocks.json")
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package com.dfsek.terra.allay;
|
||||
import com.dfsek.tectonic.api.TypeRegistry;
|
||||
import com.dfsek.tectonic.api.depth.DepthTracker;
|
||||
import com.dfsek.tectonic.api.exception.LoadException;
|
||||
import org.allaymc.api.registry.Registries;
|
||||
import org.allaymc.api.server.Server;
|
||||
import org.allaymc.api.world.biome.BiomeId;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
@@ -45,7 +45,7 @@ public class AllayPlatform extends AbstractPlatform {
|
||||
getConfigRegistry().get(wrapper.getConfigPack().getRegistryKey()).ifPresent(pack -> {
|
||||
wrapper.setConfigPack(pack);
|
||||
var dimension = wrapper.getAllayWorldGenerator().getDimension();
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().info(
|
||||
TerraAllayPlugin.instance.getPluginLogger().info(
|
||||
"Replaced pack in chunk generator for world {}",
|
||||
dimension.getWorld().getWorldData().getDisplayName() + ":" + dimension.getDimensionInfo().dimensionId()
|
||||
);
|
||||
@@ -72,7 +72,7 @@ public class AllayPlatform extends AbstractPlatform {
|
||||
|
||||
@Override
|
||||
public @NotNull File getDataFolder() {
|
||||
return TerraAllayPlugin.INSTANCE.getPluginContainer().dataFolder().toFile();
|
||||
return TerraAllayPlugin.instance.getPluginContainer().dataFolder().toFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,6 +89,6 @@ public class AllayPlatform extends AbstractPlatform {
|
||||
|
||||
protected AllayBiome parseBiome(String id, DepthTracker depthTracker) throws LoadException {
|
||||
if(!id.startsWith("minecraft:")) throw new LoadException("Invalid biome identifier " + id, depthTracker);
|
||||
return new AllayBiome(BiomeId.fromId(Mapping.biomeIdJeToBe(id)));
|
||||
return new AllayBiome(Registries.BIOMES.getByK1(Mapping.biomeIdJeToBe(id)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.dfsek.terra.allay;
|
||||
|
||||
import org.allaymc.api.utils.HashUtils;
|
||||
import org.allaymc.api.utils.hash.HashUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
@@ -10,12 +10,25 @@ import java.util.TreeMap;
|
||||
* @author daoge_cmd
|
||||
*/
|
||||
public class JeBlockState {
|
||||
|
||||
protected final String identifier;
|
||||
protected final TreeMap<String, String> properties;
|
||||
|
||||
protected int hash = Integer.MAX_VALUE;
|
||||
|
||||
private JeBlockState(String data) {
|
||||
String[] strings = data.replace("[", ",").replace("]", ",").replace(" ", "").split(",");
|
||||
// TODO: support block state with nbt (identifier[properties]{nbt}), for now we just ignore it
|
||||
int braceIndex = data.indexOf('{');
|
||||
if(braceIndex != -1) {
|
||||
data = data.substring(0, braceIndex);
|
||||
}
|
||||
|
||||
String[] strings = data
|
||||
.replace("[", ",")
|
||||
.replace("]", ",")
|
||||
.replace(" ", "")
|
||||
.split(",");
|
||||
|
||||
this.identifier = strings[0];
|
||||
this.properties = new TreeMap<>();
|
||||
if(strings.length > 1) {
|
||||
|
||||
@@ -8,19 +8,17 @@ import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import org.allaymc.api.block.type.BlockState;
|
||||
import org.allaymc.api.block.type.BlockStateSafeGetter;
|
||||
import org.allaymc.api.block.type.BlockStateGetter;
|
||||
import org.allaymc.api.block.type.BlockTypes;
|
||||
import org.allaymc.api.item.type.ItemType;
|
||||
import org.allaymc.api.item.type.ItemTypeSafeGetter;
|
||||
import org.allaymc.api.item.type.ItemTypeGetter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -37,11 +35,11 @@ public final class Mapping {
|
||||
.registerTypeAdapterFactory(new IgnoreFailureTypeAdapterFactory())
|
||||
.create();
|
||||
|
||||
private static final Map<String, Map<String, String>> JE_BLOCK_DEFAULT_PROPERTIES = new Object2ObjectOpenHashMap<>();
|
||||
private static final Map<BlockState, JeBlockState> BE_BLOCK_STATE_TO_JE = new Object2ObjectOpenHashMap<>();
|
||||
private static final Map<Integer, BlockState> JE_BLOCK_STATE_HASH_TO_BE = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, ItemType<?>> JE_ITEM_ID_TO_BE = new Object2ObjectOpenHashMap<>();
|
||||
private static final Map<String, Integer> JE_BIOME_ID_TO_BE = new Object2IntOpenHashMap<>();
|
||||
private static final Map<String, Map<String, String>> JE_BLOCK_DEFAULT_PROPERTIES = new HashMap<>();
|
||||
private static final Map<BlockState, JeBlockState> BE_BLOCK_STATE_TO_JE = new HashMap<>();
|
||||
private static final Map<Integer, BlockState> JE_BLOCK_STATE_HASH_TO_BE = new HashMap<>();
|
||||
private static final Map<String, ItemType<?>> JE_ITEM_ID_TO_BE = new HashMap<>();
|
||||
private static final Map<String, Integer> JE_BIOME_ID_TO_BE = new HashMap<>();
|
||||
|
||||
private static final BlockState BE_AIR_STATE = BlockTypes.AIR.getDefaultState();
|
||||
|
||||
@@ -59,7 +57,7 @@ public final class Mapping {
|
||||
public static BlockState blockStateJeToBe(JeBlockState jeBlockState) {
|
||||
BlockState result = JE_BLOCK_STATE_HASH_TO_BE.get(jeBlockState.getHash());
|
||||
if(result == null) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().warn("Failed to find be block state for {}", jeBlockState);
|
||||
TerraAllayPlugin.instance.getPluginLogger().warn("Failed to find be block state for {}", jeBlockState);
|
||||
return BE_AIR_STATE;
|
||||
}
|
||||
return result;
|
||||
@@ -83,10 +81,19 @@ public final class Mapping {
|
||||
return JE_BIOME_ID_TO_BE.get(jeBiomeId);
|
||||
}
|
||||
|
||||
public static String dimensionIdBeToJe(String beDimensionId) {
|
||||
return switch(beDimensionId) {
|
||||
case "overworld" -> "minecraft:overworld";
|
||||
case "nether" -> "minecraft:the_nether";
|
||||
case "the_end" -> "minecraft:the_end";
|
||||
default -> beDimensionId;
|
||||
};
|
||||
}
|
||||
|
||||
public static Map<String, String> getJeBlockDefaultProperties(String jeBlockIdentifier) {
|
||||
var defaultProperties = JE_BLOCK_DEFAULT_PROPERTIES.get(jeBlockIdentifier);
|
||||
if(defaultProperties == null) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().warn("Failed to find default properties for {}", jeBlockIdentifier);
|
||||
TerraAllayPlugin.instance.getPluginLogger().warn("Failed to find default properties for {}", jeBlockIdentifier);
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@@ -100,7 +107,7 @@ public final class Mapping {
|
||||
private static boolean initBiomeMapping() {
|
||||
try(InputStream stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/biomes.json")) {
|
||||
if(stream == null) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().error("biomes mapping not found");
|
||||
TerraAllayPlugin.instance.getPluginLogger().error("biomes mapping not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -108,7 +115,7 @@ public final class Mapping {
|
||||
});
|
||||
mappings.forEach((javaId, mapping) -> JE_BIOME_ID_TO_BE.put(javaId, mapping.bedrockId()));
|
||||
} catch(IOException e) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Failed to load biomes mapping", e);
|
||||
TerraAllayPlugin.instance.getPluginLogger().error("Failed to load biomes mapping", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -117,21 +124,21 @@ public final class Mapping {
|
||||
private static boolean initItemMapping() {
|
||||
try(InputStream stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/items.json")) {
|
||||
if(stream == null) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().error("items mapping not found");
|
||||
TerraAllayPlugin.instance.getPluginLogger().error("items mapping not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<String, ItemMapping> mappings = from(stream, new TypeToken<>() {
|
||||
});
|
||||
mappings.forEach((javaId, mapping) -> {
|
||||
ItemType<?> itemType = ItemTypeSafeGetter
|
||||
ItemType<?> itemType = ItemTypeGetter
|
||||
.name(mapping.bedrockId())
|
||||
.meta(mapping.bedrockData())
|
||||
.itemType();
|
||||
JE_ITEM_ID_TO_BE.put(javaId, itemType);
|
||||
});
|
||||
} catch(IOException e) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Failed to load items mapping", e);
|
||||
TerraAllayPlugin.instance.getPluginLogger().error("Failed to load items mapping", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -140,7 +147,7 @@ public final class Mapping {
|
||||
private static boolean initBlockStateMapping() {
|
||||
try(InputStream stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/blocks.json")) {
|
||||
if(stream == null) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().error("blocks mapping not found");
|
||||
TerraAllayPlugin.instance.getPluginLogger().error("blocks mapping not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -154,22 +161,28 @@ public final class Mapping {
|
||||
JE_BLOCK_STATE_HASH_TO_BE.put(jeState.getHash(), beState);
|
||||
});
|
||||
} catch(IOException e) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Failed to load blocks mapping", e);
|
||||
TerraAllayPlugin.instance.getPluginLogger().error("Failed to load blocks mapping", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static boolean initJeBlockDefaultProperties() {
|
||||
try(InputStream stream = Mapping.class.getClassLoader().getResourceAsStream("je_block_default_states.json")) {
|
||||
try(InputStream stream = Mapping.class.getClassLoader().getResourceAsStream("je_blocks.json")) {
|
||||
if(stream == null) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().error("je_block_default_states.json not found");
|
||||
TerraAllayPlugin.instance.getPluginLogger().error("je_block_default_states.json not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<String, Map<String, String>> states = from(stream, new TypeToken<>() {
|
||||
Map<String, List<Map<String, ?>>> data = from(stream, new TypeToken<>() {
|
||||
});
|
||||
JE_BLOCK_DEFAULT_PROPERTIES.putAll(states);
|
||||
for(var entry : data.entrySet()) {
|
||||
JE_BLOCK_DEFAULT_PROPERTIES.put(
|
||||
"minecraft:" + entry.getKey(),
|
||||
(Map<String, String>) entry.getValue().get(1)
|
||||
);
|
||||
}
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -182,7 +195,7 @@ public final class Mapping {
|
||||
}
|
||||
|
||||
private static BlockState createBeBlockState(BlockMapping.BedrockState state) {
|
||||
BlockStateSafeGetter.Getter getter = BlockStateSafeGetter.name("minecraft:" + state.bedrockId());
|
||||
BlockStateGetter.Getter getter = BlockStateGetter.name("minecraft:" + state.bedrockId());
|
||||
if(state.state() != null) {
|
||||
convertValueType(state.state()).forEach(getter::property);
|
||||
}
|
||||
|
||||
@@ -15,38 +15,38 @@ import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent;
|
||||
*/
|
||||
public class TerraAllayPlugin extends Plugin {
|
||||
|
||||
public static TerraAllayPlugin INSTANCE;
|
||||
public static AllayPlatform PLATFORM;
|
||||
public static TerraAllayPlugin instance;
|
||||
public static AllayPlatform platform;
|
||||
|
||||
{
|
||||
INSTANCE = this;
|
||||
TerraAllayPlugin.instance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
pluginLogger.info("Starting Terra...");
|
||||
this.pluginLogger.info("Starting Terra...");
|
||||
|
||||
pluginLogger.info("Loading mapping...");
|
||||
this.pluginLogger.info("Loading mapping...");
|
||||
Mapping.init();
|
||||
|
||||
pluginLogger.info("Initializing allay platform...");
|
||||
PLATFORM = new AllayPlatform();
|
||||
PLATFORM.getEventManager().callEvent(new PlatformInitializationEvent());
|
||||
this.pluginLogger.info("Initializing allay platform...");
|
||||
TerraAllayPlugin.platform = new AllayPlatform();
|
||||
TerraAllayPlugin.platform.getEventManager().callEvent(new PlatformInitializationEvent());
|
||||
// TODO: adapt command manager
|
||||
|
||||
pluginLogger.info("Registering generator...");
|
||||
this.pluginLogger.info("Registering generator...");
|
||||
Registries.WORLD_GENERATOR_FACTORIES.register("TERRA", preset -> {
|
||||
try {
|
||||
AllayGeneratorWrapper wrapper = new AllayGeneratorWrapper(preset);
|
||||
AllayPlatform.GENERATOR_WRAPPERS.add(wrapper);
|
||||
return wrapper.getAllayWorldGenerator();
|
||||
} catch(IllegalArgumentException e) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Fail to create world generator with preset: {}", preset, e);
|
||||
TerraAllayPlugin.instance.getPluginLogger().error("Fail to create world generator with preset: {}", preset, e);
|
||||
return Registries.WORLD_GENERATOR_FACTORIES.get("FLAT").apply("");
|
||||
}
|
||||
});
|
||||
|
||||
pluginLogger.info("Terra started");
|
||||
this.pluginLogger.info("Terra started");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,10 +61,10 @@ public class TerraAllayPlugin extends Plugin {
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
if(PLATFORM.reload()) {
|
||||
pluginLogger.info("Terra reloaded successfully.");
|
||||
if(TerraAllayPlugin.platform.reload()) {
|
||||
this.pluginLogger.info("Terra reloaded successfully.");
|
||||
} else {
|
||||
pluginLogger.error("Terra failed to reload.");
|
||||
this.pluginLogger.error("Terra failed to reload.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.dfsek.terra.allay.delegate;
|
||||
|
||||
import com.dfsek.seismic.type.vector.Vector3;
|
||||
import org.allaymc.api.blockentity.BlockEntity;
|
||||
|
||||
import com.dfsek.terra.allay.Mapping;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
|
||||
|
||||
/**
|
||||
* @author daoge_cmd
|
||||
*/
|
||||
public record AllayBlockEntity(BlockEntity allayBlockEntity) implements com.dfsek.terra.api.block.entity.BlockEntity {
|
||||
|
||||
@Override
|
||||
public boolean update(boolean applyPhysics) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3 getPosition() {
|
||||
var pos = this.allayBlockEntity.getPosition();
|
||||
return Vector3.of(pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return this.allayBlockEntity.getPosition().x();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return this.allayBlockEntity.getPosition().y();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return this.allayBlockEntity.getPosition().z();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState() {
|
||||
var allayBlockState = this.allayBlockEntity.getBlockState();
|
||||
return new AllayBlockState(allayBlockState, Mapping.blockStateBeToJe(this.allayBlockEntity.getBlockState()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return this.allayBlockEntity;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.dfsek.terra.allay.delegate;
|
||||
|
||||
import org.allaymc.api.block.tag.BlockTags;
|
||||
import org.allaymc.api.block.data.BlockTags;
|
||||
import org.allaymc.api.block.type.BlockType;
|
||||
|
||||
import com.dfsek.terra.allay.Mapping;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.dfsek.terra.allay.delegate;
|
||||
|
||||
import org.allaymc.api.block.data.BlockTags;
|
||||
import org.allaymc.api.block.property.type.BlockPropertyTypes;
|
||||
import org.allaymc.api.block.tag.BlockTags;
|
||||
import org.allaymc.api.block.type.BlockTypes;
|
||||
import org.allaymc.api.world.chunk.Chunk;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -21,6 +21,13 @@ public record AllayChunk(ServerWorld world, Chunk allayChunk) implements com.dfs
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, BlockState data, boolean physics) {
|
||||
var dimensionInfo = allayChunk.getDimensionInfo();
|
||||
if(x < 0 || x > 15 ||
|
||||
z < 0 || z > 15 ||
|
||||
y < dimensionInfo.minHeight() || y > dimensionInfo.maxHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AllayBlockState allayBlockState = (AllayBlockState) data;
|
||||
allayChunk.setBlockState(x, y, z, allayBlockState.allayBlockState());
|
||||
if(allayBlockState.containsWater() || allayChunk.getBlockState(x, y, z).getBlockType().hasBlockTag(BlockTags.WATER)) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.dfsek.terra.api.world.ServerWorld;
|
||||
|
||||
|
||||
/**
|
||||
* NOTICE: Entity is not supported currently, and this is a fake implementation.
|
||||
* TODO: Entity is not supported currently, and this is a fake implementation.
|
||||
*
|
||||
* @author daoge_cmd
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.dfsek.terra.allay.delegate;
|
||||
|
||||
import org.allaymc.api.block.data.BlockTags;
|
||||
import org.allaymc.api.block.property.type.BlockPropertyTypes;
|
||||
import org.allaymc.api.block.tag.BlockTags;
|
||||
import org.allaymc.api.block.type.BlockTypes;
|
||||
import org.allaymc.api.world.chunk.UnsafeChunk;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -26,6 +26,13 @@ public record AllayProtoChunk(UnsafeChunk allayChunk) implements ProtoChunk {
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, @NotNull BlockState blockState) {
|
||||
var dimensionInfo = allayChunk.getDimensionInfo();
|
||||
if(x < 0 || x > 15 ||
|
||||
z < 0 || z > 15 ||
|
||||
y < dimensionInfo.minHeight() || y > dimensionInfo.maxHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AllayBlockState allayBlockState = (AllayBlockState) blockState;
|
||||
allayChunk.setBlockState(x, y, z, allayBlockState.allayBlockState());
|
||||
if(allayBlockState.containsWater() || allayChunk.getBlockState(x, y, z).getBlockType().hasBlockTag(BlockTags.WATER)) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.dfsek.terra.allay.delegate;
|
||||
|
||||
import com.dfsek.seismic.type.vector.Vector3;
|
||||
import org.allaymc.api.block.data.BlockTags;
|
||||
import org.allaymc.api.block.property.type.BlockPropertyTypes;
|
||||
import org.allaymc.api.block.tag.BlockTags;
|
||||
import org.allaymc.api.block.type.BlockTypes;
|
||||
import org.allaymc.api.world.generator.context.OtherChunkAccessibleContext;
|
||||
|
||||
@@ -26,6 +26,23 @@ public record AllayProtoWorld(AllayServerWorld allayServerWorld, OtherChunkAcces
|
||||
private static final org.allaymc.api.block.type.BlockState WATER = BlockTypes.WATER.ofState(
|
||||
BlockPropertyTypes.LIQUID_DEPTH.createValue(0));
|
||||
|
||||
// TODO: use method in OtherChunkAccessibleContext directly after bumped allay-api version to 0.14.0
|
||||
private static org.allaymc.api.blockentity.BlockEntity getBlockEntity(OtherChunkAccessibleContext context, int x, int y, int z) {
|
||||
var currentChunk = context.getCurrentChunk();
|
||||
var currentChunkX = currentChunk.getX();
|
||||
var currentChunkZ = currentChunk.getZ();
|
||||
var dimInfo = currentChunk.getDimensionInfo();
|
||||
|
||||
if(x >= currentChunkX * 16 && x < currentChunkX * 16 + 16 &&
|
||||
z >= currentChunkZ * 16 && z < currentChunkZ * 16 + 16 &&
|
||||
y >= dimInfo.minHeight() && y <= dimInfo.maxHeight()) {
|
||||
return currentChunk.getBlockEntity(x & 15, y, z & 15);
|
||||
} else {
|
||||
var chunk = context.getChunkSource().getChunk(x >> 4, z >> 4);
|
||||
return chunk == null ? null : chunk.getBlockEntity(x & 15, y, z & 15);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int centerChunkX() {
|
||||
return context.getCurrentChunk().getX();
|
||||
@@ -43,6 +60,11 @@ public record AllayProtoWorld(AllayServerWorld allayServerWorld, OtherChunkAcces
|
||||
|
||||
@Override
|
||||
public void setBlockState(int x, int y, int z, BlockState data, boolean physics) {
|
||||
var dimensionInfo = allayServerWorld.allayDimension().getDimensionInfo();
|
||||
if(y < dimensionInfo.minHeight() || y > dimensionInfo.maxHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AllayBlockState allayBlockState = (AllayBlockState) data;
|
||||
context.setBlockState(x, y, z, allayBlockState.allayBlockState());
|
||||
if(allayBlockState.containsWater() || context.getBlockState(x, y, z).getBlockType().hasBlockTag(BlockTags.WATER)) {
|
||||
@@ -63,7 +85,7 @@ public record AllayProtoWorld(AllayServerWorld allayServerWorld, OtherChunkAcces
|
||||
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(int x, int y, int z) {
|
||||
return null;
|
||||
return new AllayBlockEntity(getBlockEntity(context, x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,11 +22,16 @@ import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
public record AllayServerWorld(AllayGeneratorWrapper allayGeneratorWrapper, Dimension allayDimension) implements ServerWorld {
|
||||
@Override
|
||||
public Chunk getChunkAt(int x, int z) {
|
||||
return new AllayChunk(this, allayDimension.getChunkService().getChunk(x, z));
|
||||
return new AllayChunk(this, allayDimension.getChunkManager().getChunk(x, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockState(int x, int y, int z, BlockState data, boolean physics) {
|
||||
var dimensionInfo = allayDimension.getDimensionInfo();
|
||||
if(y < dimensionInfo.minHeight() || y > dimensionInfo.maxHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In dimension#setBlockState() method, Water will be moved to layer 1 if it is placed at layer 0
|
||||
allayDimension.setBlockState(x, y, z, ((AllayBlockState) data).allayBlockState());
|
||||
}
|
||||
@@ -44,7 +49,7 @@ public record AllayServerWorld(AllayGeneratorWrapper allayGeneratorWrapper, Dime
|
||||
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(int x, int y, int z) {
|
||||
return null;
|
||||
return new AllayBlockEntity(allayDimension.getBlockEntity(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.dfsek.terra.allay.delegate;
|
||||
|
||||
import org.allaymc.api.world.data.DimensionInfo;
|
||||
|
||||
import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
|
||||
|
||||
/**
|
||||
* @author daoge_cmd
|
||||
*/
|
||||
public class AllayWorldProperties implements WorldProperties {
|
||||
|
||||
private final Object fakeHandle;
|
||||
private final long seed;
|
||||
private final DimensionInfo dimensionInfo;
|
||||
|
||||
public AllayWorldProperties(long seed, DimensionInfo dimensionInfo) {
|
||||
this.fakeHandle = new Object();
|
||||
this.seed = seed;
|
||||
this.dimensionInfo = dimensionInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSeed() {
|
||||
return this.seed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHeight() {
|
||||
return dimensionInfo.maxHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight() {
|
||||
return dimensionInfo.minHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return fakeHandle;
|
||||
}
|
||||
}
|
||||
+54
-54
@@ -1,22 +1,22 @@
|
||||
package com.dfsek.terra.allay.generator;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.allaymc.api.utils.AllayStringUtils;
|
||||
import org.allaymc.api.world.biome.BiomeType;
|
||||
import org.allaymc.api.world.chunk.UnsafeChunk;
|
||||
import org.allaymc.api.world.data.DimensionInfo;
|
||||
import org.allaymc.api.world.generator.WorldGenerator;
|
||||
import org.allaymc.api.world.generator.context.NoiseContext;
|
||||
import org.allaymc.api.world.generator.context.PopulateContext;
|
||||
import org.allaymc.api.world.generator.function.Noiser;
|
||||
import org.allaymc.api.world.generator.function.Populator;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.dfsek.terra.allay.Mapping;
|
||||
import com.dfsek.terra.allay.TerraAllayPlugin;
|
||||
import com.dfsek.terra.allay.delegate.AllayProtoChunk;
|
||||
import com.dfsek.terra.allay.delegate.AllayProtoWorld;
|
||||
import com.dfsek.terra.allay.delegate.AllayServerWorld;
|
||||
import com.dfsek.terra.allay.delegate.AllayWorldProperties;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
@@ -30,27 +30,23 @@ import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
*/
|
||||
public class AllayGeneratorWrapper implements GeneratorWrapper {
|
||||
|
||||
protected static final String OPTION_META_PACK_NAME = "meta-pack";
|
||||
protected static final String OPTION_PACK_NAME = "pack";
|
||||
protected static final String OPTION_SEED = "seed";
|
||||
|
||||
protected final BiomeProvider biomeProvider;
|
||||
protected final long seed;
|
||||
protected final WorldGenerator allayWorldGenerator;
|
||||
protected ChunkGenerator chunkGenerator;
|
||||
|
||||
protected ConfigPack configPack;
|
||||
protected ChunkGenerator chunkGenerator;
|
||||
protected BiomeProvider biomeProvider;
|
||||
|
||||
protected WorldProperties worldProperties;
|
||||
protected AllayServerWorld allayServerWorld;
|
||||
|
||||
public AllayGeneratorWrapper(String preset) {
|
||||
Map<String, String> options = AllayStringUtils.parseOptions(preset);
|
||||
String packName = options.get(OPTION_PACK_NAME);
|
||||
if(packName == null) {
|
||||
throw new IllegalArgumentException("Missing config pack name");
|
||||
}
|
||||
this.seed = Long.parseLong(options.getOrDefault(OPTION_SEED, "0"));
|
||||
this.configPack = getConfigPack(packName);
|
||||
this.chunkGenerator = createGenerator(this.configPack);
|
||||
this.biomeProvider = this.configPack.getBiomeProvider();
|
||||
var options = AllayStringUtils.parseOptions(preset);
|
||||
this.seed = parseSeed(options.get(OPTION_SEED));
|
||||
this.allayWorldGenerator = WorldGenerator
|
||||
.builder()
|
||||
.name("TERRA")
|
||||
@@ -59,40 +55,52 @@ public class AllayGeneratorWrapper implements GeneratorWrapper {
|
||||
.populators(new AllayPopulator())
|
||||
.onDimensionSet(dimension -> {
|
||||
this.allayServerWorld = new AllayServerWorld(this, dimension);
|
||||
this.worldProperties = new WorldProperties() {
|
||||
this.worldProperties = new AllayWorldProperties(this.seed, dimension.getDimensionInfo());
|
||||
|
||||
private final Object fakeHandle = new Object();
|
||||
var metaPackName = options.get(OPTION_META_PACK_NAME);
|
||||
if(metaPackName != null) {
|
||||
setConfigPack(getConfigPackByMeta(metaPackName, dimension.getDimensionInfo()));
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSeed() {
|
||||
return seed;
|
||||
}
|
||||
var packName = options.get(OPTION_PACK_NAME);
|
||||
if(packName != null) {
|
||||
setConfigPack(getConfigPackById(packName));
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHeight() {
|
||||
return dimension.getDimensionInfo().maxHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight() {
|
||||
return dimension.getDimensionInfo().minHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return fakeHandle;
|
||||
}
|
||||
};
|
||||
throw new IllegalArgumentException("Either 'pack' or 'meta-pack' option should be specified in the generator preset!");
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
protected static ConfigPack getConfigPack(String packName) {
|
||||
Optional<ConfigPack> byId = TerraAllayPlugin.PLATFORM.getConfigRegistry().getByID(packName);
|
||||
return byId.orElseGet(
|
||||
() -> TerraAllayPlugin.PLATFORM.getConfigRegistry().getByID(packName.toUpperCase(Locale.ENGLISH))
|
||||
.orElseThrow(() -> new IllegalArgumentException("Cant find terra config pack named " + packName))
|
||||
);
|
||||
protected static long parseSeed(String str) {
|
||||
if(str == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return Long.parseLong(str);
|
||||
} catch(NumberFormatException e) {
|
||||
// Return the hashcode of the string if it cannot be parsed to a long value directly
|
||||
return str.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
protected static ConfigPack getConfigPackById(String packId) {
|
||||
return TerraAllayPlugin.platform
|
||||
.getConfigRegistry()
|
||||
.getByID(packId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Cant find terra config pack named " + packId));
|
||||
}
|
||||
|
||||
protected static ConfigPack getConfigPackByMeta(String metaPackId, DimensionInfo dimensionInfo) {
|
||||
return TerraAllayPlugin.platform
|
||||
.getMetaConfigRegistry()
|
||||
.getByID(metaPackId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Cant find terra meta pack named " + metaPackId))
|
||||
.packs()
|
||||
.get(Mapping.dimensionIdBeToJe(dimensionInfo.toString()));
|
||||
}
|
||||
|
||||
protected static ChunkGenerator createGenerator(ConfigPack configPack) {
|
||||
@@ -101,7 +109,7 @@ public class AllayGeneratorWrapper implements GeneratorWrapper {
|
||||
|
||||
@Override
|
||||
public ChunkGenerator getHandle() {
|
||||
return chunkGenerator;
|
||||
return this.chunkGenerator;
|
||||
}
|
||||
|
||||
public BiomeProvider getBiomeProvider() {
|
||||
@@ -113,8 +121,10 @@ public class AllayGeneratorWrapper implements GeneratorWrapper {
|
||||
}
|
||||
|
||||
public void setConfigPack(ConfigPack configPack) {
|
||||
Preconditions.checkNotNull(configPack, "Config pack cannot be null!");
|
||||
this.configPack = configPack;
|
||||
this.chunkGenerator = createGenerator(this.configPack);
|
||||
this.biomeProvider = this.configPack.getBiomeProvider();
|
||||
}
|
||||
|
||||
public long getSeed() {
|
||||
@@ -152,11 +162,6 @@ public class AllayGeneratorWrapper implements GeneratorWrapper {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "TERRA_NOISER";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,14 +175,9 @@ public class AllayGeneratorWrapper implements GeneratorWrapper {
|
||||
generationStage.populate(tmp);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Error while populating chunk", e);
|
||||
TerraAllayPlugin.instance.getPluginLogger().error("Error while populating chunk", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "TERRA_POPULATOR";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.dfsek.terra.allay.handle;
|
||||
|
||||
import org.allaymc.api.registry.Registries;
|
||||
import org.allaymc.api.utils.Identifier;
|
||||
import org.allaymc.api.utils.identifier.Identifier;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ dependencies {
|
||||
paperweight.paperDevBundle(Versions.Bukkit.paperDevBundle)
|
||||
|
||||
shaded(project(":platforms:bukkit:common"))
|
||||
shaded(project(":platforms:bukkit:nms:v1_21_9"))
|
||||
shaded(project(":platforms:bukkit:nms"))
|
||||
shaded("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ tasks {
|
||||
}
|
||||
|
||||
runServer {
|
||||
minecraftVersion(Versions.Bukkit.runPaperMinecraft)
|
||||
minecraftVersion(Versions.Bukkit.minecraft)
|
||||
dependsOn(shadowJar)
|
||||
pluginJars(shadowJar.get().archiveFile)
|
||||
|
||||
downloadPlugins {
|
||||
modrinth("viaversion", "5.3.2")
|
||||
modrinth("viabackwards", "5.3.2")
|
||||
modrinth("viaversion", "5.5.0")
|
||||
modrinth("viabackwards", "5.5.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.dfsek.terra.bukkit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.bukkit.util.VersionUtil;
|
||||
|
||||
|
||||
public interface NMSInitializer {
|
||||
List<String> SUPPORTED_VERSIONS = List.of("v1.21.9", "v1.21.10");
|
||||
String MINECRAFT_VERSION = VersionUtil.getMinecraftVersionInfo().toString();
|
||||
String TERRA_PACKAGE = NMSInitializer.class.getPackageName();
|
||||
|
||||
static PlatformImpl init(TerraBukkitPlugin plugin) {
|
||||
Logger logger = LoggerFactory.getLogger(NMSInitializer.class);
|
||||
|
||||
if(!SUPPORTED_VERSIONS.contains(MINECRAFT_VERSION)) {
|
||||
logger.error("You are running your server on Minecraft version {} which is not supported by this version of Terra.",
|
||||
MINECRAFT_VERSION);
|
||||
|
||||
String bypassKey = "IKnowThereAreNoNMSBindingsFor" + MINECRAFT_VERSION.replace(".", "_") + "ButIWillProceedAnyway";
|
||||
if(System.getProperty(bypassKey) == null) {
|
||||
logger.error("Because of this **TERRA HAS BEEN DISABLED**.");
|
||||
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 null;
|
||||
} 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("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);
|
||||
}
|
||||
}
|
||||
|
||||
return constructPlatform(plugin);
|
||||
}
|
||||
|
||||
private static PlatformImpl constructPlatform(TerraBukkitPlugin plugin) {
|
||||
try {
|
||||
Class<?> platformClass = Class.forName(TERRA_PACKAGE + ".nms.NMSPlatform");
|
||||
return (PlatformImpl) platformClass
|
||||
.getConstructor(TerraBukkitPlugin.class)
|
||||
.newInstance(plugin);
|
||||
} catch(ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Error initializing NMS bindings. Report this to Terra.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,6 @@ import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent;
|
||||
import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent;
|
||||
import com.dfsek.terra.bukkit.generator.BukkitChunkGeneratorWrapper;
|
||||
import com.dfsek.terra.bukkit.listeners.CommonListener;
|
||||
import com.dfsek.terra.bukkit.nms.Initializer;
|
||||
import com.dfsek.terra.bukkit.util.PaperUtil;
|
||||
import com.dfsek.terra.bukkit.util.VersionUtil;
|
||||
import com.dfsek.terra.bukkit.world.BukkitAdapter;
|
||||
@@ -60,7 +59,7 @@ public class TerraBukkitPlugin extends JavaPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
platform = Initializer.init(this);
|
||||
platform = NMSInitializer.init(this);
|
||||
if(platform == null) {
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
@@ -94,7 +93,7 @@ public class TerraBukkitPlugin extends JavaPlugin {
|
||||
BukkitAdapter::adapt,
|
||||
BukkitAdapter::adapt
|
||||
))
|
||||
.executionCoordinator(ExecutionCoordinator.simpleCoordinator())
|
||||
.executionCoordinator(ExecutionCoordinator.asyncCoordinator())
|
||||
.buildOnEnable(this);
|
||||
|
||||
commandManager.brigadierManager().setNativeNumberSuggestions(false);
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.dfsek.terra.bukkit.PlatformImpl;
|
||||
import com.dfsek.terra.bukkit.TerraBukkitPlugin;
|
||||
import com.dfsek.terra.bukkit.util.VersionUtil;
|
||||
|
||||
|
||||
public interface Initializer {
|
||||
String NMS = VersionUtil.getMinecraftVersionInfo().toString().replace(".", "_");
|
||||
String TERRA_PACKAGE = Initializer.class.getPackageName();
|
||||
|
||||
static PlatformImpl init(TerraBukkitPlugin plugin) {
|
||||
Logger logger = LoggerFactory.getLogger(Initializer.class);
|
||||
|
||||
PlatformImpl platform = constructPlatform(plugin);
|
||||
if(platform == null) {
|
||||
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.");
|
||||
String bypassKey = "IKnowThereAreNoNMSBindingsFor" + NMS + "ButIWillProceedAnyway";
|
||||
if(System.getProperty(bypassKey) == null) {
|
||||
logger.error("Because of this **TERRA HAS BEEN DISABLED**.");
|
||||
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 null;
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
return platform;
|
||||
}
|
||||
|
||||
private static PlatformImpl constructPlatform(TerraBukkitPlugin plugin) {
|
||||
try {
|
||||
Class<?> platformClass = Class.forName(TERRA_PACKAGE + "." + NMS + ".NMSPlatform");
|
||||
try {
|
||||
return (PlatformImpl) platformClass
|
||||
.getConstructor(TerraBukkitPlugin.class)
|
||||
.newInstance(plugin);
|
||||
} catch(ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Error initializing NMS bindings. Report this to Terra.", e);
|
||||
}
|
||||
} catch(ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Holder.Reference;
|
||||
@@ -25,7 +25,7 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.VanillaBiomeProperties;
|
||||
import com.dfsek.terra.bukkit.nms.config.VanillaBiomeProperties;
|
||||
import com.dfsek.terra.bukkit.world.BukkitBiomeInfo;
|
||||
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
|
||||
import com.dfsek.terra.registry.master.ConfigRegistry;
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
|
||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.bukkit.BukkitAddon;
|
||||
import com.dfsek.terra.bukkit.PlatformImpl;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.VanillaBiomeProperties;
|
||||
import com.dfsek.terra.bukkit.nms.config.VanillaBiomeProperties;
|
||||
|
||||
|
||||
public class NMSAddon extends BukkitAddon {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
@@ -12,7 +12,7 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.VanillaBiomeProperties;
|
||||
import com.dfsek.terra.bukkit.nms.config.VanillaBiomeProperties;
|
||||
|
||||
|
||||
public class NMSBiomeInjector {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import net.minecraft.core.Holder;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
+12
-12
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import com.dfsek.tectonic.api.TypeRegistry;
|
||||
import com.dfsek.tectonic.api.exception.LoadException;
|
||||
@@ -27,17 +27,17 @@ import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.world.biome.PlatformBiome;
|
||||
import com.dfsek.terra.bukkit.PlatformImpl;
|
||||
import com.dfsek.terra.bukkit.TerraBukkitPlugin;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.BiomeAdditionsSoundTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.BiomeMoodSoundTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.BiomeParticleConfigTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.EntityTypeTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.MusicSoundTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.SoundEventTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.SpawnCostConfig;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.SpawnEntryConfig;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.SpawnSettingsTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.SpawnTypeConfig;
|
||||
import com.dfsek.terra.bukkit.nms.v1_21_9.config.VillagerTypeTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.config.BiomeAdditionsSoundTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.config.BiomeMoodSoundTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.config.BiomeParticleConfigTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.config.EntityTypeTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.config.MusicSoundTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.config.SoundEventTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.config.SpawnCostConfig;
|
||||
import com.dfsek.terra.bukkit.nms.config.SpawnEntryConfig;
|
||||
import com.dfsek.terra.bukkit.nms.config.SpawnSettingsTemplate;
|
||||
import com.dfsek.terra.bukkit.nms.config.SpawnTypeConfig;
|
||||
import com.dfsek.terra.bukkit.nms.config.VillagerTypeTemplate;
|
||||
|
||||
|
||||
public class NMSPlatform extends PlatformImpl {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Holder.Reference;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9;
|
||||
package com.dfsek.terra.bukkit.nms;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
+6
-8
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
@@ -6,6 +6,8 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData;
|
||||
|
||||
import com.dfsek.terra.api.util.range.Range;
|
||||
|
||||
|
||||
public class SpawnEntryConfig implements ObjectTemplate<SpawnEntryConfig> {
|
||||
@Value("type")
|
||||
@@ -16,20 +18,16 @@ public class SpawnEntryConfig implements ObjectTemplate<SpawnEntryConfig> {
|
||||
@Default
|
||||
private Integer weight = null;
|
||||
|
||||
@Value("min-group-size")
|
||||
@Value("group-size")
|
||||
@Default
|
||||
private Integer minGroupSize = null;
|
||||
|
||||
@Value("max-group-size")
|
||||
@Default
|
||||
private Integer maxGroupSize = null;
|
||||
private Range groupSize = null;
|
||||
|
||||
public Integer getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public SpawnerData getSpawnEntry() {
|
||||
return new SpawnerData(type, minGroupSize, maxGroupSize);
|
||||
return new SpawnerData(type, groupSize.getMin(), groupSize.getMax());
|
||||
}
|
||||
|
||||
@Override
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.ConfigTemplate;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.bukkit.nms.v1_21_9.config;
|
||||
package com.dfsek.terra.bukkit.nms.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
@@ -35,7 +35,7 @@
|
||||
"depends": {
|
||||
"fabricloader": ">=0.16.10",
|
||||
"java": ">=21",
|
||||
"minecraft": "1.21.9",
|
||||
"minecraft": "1.21.10",
|
||||
"fabric": "*"
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ dependencies {
|
||||
shadedApi("com.github.ben-manes.caffeine", "caffeine", Versions.Libraries.caffeine)
|
||||
shadedImplementation("com.google.guava", "guava", Versions.Libraries.Internal.guava)
|
||||
|
||||
compileOnly("net.minestom", "minestom-snapshots", Versions.Minestom.minestom)
|
||||
compileOnly("net.minestom", "minestom", Versions.Minestom.minestom)
|
||||
}
|
||||
|
||||
tasks.named("jar") {
|
||||
|
||||
@@ -7,7 +7,7 @@ val javaMainClass = "com.dfsek.terra.minestom.TerraMinestomExample"
|
||||
dependencies {
|
||||
shadedApi(project(":platforms:minestom"))
|
||||
|
||||
implementation("net.minestom", "minestom-snapshots", Versions.Minestom.minestom)
|
||||
implementation("net.minestom", "minestom", Versions.Minestom.minestom)
|
||||
implementation("org.slf4j", "slf4j-simple", Versions.Libraries.slf4j)
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -9,6 +9,7 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
|
||||
import net.minestom.server.event.player.PlayerSpawnEvent;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.LightingChunk;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -26,6 +27,8 @@ public class TerraMinestomExample {
|
||||
private TerraMinestomWorld world;
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("minestom.registry.unsafe-ops", "true");
|
||||
|
||||
TerraMinestomExample example = new TerraMinestomExample();
|
||||
example.createNewInstance();
|
||||
example.attachTerra();
|
||||
@@ -43,7 +46,7 @@ public class TerraMinestomExample {
|
||||
|
||||
public void attachTerra() {
|
||||
world = platform.worldBuilder(instance)
|
||||
.defaultPack()
|
||||
.packByDefaultMeta(DimensionType.OVERWORLD)
|
||||
.attach();
|
||||
}
|
||||
|
||||
|
||||
+68
-4
@@ -9,6 +9,7 @@ import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.sound.SoundEvent;
|
||||
import net.minestom.server.world.biome.BiomeEffects;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -25,8 +26,11 @@ import com.dfsek.terra.api.handle.ItemHandle;
|
||||
import com.dfsek.terra.api.handle.WorldHandle;
|
||||
import com.dfsek.terra.api.world.biome.PlatformBiome;
|
||||
import com.dfsek.terra.minestom.addon.MinestomAddon;
|
||||
import com.dfsek.terra.minestom.api.BiomeFactory;
|
||||
import com.dfsek.terra.minestom.api.TerraMinestomWorldBuilder;
|
||||
import com.dfsek.terra.minestom.biome.MinestomBiomeLoader;
|
||||
import com.dfsek.terra.minestom.biome.MinestomUserDefinedBiomeFactory;
|
||||
import com.dfsek.terra.minestom.biome.MinestomUserDefinedBiomePool;
|
||||
import com.dfsek.terra.minestom.config.BiomeAdditionsSoundTemplate;
|
||||
import com.dfsek.terra.minestom.config.BiomeMoodSoundTemplate;
|
||||
import com.dfsek.terra.minestom.config.BiomeParticleConfigTemplate;
|
||||
@@ -45,19 +49,26 @@ public final class TerraMinestomPlatform extends AbstractPlatform {
|
||||
private final ItemHandle itemHandle;
|
||||
private final TypeLoader<PlatformBiome> biomeTypeLoader;
|
||||
private final ArrayList<BaseAddon> platformAddons = new ArrayList<>(List.of(new MinestomAddon(this)));
|
||||
private final MinestomUserDefinedBiomePool biomePool;
|
||||
|
||||
public TerraMinestomPlatform(WorldHandle worldHandle, ItemHandle itemHandle, TypeLoader<PlatformBiome> biomeTypeLoader,
|
||||
BaseAddon... extraAddons) {
|
||||
BiomeFactory biomeFactory, BaseAddon... extraAddons) {
|
||||
this.worldHandle = worldHandle;
|
||||
this.itemHandle = itemHandle;
|
||||
this.biomeTypeLoader = biomeTypeLoader;
|
||||
this.biomePool = new MinestomUserDefinedBiomePool(biomeFactory);
|
||||
this.platformAddons.addAll(List.of(extraAddons));
|
||||
load();
|
||||
getEventManager().callEvent(new PlatformInitializationEvent());
|
||||
initializeRegistry(); // Needs to be called before minecraft server bind
|
||||
}
|
||||
|
||||
public TerraMinestomPlatform() {
|
||||
this(new MinestomWorldHandle(), new MinestomItemHandle(), new MinestomBiomeLoader());
|
||||
this(new MinestomWorldHandle(), new MinestomItemHandle(), new MinestomBiomeLoader(), new MinestomUserDefinedBiomeFactory());
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,6 +105,10 @@ public final class TerraMinestomPlatform extends AbstractPlatform {
|
||||
return succeed;
|
||||
}
|
||||
|
||||
public void initializeRegistry() {
|
||||
getRawConfigRegistry()
|
||||
.forEach(pack -> biomePool.preloadBiomes(pack, pack.getBiomeProvider().getBiomes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull WorldHandle getWorldHandle() {
|
||||
@@ -125,10 +140,59 @@ public final class TerraMinestomPlatform extends AbstractPlatform {
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder worldBuilder(Instance instance) {
|
||||
return new TerraMinestomWorldBuilder(this, instance);
|
||||
return new TerraMinestomWorldBuilder(this, instance, biomePool);
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder worldBuilder() {
|
||||
return new TerraMinestomWorldBuilder(this, MinecraftServer.getInstanceManager().createInstanceContainer());
|
||||
return worldBuilder(MinecraftServer.getInstanceManager().createInstanceContainer());
|
||||
}
|
||||
|
||||
|
||||
public static class Builder {
|
||||
private final List<BaseAddon> platformAddons = new ArrayList<>();
|
||||
private @Nullable WorldHandle worldHandle;
|
||||
private @Nullable ItemHandle itemHandle;
|
||||
private @Nullable TypeLoader<PlatformBiome> biomeTypeLoader;
|
||||
private @Nullable BiomeFactory biomeFactory;
|
||||
|
||||
public Builder worldHandle(@Nullable WorldHandle worldHandle) {
|
||||
this.worldHandle = worldHandle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder itemHandle(@Nullable ItemHandle itemHandle) {
|
||||
this.itemHandle = itemHandle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder biomeTypeLoader(@Nullable TypeLoader<PlatformBiome> biomeTypeLoader) {
|
||||
this.biomeTypeLoader = biomeTypeLoader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addPlatformAddon(BaseAddon addon) {
|
||||
this.platformAddons.add(addon);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder biomeFactory(BiomeFactory biomeFactory) {
|
||||
this.biomeFactory = biomeFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomPlatform build() {
|
||||
if(worldHandle == null) worldHandle = new MinestomWorldHandle();
|
||||
if(itemHandle == null) itemHandle = new MinestomItemHandle();
|
||||
if(biomeTypeLoader == null) biomeTypeLoader = new MinestomBiomeLoader();
|
||||
if(biomeFactory == null) biomeFactory = new MinestomUserDefinedBiomeFactory();
|
||||
|
||||
return new TerraMinestomPlatform(
|
||||
worldHandle,
|
||||
itemHandle,
|
||||
biomeTypeLoader,
|
||||
biomeFactory,
|
||||
platformAddons.toArray(new BaseAddon[0])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package com.dfsek.terra.minestom.addon;
|
||||
|
||||
import ca.solostudios.strata.Versions;
|
||||
import ca.solostudios.strata.version.Version;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
|
||||
@@ -10,9 +12,6 @@ import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.minestom.TerraMinestomPlatform;
|
||||
import com.dfsek.terra.minestom.config.VanillaBiomeProperties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class MinestomAddon implements BaseAddon {
|
||||
private static final Version VERSION = Versions.getVersion(1, 0, 0);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.dfsek.terra.minestom.api;
|
||||
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
|
||||
@@ -9,5 +10,22 @@ import net.minestom.server.entity.EntityType;
|
||||
* Allows adding AI to generated entities using custom entity types
|
||||
*/
|
||||
public interface EntityFactory {
|
||||
/**
|
||||
* Creates a new entity of the specified type.
|
||||
*
|
||||
* @param type the type of the entity to be created
|
||||
* @return the created entity instance
|
||||
*/
|
||||
Entity createEntity(EntityType type);
|
||||
|
||||
/**
|
||||
* Creates a new entity of the specified type with additional data.
|
||||
*
|
||||
* @param type the type of the entity to be created
|
||||
* @param data the additional data for the entity, represented as a CompoundBinaryTag
|
||||
* @return the created entity instance
|
||||
*/
|
||||
default Entity createEntity(EntityType type, CompoundBinaryTag data) {
|
||||
return createEntity(type);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-10
@@ -1,6 +1,9 @@
|
||||
package com.dfsek.terra.minestom.api;
|
||||
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.registry.RegistryKey;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.function.Function;
|
||||
@@ -8,7 +11,7 @@ import java.util.function.Function;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.registry.CheckedRegistry;
|
||||
import com.dfsek.terra.minestom.TerraMinestomPlatform;
|
||||
import com.dfsek.terra.minestom.biome.MinestomUserDefinedBiomeFactory;
|
||||
import com.dfsek.terra.minestom.biome.MinestomUserDefinedBiomePool;
|
||||
import com.dfsek.terra.minestom.block.DefaultBlockEntityFactory;
|
||||
import com.dfsek.terra.minestom.entity.DefaultEntityFactory;
|
||||
import com.dfsek.terra.minestom.world.TerraMinestomWorld;
|
||||
@@ -17,16 +20,17 @@ import com.dfsek.terra.minestom.world.TerraMinestomWorld;
|
||||
public class TerraMinestomWorldBuilder {
|
||||
private final TerraMinestomPlatform platform;
|
||||
private final Instance instance;
|
||||
private final MinestomUserDefinedBiomePool biomePool;
|
||||
private ConfigPack pack;
|
||||
private long seed = new Random().nextLong();
|
||||
private EntityFactory entityFactory = new DefaultEntityFactory();
|
||||
private BlockEntityFactory blockEntityFactory;
|
||||
private BiomeFactory biomeFactory = new MinestomUserDefinedBiomeFactory();
|
||||
|
||||
public TerraMinestomWorldBuilder(TerraMinestomPlatform platform, Instance instance) {
|
||||
public TerraMinestomWorldBuilder(TerraMinestomPlatform platform, Instance instance, MinestomUserDefinedBiomePool biomePool) {
|
||||
this.platform = platform;
|
||||
this.instance = instance;
|
||||
this.blockEntityFactory = new DefaultBlockEntityFactory(instance);
|
||||
this.biomePool = biomePool;
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder pack(ConfigPack pack) {
|
||||
@@ -36,10 +40,22 @@ public class TerraMinestomWorldBuilder {
|
||||
|
||||
public TerraMinestomWorldBuilder packById(String id) {
|
||||
this.pack = platform.getConfigRegistry().getByID(id).orElseThrow();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder packByMeta(String metaPack, RegistryKey<@NonNull DimensionType> dimensionType) {
|
||||
this.pack = platform.getMetaConfigRegistry()
|
||||
.getByID(metaPack)
|
||||
.orElseThrow(() -> new RuntimeException("MetaPack " + metaPack + " could not be found"))
|
||||
.packs()
|
||||
.get(dimensionType.key().asString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder packByDefaultMeta(RegistryKey<@NonNull DimensionType> dimensionType) {
|
||||
return packByMeta("DEFAULT", dimensionType);
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder findPack(Function<CheckedRegistry<ConfigPack>, ConfigPack> fn) {
|
||||
this.pack = fn.apply(platform.getConfigRegistry());
|
||||
return this;
|
||||
@@ -64,12 +80,7 @@ public class TerraMinestomWorldBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder biomeFactory(BiomeFactory factory) {
|
||||
this.biomeFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorld attach() {
|
||||
return new TerraMinestomWorld(platform, instance, pack, seed, entityFactory, blockEntityFactory, biomeFactory);
|
||||
return new TerraMinestomWorld(platform, instance, pack, seed, entityFactory, blockEntityFactory, biomePool);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -12,14 +12,12 @@ public class MinestomUserDefinedBiomePool {
|
||||
private final IdentityHashMap<Biome, UserDefinedBiome> biomes = new IdentityHashMap<>();
|
||||
private final HashSet<String> createdBiomes = new HashSet<>();
|
||||
private final BiomeFactory factory;
|
||||
private final ConfigPack configPack;
|
||||
|
||||
public MinestomUserDefinedBiomePool(ConfigPack configPack, BiomeFactory factory) {
|
||||
this.configPack = configPack;
|
||||
public MinestomUserDefinedBiomePool(BiomeFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public UserDefinedBiome getBiome(Biome source) {
|
||||
public UserDefinedBiome getBiome(ConfigPack configPack, Biome source) {
|
||||
UserDefinedBiome userDefinedBiome = biomes.get(source);
|
||||
if(userDefinedBiome != null) return userDefinedBiome;
|
||||
userDefinedBiome = factory.create(configPack, source);
|
||||
@@ -28,7 +26,7 @@ public class MinestomUserDefinedBiomePool {
|
||||
return userDefinedBiome;
|
||||
}
|
||||
|
||||
public void preloadBiomes(Iterable<Biome> biomesToLoad) {
|
||||
public void preloadBiomes(ConfigPack configPack, Iterable<Biome> biomesToLoad) {
|
||||
biomesToLoad
|
||||
.forEach(biome -> {
|
||||
if(!this.createdBiomes.contains(biome.getID())) {
|
||||
|
||||
+72
-22
@@ -1,7 +1,10 @@
|
||||
package com.dfsek.terra.minestom.block;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -10,37 +13,84 @@ import com.dfsek.terra.api.block.BlockType;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.block.state.properties.Property;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class MinestomBlockState implements BlockState {
|
||||
private final Block block;
|
||||
|
||||
public MinestomBlockState(Block block) {
|
||||
if(block == null) {
|
||||
this.block = Block.AIR;
|
||||
} else {
|
||||
this.block = block;
|
||||
}
|
||||
public record MinestomBlockState(Block block) implements BlockState {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MinestomBlockState.class);
|
||||
public static final MinestomBlockState AIR = new MinestomBlockState(Block.AIR);
|
||||
private static final TagStringIO tagStringIO = TagStringIO.tagStringIO();
|
||||
|
||||
public MinestomBlockState {
|
||||
block = Objects.requireNonNullElse(block, Block.AIR);
|
||||
}
|
||||
|
||||
public MinestomBlockState(String data) {
|
||||
if(!data.contains("[")) {
|
||||
block = Block.fromKey(data);
|
||||
return;
|
||||
public static MinestomBlockState fromStateId(String data) {
|
||||
CompoundBinaryTag nbt = CompoundBinaryTag.empty();
|
||||
int splitIndex = data.indexOf('{');
|
||||
if(splitIndex != -1) {
|
||||
String fullId = data;
|
||||
data = data.substring(0, splitIndex);
|
||||
String dataString = fullId.substring(splitIndex);
|
||||
try {
|
||||
nbt = tagStringIO.asCompound(dataString);
|
||||
} catch(IOException exception) {
|
||||
LOGGER.warn("Invalid entity data, will be ignored: {}", dataString);
|
||||
}
|
||||
}
|
||||
|
||||
String[] split = data.split("\\[");
|
||||
String namespaceId = split[0];
|
||||
String properties = split[1].substring(0, split[1].length() - 1);
|
||||
int openBracketIndex = data.indexOf('[');
|
||||
int closeBracketIndex = data.indexOf(']');
|
||||
|
||||
if(openBracketIndex == -1 || closeBracketIndex == -1 || closeBracketIndex < openBracketIndex) {
|
||||
// no or invalid properties
|
||||
Block block = Block.fromKey(data);
|
||||
if(block != null && !nbt.isEmpty()) {
|
||||
block = block.withNbt(nbt);
|
||||
}
|
||||
return new MinestomBlockState(block);
|
||||
}
|
||||
|
||||
String namespaceId = data.substring(0, openBracketIndex);
|
||||
String propertiesContent = data.substring(openBracketIndex + 1, closeBracketIndex);
|
||||
Block block = Block.fromKey(namespaceId);
|
||||
HashMap<String, String> propertiesMap = new HashMap<>();
|
||||
|
||||
for(String property : properties.split(",")) {
|
||||
String[] kv = property.split("=");
|
||||
propertiesMap.put(kv[0].strip(), kv[1].strip());
|
||||
if (block == null) {
|
||||
LOGGER.error("Invalid block ID found during parsing: {}", namespaceId);
|
||||
return new MinestomBlockState(Block.AIR);
|
||||
}
|
||||
|
||||
assert block != null;
|
||||
this.block = block.withProperties(propertiesMap);
|
||||
HashMap<String, String> propertiesMap = new HashMap<>();
|
||||
int current = 0;
|
||||
while (current < propertiesContent.length()) {
|
||||
int nextComma = propertiesContent.indexOf(',', current);
|
||||
String property;
|
||||
|
||||
if (nextComma == -1) {
|
||||
property = propertiesContent.substring(current);
|
||||
current = propertiesContent.length();
|
||||
} else {
|
||||
property = propertiesContent.substring(current, nextComma);
|
||||
current = nextComma + 1;
|
||||
}
|
||||
|
||||
int equalsIndex = property.indexOf('=');
|
||||
|
||||
if (equalsIndex == -1) {
|
||||
LOGGER.warn("Invalid block property syntax (missing '=') in string: {}", property);
|
||||
continue;
|
||||
}
|
||||
|
||||
String key = property.substring(0, equalsIndex).strip();
|
||||
String value = property.substring(equalsIndex + 1).strip();
|
||||
propertiesMap.put(key, value);
|
||||
}
|
||||
|
||||
if(!nbt.isEmpty()) {
|
||||
block = block.withNbt(nbt);
|
||||
}
|
||||
|
||||
return new MinestomBlockState(block.withProperties(propertiesMap));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,24 +15,27 @@ import com.dfsek.terra.minestom.block.MinestomBlockState;
|
||||
public class CachedChunk implements ProtoChunk {
|
||||
private final int minHeight;
|
||||
private final int maxHeight;
|
||||
private final Block[] blocks;
|
||||
private final MinestomBlockState[] blocks;
|
||||
|
||||
public CachedChunk(int minHeight, int maxHeight) {
|
||||
this.minHeight = minHeight;
|
||||
this.maxHeight = maxHeight;
|
||||
this.blocks = new Block[16 * (maxHeight - minHeight + 1) * 16];
|
||||
Arrays.fill(blocks, Block.AIR);
|
||||
this.blocks = new MinestomBlockState[16 * (maxHeight - minHeight + 1) * 16];
|
||||
Arrays.fill(blocks, MinestomBlockState.AIR);
|
||||
}
|
||||
|
||||
public void writeRelative(UnitModifier modifier) {
|
||||
modifier.setAllRelative((x, y, z) -> blocks[getIndex(x, y + minHeight, z)]);
|
||||
modifier.setAllRelative((x, y, z) -> blocks[getIndex(x, y + minHeight, z)].block());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, @NotNull BlockState blockState) {
|
||||
Block block = (Block) blockState.getHandle();
|
||||
MinestomBlockState minestomBlockState = (MinestomBlockState) blockState;
|
||||
Block block = minestomBlockState.block();
|
||||
if(block == null) return;
|
||||
blocks[getIndex(x, y, z)] = block;
|
||||
int index = getIndex(x, y, z);
|
||||
if(index > blocks.length || index < 0) return;
|
||||
blocks[index] = minestomBlockState;
|
||||
}
|
||||
|
||||
private int getIndex(int x, int y, int z) {
|
||||
@@ -42,7 +45,9 @@ public class CachedChunk implements ProtoChunk {
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState getBlock(int x, int y, int z) {
|
||||
return new MinestomBlockState(blocks[getIndex(x, y, z)]);
|
||||
int index = getIndex(x, y, z);
|
||||
if(index > blocks.length || index < 0) return MinestomBlockState.AIR;
|
||||
return blocks[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+16
-3
@@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.github.benmanes.caffeine.cache.stats.CacheStats;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -15,7 +16,7 @@ import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
|
||||
public class GeneratedChunkCache {
|
||||
private static final Logger log = LoggerFactory.getLogger(GeneratedChunkCache.class);
|
||||
private final LoadingCache<Pair<Integer, Integer>, CachedChunk> cache;
|
||||
private final LoadingCache<@NotNull Long, CachedChunk> cache;
|
||||
private final DimensionType dimensionType;
|
||||
private final ChunkGenerator generator;
|
||||
private final ServerWorld world;
|
||||
@@ -29,7 +30,7 @@ public class GeneratedChunkCache {
|
||||
this.cache = Caffeine.newBuilder()
|
||||
.maximumSize(128)
|
||||
.recordStats()
|
||||
.build((Pair<Integer, Integer> key) -> generateChunk(key.getLeft(), key.getRight()));
|
||||
.build((Long key) -> generateChunk(unpackX(key), unpackZ(key)));
|
||||
}
|
||||
|
||||
private CachedChunk generateChunk(int x, int z) {
|
||||
@@ -50,6 +51,18 @@ public class GeneratedChunkCache {
|
||||
}
|
||||
|
||||
public CachedChunk at(int x, int z) {
|
||||
return cache.get(Pair.of(x, z));
|
||||
return cache.get(pack(x, z));
|
||||
}
|
||||
|
||||
private long pack(final int x, final int z) {
|
||||
return ((long) x) << 32 | z & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
private int unpackX(long key) {
|
||||
return (int) (key >>> 32);
|
||||
}
|
||||
|
||||
private int unpackZ(long key) {
|
||||
return (int) key;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -5,6 +5,7 @@ import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.world.biome.BiomeEffects;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class BiomeParticleConfigTemplate implements ObjectTemplate<BiomeEffects.Particle> {
|
||||
@@ -22,9 +23,17 @@ public class BiomeParticleConfigTemplate implements ObjectTemplate<BiomeEffects.
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] parts = particle.split("\\{");
|
||||
Particle parsedParticle = Particle.fromKey(parts[0]);
|
||||
if(parts.length > 1) {
|
||||
LoggerFactory.getLogger(BiomeParticleConfigTemplate.class).warn("Particle {} has additional data, particle will be ignored.",
|
||||
particle);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new BiomeEffects.Particle(
|
||||
probability,
|
||||
Particle.fromKey(particle)
|
||||
parsedParticle
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -22,7 +22,8 @@ public class MinestomEntity implements com.dfsek.terra.api.entity.Entity {
|
||||
|
||||
public static MinestomEntity spawn(double x, double y, double z, EntityType type, TerraMinestomWorld world) {
|
||||
Instance instance = world.getHandle();
|
||||
Entity entity = world.getEntityFactory().createEntity(((MinestomEntityType) type).getHandle());
|
||||
MinestomEntityType entityType = (MinestomEntityType) type;
|
||||
Entity entity = world.getEntityFactory().createEntity(entityType.getHandle(), entityType.getData());
|
||||
entity.setInstance(instance, new Pos(x, y, z));
|
||||
return new MinestomEntity(entity, world);
|
||||
}
|
||||
|
||||
+30
@@ -1,12 +1,38 @@
|
||||
package com.dfsek.terra.minestom.entity;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
public class MinestomEntityType implements com.dfsek.terra.api.entity.EntityType {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MinestomEntityType.class);
|
||||
private static final TagStringIO tagStringIO = TagStringIO.tagStringIO();
|
||||
private final EntityType delegate;
|
||||
private final CompoundBinaryTag data;
|
||||
|
||||
public MinestomEntityType(String id) {
|
||||
int splitIndex = id.indexOf('{');
|
||||
if(splitIndex != -1) {
|
||||
String fullId = id;
|
||||
id = id.substring(0, splitIndex);
|
||||
String dataString = fullId.substring(splitIndex);
|
||||
CompoundBinaryTag data;
|
||||
try {
|
||||
data = tagStringIO.asCompound(dataString);
|
||||
} catch(IOException exception) {
|
||||
LOGGER.warn("Invalid entity data, will be ignored: {}", dataString);
|
||||
data = CompoundBinaryTag.empty();
|
||||
}
|
||||
this.data = data;
|
||||
} else {
|
||||
this.data = CompoundBinaryTag.empty();
|
||||
}
|
||||
|
||||
delegate = EntityType.fromKey(id);
|
||||
}
|
||||
|
||||
@@ -14,4 +40,8 @@ public class MinestomEntityType implements com.dfsek.terra.api.entity.EntityType
|
||||
public EntityType getHandle() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
+1
-6
@@ -40,7 +40,6 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe
|
||||
this.biomePool = biomePool;
|
||||
this.biomeProvider = pack.getBiomeProvider();
|
||||
this.cache = new GeneratedChunkCache(world.getDimensionType(), generator, world, biomeProvider);
|
||||
preloadBiomes();
|
||||
}
|
||||
|
||||
public ChunkGenerator getGenerator() {
|
||||
@@ -73,6 +72,7 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe
|
||||
|
||||
if(relativeX % 4 == 0 && relativeY % 4 == 0 && relativeZ % 4 == 0) {
|
||||
UserDefinedBiome userDefinedBiome = biomePool.getBiome(
|
||||
pack,
|
||||
biomeProvider.getBiome(absoluteX, absoluteY, absoluteZ, world.getSeed())
|
||||
);
|
||||
|
||||
@@ -101,11 +101,6 @@ public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrappe
|
||||
this.pack = pack;
|
||||
this.generator = pack.getGeneratorProvider().newInstance(pack);
|
||||
this.biomePool.invalidate();
|
||||
preloadBiomes();
|
||||
}
|
||||
|
||||
private void preloadBiomes() {
|
||||
this.biomePool.preloadBiomes(world.getBiomeProvider().getBiomes());
|
||||
}
|
||||
|
||||
public void displayStats() {
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ public class MinestomWorldHandle implements WorldHandle {
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState createBlockState(@NotNull String data) {
|
||||
return new MinestomBlockState(data);
|
||||
return MinestomBlockState.fromStateId(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-3
@@ -20,7 +20,6 @@ import com.dfsek.terra.api.world.chunk.Chunk;
|
||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
import com.dfsek.terra.minestom.TerraMinestomPlatform;
|
||||
import com.dfsek.terra.minestom.api.BiomeFactory;
|
||||
import com.dfsek.terra.minestom.api.BlockEntityFactory;
|
||||
import com.dfsek.terra.minestom.api.EntityFactory;
|
||||
import com.dfsek.terra.minestom.biome.MinestomUserDefinedBiomePool;
|
||||
@@ -44,7 +43,7 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties {
|
||||
long seed,
|
||||
EntityFactory entityFactory,
|
||||
BlockEntityFactory blockEntityFactory,
|
||||
BiomeFactory factory
|
||||
MinestomUserDefinedBiomePool biomePool
|
||||
) {
|
||||
this.instance = instance;
|
||||
this.pack = pack;
|
||||
@@ -57,7 +56,7 @@ public final class TerraMinestomWorld implements ServerWorld, WorldProperties {
|
||||
pack.getGeneratorProvider().newInstance(pack),
|
||||
this,
|
||||
pack,
|
||||
new MinestomUserDefinedBiomePool(pack, factory)
|
||||
biomePool
|
||||
);
|
||||
this.entityFactory = entityFactory;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user